| ... | @@ -24,8 +24,11 @@ mtime: u64, | ... | @@ -24,8 +24,11 @@ mtime: u64, |
| 24 | contents: []align(@alignOf(u64)) const u8, | 24 | contents: []align(@alignOf(u64)) const u8, |
| 25 | | 25 | |
| 26 | header: macho.mach_header_64 = undefined, | 26 | header: macho.mach_header_64 = undefined, |
| 27 | in_symtab: []align(1) const macho.nlist_64 = undefined, | 27 | |
| 28 | in_strtab: []const u8 = undefined, | 28 | /// Symtab and strtab might not exist for empty object files so we use an optional |
| | 29 | /// to signal this. |
| | 30 | in_symtab: ?[]align(1) const macho.nlist_64 = null, |
| | 31 | in_strtab: ?[]const u8 = null, |
| 29 | | 32 | |
| 30 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 33 | symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 31 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, | 34 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, |
| ... | @@ -105,7 +108,7 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) | ... | @@ -105,7 +108,7 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) |
| 105 | self.contents.ptr + symtab.symoff, | 108 | self.contents.ptr + symtab.symoff, |
| 106 | )[0..symtab.nsyms]; | 109 | )[0..symtab.nsyms]; |
| 107 | self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize]; | 110 | self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize]; |
| 108 | try self.symtab.appendUnalignedSlice(allocator, self.in_symtab); | 111 | try self.symtab.appendUnalignedSlice(allocator, self.in_symtab.?); |
| 109 | }, | 112 | }, |
| 110 | else => {}, | 113 | else => {}, |
| 111 | } | 114 | } |
| ... | @@ -243,6 +246,50 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) | ... | @@ -243,6 +246,50 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) |
| 243 | | 246 | |
| 244 | log.debug("splitting object({d}, {s}) into atoms: one-shot mode", .{ object_id, self.name }); | 247 | log.debug("splitting object({d}, {s}) into atoms: one-shot mode", .{ object_id, self.name }); |
| 245 | | 248 | |
| | 249 | const in_symtab = self.in_symtab orelse { |
| | 250 | for (self.sections.items) |sect, id| { |
| | 251 | if (sect.isDebug()) continue; |
| | 252 | const match = (try macho_file.getOutputSection(sect)) orelse { |
| | 253 | log.debug(" unhandled section", .{}); |
| | 254 | continue; |
| | 255 | }; |
| | 256 | if (sect.size == 0) continue; |
| | 257 | |
| | 258 | const sect_id = @intCast(u8, id); |
| | 259 | const sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { |
| | 260 | const sym_index = @intCast(u32, self.symtab.items.len); |
| | 261 | try self.symtab.append(gpa, .{ |
| | 262 | .n_strx = 0, |
| | 263 | .n_type = macho.N_SECT, |
| | 264 | .n_sect = match + 1, |
| | 265 | .n_desc = 0, |
| | 266 | .n_value = sect.addr, |
| | 267 | }); |
| | 268 | try self.sections_as_symbols.putNoClobber(gpa, sect_id, sym_index); |
| | 269 | break :blk sym_index; |
| | 270 | }; |
| | 271 | const code: ?[]const u8 = if (!sect.isZerofill()) try self.getSectionContents(sect) else null; |
| | 272 | const relocs = @ptrCast( |
| | 273 | [*]align(1) const macho.relocation_info, |
| | 274 | self.contents.ptr + sect.reloff, |
| | 275 | )[0..sect.nreloc]; |
| | 276 | const atom = try self.createAtomFromSubsection( |
| | 277 | macho_file, |
| | 278 | object_id, |
| | 279 | sym_index, |
| | 280 | sect.size, |
| | 281 | sect.@"align", |
| | 282 | code, |
| | 283 | relocs, |
| | 284 | &.{}, |
| | 285 | match, |
| | 286 | sect, |
| | 287 | ); |
| | 288 | try macho_file.addAtomToSection(atom, match); |
| | 289 | } |
| | 290 | return; |
| | 291 | }; |
| | 292 | |
| 246 | // You would expect that the symbol table is at least pre-sorted based on symbol's type: | 293 | // You would expect that the symbol table is at least pre-sorted based on symbol's type: |
| 247 | // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance, | 294 | // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance, |
| 248 | // the GO compiler does not necessarily respect that therefore we sort immediately by type | 295 | // the GO compiler does not necessarily respect that therefore we sort immediately by type |
| ... | @@ -250,10 +297,10 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) | ... | @@ -250,10 +297,10 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) |
| 250 | const context = Context{ | 297 | const context = Context{ |
| 251 | .object = self, | 298 | .object = self, |
| 252 | }; | 299 | }; |
| 253 | var sorted_all_syms = try std.ArrayList(SymbolAtIndex).initCapacity(gpa, self.in_symtab.len); | 300 | var sorted_all_syms = try std.ArrayList(SymbolAtIndex).initCapacity(gpa, in_symtab.len); |
| 254 | defer sorted_all_syms.deinit(); | 301 | defer sorted_all_syms.deinit(); |
| 255 | | 302 | |
| 256 | for (self.in_symtab) |_, index| { | 303 | for (in_symtab) |_, index| { |
| 257 | sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) }); | 304 | sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) }); |
| 258 | } | 305 | } |
| 259 | | 306 | |
| ... | @@ -282,6 +329,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) | ... | @@ -282,6 +329,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) |
| 282 | const subsections_via_symbols = self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; | 329 | const subsections_via_symbols = self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; |
| 283 | | 330 | |
| 284 | for (self.sections.items) |sect, id| { | 331 | for (self.sections.items) |sect, id| { |
| | 332 | if (sect.isDebug()) continue; |
| | 333 | |
| 285 | const sect_id = @intCast(u8, id); | 334 | const sect_id = @intCast(u8, id); |
| 286 | log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() }); | 335 | log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() }); |
| 287 | | 336 | |
| ... | @@ -530,8 +579,9 @@ fn createAtomFromSubsection( | ... | @@ -530,8 +579,9 @@ fn createAtomFromSubsection( |
| 530 | } | 579 | } |
| 531 | | 580 | |
| 532 | pub fn getSourceSymbol(self: Object, index: u32) ?macho.nlist_64 { | 581 | pub fn getSourceSymbol(self: Object, index: u32) ?macho.nlist_64 { |
| 533 | if (index >= self.in_symtab.len) return null; | 582 | const symtab = self.in_symtab.?; |
| 534 | return self.in_symtab[index]; | 583 | if (index >= symtab.len) return null; |
| | 584 | return symtab[index]; |
| 535 | } | 585 | } |
| 536 | | 586 | |
| 537 | pub fn getSourceSection(self: Object, index: u16) macho.section_64 { | 587 | pub fn getSourceSection(self: Object, index: u16) macho.section_64 { |
| ... | @@ -636,8 +686,9 @@ pub fn getSectionContents(self: Object, sect: macho.section_64) error{Overflow}! | ... | @@ -636,8 +686,9 @@ pub fn getSectionContents(self: Object, sect: macho.section_64) error{Overflow}! |
| 636 | } | 686 | } |
| 637 | | 687 | |
| 638 | pub fn getString(self: Object, off: u32) []const u8 { | 688 | pub fn getString(self: Object, off: u32) []const u8 { |
| 639 | assert(off < self.in_strtab.len); | 689 | const strtab = self.in_strtab.?; |
| 640 | return mem.sliceTo(@ptrCast([*:0]const u8, self.in_strtab.ptr + off), 0); | 690 | assert(off < strtab.len); |
| | 691 | return mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + off), 0); |
| 641 | } | 692 | } |
| 642 | | 693 | |
| 643 | pub fn getAtomForSymbol(self: Object, sym_index: u32) ?*Atom { | 694 | pub fn getAtomForSymbol(self: Object, sym_index: u32) ?*Atom { |