authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-24 10:34:59+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-29 11:39:34+02:00
log04e93dd26572e8d1d69c0f714a6eb06b9435f771
treece2729d357027bbec58ae8fd01b3264f18e850db
parent837114f019a5ba2695165030790fb162ca199151

macho: use TableSection for GOT entries in zld driver


6 files changed, 153 insertions(+), 183 deletions(-)

src/link/MachO.zig+30-18
...@@ -3222,18 +3222,24 @@ fn writeLinkeditSegmentData(self: *MachO) !void {...@@ -3222,18 +3222,24 @@ fn writeLinkeditSegmentData(self: *MachO) !void {
3222 seg.vmsize = mem.alignForward(u64, seg.filesize, page_size);3222 seg.vmsize = mem.alignForward(u64, seg.filesize, page_size);
3223}3223}
32243224
3225fn collectRebaseDataFromTableSection(self: *MachO, sect_id: u8, rebase: *Rebase, table: anytype) !void {3225pub fn collectRebaseDataFromTableSection(
3226 const header = self.sections.items(.header)[sect_id];3226 gpa: Allocator,
3227 const segment_index = self.sections.items(.segment_index)[sect_id];3227 ctx: anytype,
3228 const segment = self.segments.items[segment_index];3228 sect_id: u8,
3229 rebase: *Rebase,
3230 table: anytype,
3231) !void {
3232 const header = ctx.sections.items(.header)[sect_id];
3233 const segment_index = ctx.sections.items(.segment_index)[sect_id];
3234 const segment = ctx.segments.items[segment_index];
3229 const base_offset = header.addr - segment.vmaddr;3235 const base_offset = header.addr - segment.vmaddr;
3230 const is_got = if (self.got_section_index) |index| index == sect_id else false;3236 const is_got = if (ctx.got_section_index) |index| index == sect_id else false;
32313237
3232 try rebase.entries.ensureUnusedCapacity(self.base.allocator, table.entries.items.len);3238 try rebase.entries.ensureUnusedCapacity(gpa, table.entries.items.len);
32333239
3234 for (table.entries.items, 0..) |entry, i| {3240 for (table.entries.items, 0..) |entry, i| {
3235 if (!table.lookup.contains(entry)) continue;3241 if (!table.lookup.contains(entry)) continue;
3236 const sym = self.getSymbol(entry);3242 const sym = ctx.getSymbol(entry);
3237 if (is_got and sym.undf()) continue;3243 if (is_got and sym.undf()) continue;
3238 const offset = i * @sizeOf(u64);3244 const offset = i * @sizeOf(u64);
3239 log.debug(" | rebase at {x}", .{base_offset + offset});3245 log.debug(" | rebase at {x}", .{base_offset + offset});
...@@ -3271,28 +3277,34 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {...@@ -3271,28 +3277,34 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {
3271 }3277 }
3272 }3278 }
32733279
3274 try self.collectRebaseDataFromTableSection(self.got_section_index.?, rebase, self.got_table);3280 try collectRebaseDataFromTableSection(gpa, self, self.got_section_index.?, rebase, self.got_table);
3275 try self.collectRebaseDataFromTableSection(self.la_symbol_ptr_section_index.?, rebase, self.stub_table);3281 try collectRebaseDataFromTableSection(gpa, self, self.la_symbol_ptr_section_index.?, rebase, self.stub_table);
32763282
3277 try rebase.finalize(gpa);3283 try rebase.finalize(gpa);
3278}3284}
32793285
3280fn collectBindDataFromTableSection(self: *MachO, sect_id: u8, bind: anytype, table: anytype) !void {3286pub fn collectBindDataFromTableSection(
3281 const header = self.sections.items(.header)[sect_id];3287 gpa: Allocator,
3282 const segment_index = self.sections.items(.segment_index)[sect_id];3288 ctx: anytype,
3283 const segment = self.segments.items[segment_index];3289 sect_id: u8,
3290 bind: anytype,
3291 table: anytype,
3292) !void {
3293 const header = ctx.sections.items(.header)[sect_id];
3294 const segment_index = ctx.sections.items(.segment_index)[sect_id];
3295 const segment = ctx.segments.items[segment_index];
3284 const base_offset = header.addr - segment.vmaddr;3296 const base_offset = header.addr - segment.vmaddr;
32853297
3286 try bind.entries.ensureUnusedCapacity(self.base.allocator, table.entries.items.len);3298 try bind.entries.ensureUnusedCapacity(gpa, table.entries.items.len);
32873299
3288 for (table.entries.items, 0..) |entry, i| {3300 for (table.entries.items, 0..) |entry, i| {
3289 if (!table.lookup.contains(entry)) continue;3301 if (!table.lookup.contains(entry)) continue;
3290 const bind_sym = self.getSymbol(entry);3302 const bind_sym = ctx.getSymbol(entry);
3291 if (!bind_sym.undf()) continue;3303 if (!bind_sym.undf()) continue;
3292 const offset = i * @sizeOf(u64);3304 const offset = i * @sizeOf(u64);
3293 log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{3305 log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
3294 base_offset + offset,3306 base_offset + offset,
3295 self.getSymbolName(entry),3307 ctx.getSymbolName(entry),
3296 @divTrunc(@as(i16, @bitCast(bind_sym.n_desc)), macho.N_SYMBOL_RESOLVER),3308 @divTrunc(@as(i16, @bitCast(bind_sym.n_desc)), macho.N_SYMBOL_RESOLVER),
3297 });3309 });
3298 if (bind_sym.weakRef()) {3310 if (bind_sym.weakRef()) {
...@@ -3349,12 +3361,12 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {...@@ -3349,12 +3361,12 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {
3349 }3361 }
33503362
3351 // Gather GOT pointers3363 // Gather GOT pointers
3352 try self.collectBindDataFromTableSection(self.got_section_index.?, bind, self.got_table);3364 try collectBindDataFromTableSection(gpa, self, self.got_section_index.?, bind, self.got_table);
3353 try bind.finalize(gpa, self);3365 try bind.finalize(gpa, self);
3354}3366}
33553367
3356fn collectLazyBindData(self: *MachO, bind: anytype) !void {3368fn collectLazyBindData(self: *MachO, bind: anytype) !void {
3357 try self.collectBindDataFromTableSection(self.la_symbol_ptr_section_index.?, bind, self.stub_table);3369 try collectBindDataFromTableSection(self.base.allocator, self, self.la_symbol_ptr_section_index.?, bind, self.stub_table);
3358 try bind.finalize(self.base.allocator, self);3370 try bind.finalize(self.base.allocator, self);
3359}3371}
33603372
src/link/MachO/Atom.zig+14-23
...@@ -358,10 +358,7 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {...@@ -358,10 +358,7 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {
358 return target;358 return target;
359}359}
360360
361pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc, is_via_got: bool) ?Index {361pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc) ?Index {
362 if (is_via_got) {
363 return zld.getGotAtomIndexForSymbol(target).?; // panic means fatal error
364 }
365 if (zld.getStubsAtomIndexForSymbol(target)) |stubs_atom| return stubs_atom;362 if (zld.getStubsAtomIndexForSymbol(target)) |stubs_atom| return stubs_atom;
366 if (zld.getTlvPtrAtomIndexForSymbol(target)) |tlv_ptr_atom| return tlv_ptr_atom;363 if (zld.getTlvPtrAtomIndexForSymbol(target)) |tlv_ptr_atom| return tlv_ptr_atom;
367364
...@@ -411,7 +408,7 @@ fn scanAtomRelocsArm64(zld: *Zld, atom_index: Index, relocs: []align(1) const ma...@@ -411,7 +408,7 @@ fn scanAtomRelocsArm64(zld: *Zld, atom_index: Index, relocs: []align(1) const ma
411 .ARM64_RELOC_POINTER_TO_GOT,408 .ARM64_RELOC_POINTER_TO_GOT,
412 => {409 => {
413 // TODO rewrite relocation410 // TODO rewrite relocation
414 try addGotEntry(zld, target);411 try zld.addGotEntry(target);
415 },412 },
416 .ARM64_RELOC_TLVP_LOAD_PAGE21,413 .ARM64_RELOC_TLVP_LOAD_PAGE21,
417 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12,414 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
...@@ -454,7 +451,7 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach...@@ -454,7 +451,7 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach
454 },451 },
455 .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => {452 .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => {
456 // TODO rewrite relocation453 // TODO rewrite relocation
457 try addGotEntry(zld, target);454 try zld.addGotEntry(target);
458 },455 },
459 .X86_64_RELOC_TLV => {456 .X86_64_RELOC_TLV => {
460 try addTlvPtrEntry(zld, target);457 try addTlvPtrEntry(zld, target);
...@@ -479,18 +476,6 @@ fn addTlvPtrEntry(zld: *Zld, target: SymbolWithLoc) !void {...@@ -479,18 +476,6 @@ fn addTlvPtrEntry(zld: *Zld, target: SymbolWithLoc) !void {
479 try zld.tlv_ptr_table.putNoClobber(gpa, target, tlv_ptr_index);476 try zld.tlv_ptr_table.putNoClobber(gpa, target, tlv_ptr_index);
480}477}
481478
482pub fn addGotEntry(zld: *Zld, target: SymbolWithLoc) !void {
483 if (zld.got_table.contains(target)) return;
484 const gpa = zld.gpa;
485 const atom_index = try zld.createGotAtom();
486 const got_index = @as(u32, @intCast(zld.got_entries.items.len));
487 try zld.got_entries.append(gpa, .{
488 .target = target,
489 .atom_index = atom_index,
490 });
491 try zld.got_table.putNoClobber(gpa, target, got_index);
492}
493
494pub fn addStub(zld: *Zld, target: SymbolWithLoc) !void {479pub fn addStub(zld: *Zld, target: SymbolWithLoc) !void {
495 const target_sym = zld.getSymbol(target);480 const target_sym = zld.getSymbol(target);
496 if (!target_sym.undf()) return;481 if (!target_sym.undf()) return;
...@@ -532,8 +517,8 @@ pub fn resolveRelocs(...@@ -532,8 +517,8 @@ pub fn resolveRelocs(
532 };517 };
533}518}
534519
535pub fn getRelocTargetAddress(zld: *Zld, target: SymbolWithLoc, is_via_got: bool, is_tlv: bool) !u64 {520pub fn getRelocTargetAddress(zld: *Zld, target: SymbolWithLoc, is_tlv: bool) !u64 {
536 const target_atom_index = getRelocTargetAtomIndex(zld, target, is_via_got) orelse {521 const target_atom_index = getRelocTargetAtomIndex(zld, target) orelse {
537 // If there is no atom for target, we still need to check for special, atom-less522 // If there is no atom for target, we still need to check for special, atom-less
538 // symbols such as `___dso_handle`.523 // symbols such as `___dso_handle`.
539 const target_name = zld.getSymbolName(target);524 const target_name = zld.getSymbolName(target);
...@@ -656,7 +641,10 @@ fn resolveRelocsArm64(...@@ -656,7 +641,10 @@ fn resolveRelocsArm64(
656 const header = zld.sections.items(.header)[source_sym.n_sect - 1];641 const header = zld.sections.items(.header)[source_sym.n_sect - 1];
657 break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;642 break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
658 };643 };
659 const target_addr = try getRelocTargetAddress(zld, target, is_via_got, is_tlv);644 const target_addr = if (is_via_got)
645 zld.getGotEntryAddress(target).?
646 else
647 try getRelocTargetAddress(zld, target, is_tlv);
660648
661 log.debug(" | source_addr = 0x{x}", .{source_addr});649 log.debug(" | source_addr = 0x{x}", .{source_addr});
662650
...@@ -670,7 +658,7 @@ fn resolveRelocsArm64(...@@ -670,7 +658,7 @@ fn resolveRelocsArm64(
670 zld.getSymbolName(atom.getSymbolWithLoc()),658 zld.getSymbolName(atom.getSymbolWithLoc()),
671 atom.getFile(),659 atom.getFile(),
672 zld.getSymbolName(target),660 zld.getSymbolName(target),
673 zld.getAtom(getRelocTargetAtomIndex(zld, target, is_via_got).?).getFile(),661 zld.getAtom(getRelocTargetAtomIndex(zld, target).?).getFile(),
674 });662 });
675663
676 const displacement = if (Relocation.calcPcRelativeDisplacementArm64(664 const displacement = if (Relocation.calcPcRelativeDisplacementArm64(
...@@ -953,7 +941,10 @@ fn resolveRelocsX86(...@@ -953,7 +941,10 @@ fn resolveRelocsX86(
953941
954 log.debug(" | source_addr = 0x{x}", .{source_addr});942 log.debug(" | source_addr = 0x{x}", .{source_addr});
955943
956 const target_addr = try getRelocTargetAddress(zld, target, is_via_got, is_tlv);944 const target_addr = if (is_via_got)
945 zld.getGotEntryAddress(target).?
946 else
947 try getRelocTargetAddress(zld, target, is_tlv);
957948
958 switch (rel_type) {949 switch (rel_type) {
959 .X86_64_RELOC_BRANCH => {950 .X86_64_RELOC_BRANCH => {
src/link/MachO/UnwindInfo.zig+3-5
...@@ -226,7 +226,7 @@ pub fn scanRelocs(zld: *Zld) !void {...@@ -226,7 +226,7 @@ pub fn scanRelocs(zld: *Zld) !void {
226 .code = mem.asBytes(&record),226 .code = mem.asBytes(&record),
227 .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),227 .base_offset = @as(i32, @intCast(record_id * @sizeOf(macho.compact_unwind_entry))),
228 });228 });
229 try Atom.addGotEntry(zld, target);229 try zld.addGotEntry(target);
230 }230 }
231 }231 }
232 }232 }
...@@ -585,10 +585,8 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {...@@ -585,10 +585,8 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {
585585
586 log.debug("Personalities:", .{});586 log.debug("Personalities:", .{});
587 for (info.personalities[0..info.personalities_count], 0..) |target, i| {587 for (info.personalities[0..info.personalities_count], 0..) |target, i| {
588 const atom_index = zld.getGotAtomIndexForSymbol(target).?;588 const addr = zld.getGotEntryAddress(target).?;
589 const atom = zld.getAtom(atom_index);589 personalities[i] = @as(u32, @intCast(addr - seg.vmaddr));
590 const sym = zld.getSymbol(atom.getSymbolWithLoc());
591 personalities[i] = @as(u32, @intCast(sym.n_value - seg.vmaddr));
592 log.debug(" {d}: 0x{x} ({s})", .{ i, personalities[i], zld.getSymbolName(target) });590 log.debug(" {d}: 0x{x} ({s})", .{ i, personalities[i], zld.getSymbolName(target) });
593 }591 }
594592
src/link/MachO/eh_frame.zig+4-4
...@@ -267,7 +267,7 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {...@@ -267,7 +267,7 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
267 source_offset: u32,267 source_offset: u32,
268 ) !void {268 ) !void {
269 if (rec.getPersonalityPointerReloc(zld, object_id, source_offset)) |target| {269 if (rec.getPersonalityPointerReloc(zld, object_id, source_offset)) |target| {
270 try Atom.addGotEntry(zld, target);270 try zld.addGotEntry(target);
271 }271 }
272 }272 }
273273
...@@ -357,14 +357,14 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {...@@ -357,14 +357,14 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
357 // Address of the __eh_frame in the source object file357 // Address of the __eh_frame in the source object file
358 },358 },
359 .ARM64_RELOC_POINTER_TO_GOT => {359 .ARM64_RELOC_POINTER_TO_GOT => {
360 const target_addr = try Atom.getRelocTargetAddress(zld, target, true, false);360 const target_addr = zld.getGotEntryAddress(target).?;
361 const result = math.cast(i32, @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr))) orelse361 const result = math.cast(i32, @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr))) orelse
362 return error.Overflow;362 return error.Overflow;
363 mem.writeIntLittle(i32, rec.data[rel_offset..][0..4], result);363 mem.writeIntLittle(i32, rec.data[rel_offset..][0..4], result);
364 },364 },
365 .ARM64_RELOC_UNSIGNED => {365 .ARM64_RELOC_UNSIGNED => {
366 assert(rel.r_extern == 1);366 assert(rel.r_extern == 1);
367 const target_addr = try Atom.getRelocTargetAddress(zld, target, false, false);367 const target_addr = try Atom.getRelocTargetAddress(zld, target, false);
368 const result = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr));368 const result = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr));
369 mem.writeIntLittle(i64, rec.data[rel_offset..][0..8], @as(i64, @intCast(result)));369 mem.writeIntLittle(i64, rec.data[rel_offset..][0..8], @as(i64, @intCast(result)));
370 },370 },
...@@ -375,7 +375,7 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {...@@ -375,7 +375,7 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
375 const rel_type = @as(macho.reloc_type_x86_64, @enumFromInt(rel.r_type));375 const rel_type = @as(macho.reloc_type_x86_64, @enumFromInt(rel.r_type));
376 switch (rel_type) {376 switch (rel_type) {
377 .X86_64_RELOC_GOT => {377 .X86_64_RELOC_GOT => {
378 const target_addr = try Atom.getRelocTargetAddress(zld, target, true, false);378 const target_addr = zld.getGotEntryAddress(target).?;
379 const addend = mem.readIntLittle(i32, rec.data[rel_offset..][0..4]);379 const addend = mem.readIntLittle(i32, rec.data[rel_offset..][0..4]);
380 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));380 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
381 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);381 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
src/link/MachO/thunks.zig+4-1
...@@ -318,7 +318,10 @@ fn isReachable(...@@ -318,7 +318,10 @@ fn isReachable(
318318
319 const source_addr = source_sym.n_value + @as(u32, @intCast(rel.r_address - base_offset));319 const source_addr = source_sym.n_value + @as(u32, @intCast(rel.r_address - base_offset));
320 const is_via_got = Atom.relocRequiresGot(zld, rel);320 const is_via_got = Atom.relocRequiresGot(zld, rel);
321 const target_addr = Atom.getRelocTargetAddress(zld, target, is_via_got, false) catch unreachable;321 const target_addr = if (is_via_got)
322 zld.getGotEntryAddress(target).?
323 else
324 Atom.getRelocTargetAddress(zld, target, false) catch unreachable;
322 _ = Relocation.calcPcRelativeDisplacementArm64(source_addr, target_addr) catch325 _ = Relocation.calcPcRelativeDisplacementArm64(source_addr, target_addr) catch
323 return false;326 return false;
324327
src/link/MachO/zld.zig+98-132
...@@ -35,6 +35,7 @@ const Section = MachO.Section;...@@ -35,6 +35,7 @@ const Section = MachO.Section;
35const StringTable = @import("../strtab.zig").StringTable;35const StringTable = @import("../strtab.zig").StringTable;
36const SymbolWithLoc = MachO.SymbolWithLoc;36const SymbolWithLoc = MachO.SymbolWithLoc;
37const SymbolResolver = MachO.SymbolResolver;37const SymbolResolver = MachO.SymbolResolver;
38const TableSection = @import("../table_section.zig").TableSection;
38const Trie = @import("Trie.zig");39const Trie = @import("Trie.zig");
39const UnwindInfo = @import("UnwindInfo.zig");40const UnwindInfo = @import("UnwindInfo.zig");
4041
...@@ -66,6 +67,8 @@ pub const Zld = struct {...@@ -66,6 +67,8 @@ pub const Zld = struct {
66 segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},67 segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
67 sections: std.MultiArrayList(Section) = .{},68 sections: std.MultiArrayList(Section) = .{},
6869
70 got_section_index: ?u8 = null,
71
69 locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},72 locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
70 globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},73 globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
7174
...@@ -81,8 +84,7 @@ pub const Zld = struct {...@@ -81,8 +84,7 @@ pub const Zld = struct {
81 tlv_ptr_entries: std.ArrayListUnmanaged(IndirectPointer) = .{},84 tlv_ptr_entries: std.ArrayListUnmanaged(IndirectPointer) = .{},
82 tlv_ptr_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},85 tlv_ptr_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
8386
84 got_entries: std.ArrayListUnmanaged(IndirectPointer) = .{},87 got_table: TableSection(SymbolWithLoc) = .{},
85 got_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
8688
87 stubs: std.ArrayListUnmanaged(IndirectPointer) = .{},89 stubs: std.ArrayListUnmanaged(IndirectPointer) = .{},
88 stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},90 stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
...@@ -266,32 +268,6 @@ pub const Zld = struct {...@@ -266,32 +268,6 @@ pub const Zld = struct {
266 return index;268 return index;
267 }269 }
268270
269 pub fn createGotAtom(self: *Zld) !AtomIndex {
270 const sym_index = try self.allocateSymbol();
271 const atom_index = try self.createEmptyAtom(sym_index, @sizeOf(u64), 3);
272 const sym = self.getSymbolPtr(.{ .sym_index = sym_index });
273 sym.n_type = macho.N_SECT;
274
275 const sect_id = self.getSectionByName("__DATA_CONST", "__got") orelse
276 try self.initSection("__DATA_CONST", "__got", .{
277 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
278 });
279 sym.n_sect = sect_id + 1;
280
281 self.addAtomToSection(atom_index);
282
283 return atom_index;
284 }
285
286 fn writeGotPointer(self: *Zld, got_index: u32, writer: anytype) !void {
287 const target_addr = blk: {
288 const entry = self.got_entries.items[got_index];
289 const sym = entry.getTargetSymbol(self);
290 break :blk sym.n_value;
291 };
292 try writer.writeIntLittle(u64, target_addr);
293 }
294
295 pub fn createTlvPtrAtom(self: *Zld) !AtomIndex {271 pub fn createTlvPtrAtom(self: *Zld) !AtomIndex {
296 const sym_index = try self.allocateSymbol();272 const sym_index = try self.allocateSymbol();
297 const atom_index = try self.createEmptyAtom(sym_index, @sizeOf(u64), 3);273 const atom_index = try self.createEmptyAtom(sym_index, @sizeOf(u64), 3);
...@@ -311,16 +287,9 @@ pub const Zld = struct {...@@ -311,16 +287,9 @@ pub const Zld = struct {
311 }287 }
312288
313 fn createDyldStubBinderGotAtom(self: *Zld) !void {289 fn createDyldStubBinderGotAtom(self: *Zld) !void {
314 const gpa = self.gpa;
315 const global_index = self.dyld_stub_binder_index orelse return;290 const global_index = self.dyld_stub_binder_index orelse return;
316 const target = self.globals.items[global_index];291 const target = self.globals.items[global_index];
317 const atom_index = try self.createGotAtom();292 try self.addGotEntry(target);
318 const got_index = @as(u32, @intCast(self.got_entries.items.len));
319 try self.got_entries.append(gpa, .{
320 .target = target,
321 .atom_index = atom_index,
322 });
323 try self.got_table.putNoClobber(gpa, target, got_index);
324 }293 }
325294
326 fn createDyldPrivateAtom(self: *Zld) !void {295 fn createDyldPrivateAtom(self: *Zld) !void {
...@@ -381,9 +350,7 @@ pub const Zld = struct {...@@ -381,9 +350,7 @@ pub const Zld = struct {
381 };350 };
382 const dyld_stub_binder_got_addr = blk: {351 const dyld_stub_binder_got_addr = blk: {
383 const sym_loc = self.globals.items[self.dyld_stub_binder_index.?];352 const sym_loc = self.globals.items[self.dyld_stub_binder_index.?];
384 const index = self.got_table.get(sym_loc).?;353 break :blk self.getGotEntryAddress(sym_loc).?;
385 const entry = self.got_entries.items[index];
386 break :blk entry.getAtomSymbol(self).n_value;
387 };354 };
388 try stub_helpers.writeStubHelperPreambleCode(.{355 try stub_helpers.writeStubHelperPreambleCode(.{
389 .cpu_arch = cpu_arch,356 .cpu_arch = cpu_arch,
...@@ -876,7 +843,6 @@ pub const Zld = struct {...@@ -876,7 +843,6 @@ pub const Zld = struct {
876843
877 self.tlv_ptr_entries.deinit(gpa);844 self.tlv_ptr_entries.deinit(gpa);
878 self.tlv_ptr_table.deinit(gpa);845 self.tlv_ptr_table.deinit(gpa);
879 self.got_entries.deinit(gpa);
880 self.got_table.deinit(gpa);846 self.got_table.deinit(gpa);
881 self.stubs.deinit(gpa);847 self.stubs.deinit(gpa);
882 self.stubs_table.deinit(gpa);848 self.stubs_table.deinit(gpa);
...@@ -993,6 +959,16 @@ pub const Zld = struct {...@@ -993,6 +959,16 @@ pub const Zld = struct {
993 return global_index;959 return global_index;
994 }960 }
995961
962 pub fn addGotEntry(zld: *Zld, target: SymbolWithLoc) !void {
963 if (zld.got_table.lookup.contains(target)) return;
964 _ = try zld.got_table.allocateEntry(zld.gpa, target);
965 if (zld.got_section_index == null) {
966 zld.got_section_index = try zld.initSection("__DATA_CONST", "__got", .{
967 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
968 });
969 }
970 }
971
996 fn allocateSpecialSymbols(self: *Zld) !void {972 fn allocateSpecialSymbols(self: *Zld) !void {
997 for (&[_]?u32{973 for (&[_]?u32{
998 self.dso_handle_index,974 self.dso_handle_index,
...@@ -1056,9 +1032,7 @@ pub const Zld = struct {...@@ -1056,9 +1032,7 @@ pub const Zld = struct {
1056 buffer.appendSliceAssumeCapacity(&[_]u8{0} ** @sizeOf(u64));1032 buffer.appendSliceAssumeCapacity(&[_]u8{0} ** @sizeOf(u64));
1057 } else if (atom.getFile() == null) outer: {1033 } else if (atom.getFile() == null) outer: {
1058 switch (header.type()) {1034 switch (header.type()) {
1059 macho.S_NON_LAZY_SYMBOL_POINTERS => {1035 macho.S_NON_LAZY_SYMBOL_POINTERS => unreachable,
1060 try self.writeGotPointer(count, buffer.writer());
1061 },
1062 macho.S_LAZY_SYMBOL_POINTERS => {1036 macho.S_LAZY_SYMBOL_POINTERS => {
1063 try self.writeLazyPointer(count, buffer.writer());1037 try self.writeLazyPointer(count, buffer.writer());
1064 },1038 },
...@@ -1113,41 +1087,70 @@ pub const Zld = struct {...@@ -1113,41 +1087,70 @@ pub const Zld = struct {
1113 }1087 }
1114 }1088 }
11151089
1090 fn writeGotEntries(self: *Zld) !void {
1091 const sect_id = self.got_section_index orelse return;
1092 const header = self.sections.items(.header)[sect_id];
1093 var buffer = try std.ArrayList(u8).initCapacity(self.gpa, header.size);
1094 defer buffer.deinit();
1095 for (self.got_table.entries.items) |entry| {
1096 const sym = self.getSymbol(entry);
1097 buffer.writer().writeIntLittle(u64, sym.n_value) catch unreachable;
1098 }
1099 log.debug("writing .got contents at file offset 0x{x}", .{header.offset});
1100 try self.file.pwriteAll(buffer.items, header.offset);
1101 }
1102
1116 fn pruneAndSortSections(self: *Zld) !void {1103 fn pruneAndSortSections(self: *Zld) !void {
1117 const gpa = self.gpa;1104 const Entry = struct {
1105 index: u8,
11181106
1119 const SortSection = struct {1107 pub fn lessThan(zld: *Zld, lhs: @This(), rhs: @This()) bool {
1120 pub fn lessThan(_: void, lhs: Section, rhs: Section) bool {1108 const lhs_header = zld.sections.items(.header)[lhs.index];
1121 return getSectionPrecedence(lhs.header) < getSectionPrecedence(rhs.header);1109 const rhs_header = zld.sections.items(.header)[rhs.index];
1110 return getSectionPrecedence(lhs_header) < getSectionPrecedence(rhs_header);
1122 }1111 }
1123 };1112 };
11241113
1125 const slice = self.sections.slice();1114 const gpa = self.gpa;
1126 var sections = std.ArrayList(Section).init(gpa);
1127 defer sections.deinit();
1128 try sections.ensureTotalCapacity(slice.len);
11291115
1130 {1116 var entries = try std.ArrayList(Entry).initCapacity(gpa, self.sections.slice().len);
1131 var i: u8 = 0;1117 defer entries.deinit();
1132 while (i < slice.len) : (i += 1) {1118
1133 const section = self.sections.get(i);1119 for (0..self.sections.slice().len) |index| {
1134 if (section.header.size == 0) {1120 const section = self.sections.get(index);
1135 log.debug("pruning section {s},{s} {?d}", .{1121 if (section.header.size == 0) {
1136 section.header.segName(),1122 log.debug("pruning section {s},{s} {?d}", .{
1137 section.header.sectName(),1123 section.header.segName(),
1138 section.first_atom_index,1124 section.header.sectName(),
1139 });1125 section.first_atom_index,
1140 continue;1126 });
1141 }1127 continue;
1142 sections.appendAssumeCapacity(section);
1143 }1128 }
1129 entries.appendAssumeCapacity(.{ .index = @intCast(index) });
1130 }
1131
1132 mem.sort(Entry, entries.items, self, Entry.lessThan);
1133
1134 var slice = self.sections.toOwnedSlice();
1135 defer slice.deinit(gpa);
1136
1137 const backlinks = try gpa.alloc(u8, slice.len);
1138 defer gpa.free(backlinks);
1139 for (entries.items, 0..) |entry, i| {
1140 backlinks[entry.index] = @as(u8, @intCast(i));
1144 }1141 }
11451142
1146 mem.sort(Section, sections.items, {}, SortSection.lessThan);1143 try self.sections.ensureTotalCapacity(gpa, entries.items.len);
1144 for (entries.items) |entry| {
1145 self.sections.appendAssumeCapacity(slice.get(entry.index));
1146 }
11471147
1148 self.sections.shrinkRetainingCapacity(0);1148 for (&[_]*?u8{
1149 for (sections.items) |out| {1149 &self.got_section_index,
1150 self.sections.appendAssumeCapacity(out);1150 }) |maybe_index| {
1151 if (maybe_index.*) |*index| {
1152 index.* = backlinks[index.*];
1153 }
1151 }1154 }
1152 }1155 }
11531156
...@@ -1227,6 +1230,12 @@ pub const Zld = struct {...@@ -1227,6 +1230,12 @@ pub const Zld = struct {
1227 } else break;1230 } else break;
1228 }1231 }
1229 }1232 }
1233
1234 if (self.got_section_index) |sect_id| {
1235 const header = &self.sections.items(.header)[sect_id];
1236 header.size = self.got_table.count() * @sizeOf(u64);
1237 header.@"align" = 3;
1238 }
1230 }1239 }
12311240
1232 fn allocateSegments(self: *Zld) !void {1241 fn allocateSegments(self: *Zld) !void {
...@@ -1448,40 +1457,12 @@ pub const Zld = struct {...@@ -1448,40 +1457,12 @@ pub const Zld = struct {
1448 seg.vmsize = mem.alignForward(u64, seg.filesize, MachO.getPageSize(self.options.target.cpu.arch));1457 seg.vmsize = mem.alignForward(u64, seg.filesize, MachO.getPageSize(self.options.target.cpu.arch));
1449 }1458 }
14501459
1451 fn collectRebaseDataFromContainer(
1452 self: *Zld,
1453 sect_id: u8,
1454 rebase: *Rebase,
1455 container: anytype,
1456 ) !void {
1457 const slice = self.sections.slice();
1458 const segment_index = slice.items(.segment_index)[sect_id];
1459 const seg = self.getSegment(sect_id);
1460
1461 try rebase.entries.ensureUnusedCapacity(self.gpa, container.items.len);
1462
1463 for (container.items) |entry| {
1464 const target_sym = entry.getTargetSymbol(self);
1465 if (target_sym.undf()) continue;
1466
1467 const atom_sym = entry.getAtomSymbol(self);
1468 const base_offset = atom_sym.n_value - seg.vmaddr;
1469
1470 log.debug(" | rebase at {x}", .{base_offset});
1471
1472 rebase.entries.appendAssumeCapacity(.{
1473 .offset = base_offset,
1474 .segment_id = segment_index,
1475 });
1476 }
1477 }
1478
1479 fn collectRebaseData(self: *Zld, rebase: *Rebase) !void {1460 fn collectRebaseData(self: *Zld, rebase: *Rebase) !void {
1480 log.debug("collecting rebase data", .{});1461 log.debug("collecting rebase data", .{});
14811462
1482 // First, unpack GOT entries1463 // First, unpack GOT entries
1483 if (self.getSectionByName("__DATA_CONST", "__got")) |sect_id| {1464 if (self.got_section_index) |sect_id| {
1484 try self.collectRebaseDataFromContainer(sect_id, rebase, self.got_entries);1465 try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.got_table);
1485 }1466 }
14861467
1487 const slice = self.sections.slice();1468 const slice = self.sections.slice();
...@@ -1543,7 +1524,11 @@ pub const Zld = struct {...@@ -1543,7 +1524,11 @@ pub const Zld = struct {
1543 };1524 };
15441525
1545 if (should_rebase) {1526 if (should_rebase) {
1546 log.debug(" ATOM({d}, %{d}, '{s}')", .{ atom_index, atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) });1527 log.debug(" ATOM({d}, %{d}, '{s}')", .{
1528 atom_index,
1529 atom.sym_index,
1530 self.getSymbolName(atom.getSymbolWithLoc()),
1531 });
15471532
1548 const code = Atom.getAtomCode(self, atom_index);1533 const code = Atom.getAtomCode(self, atom_index);
1549 const relocs = Atom.getAtomRelocs(self, atom_index);1534 const relocs = Atom.getAtomRelocs(self, atom_index);
...@@ -1639,8 +1624,8 @@ pub const Zld = struct {...@@ -1639,8 +1624,8 @@ pub const Zld = struct {
1639 log.debug("collecting bind data", .{});1624 log.debug("collecting bind data", .{});
16401625
1641 // First, unpack GOT section1626 // First, unpack GOT section
1642 if (self.getSectionByName("__DATA_CONST", "__got")) |sect_id| {1627 if (self.got_section_index) |sect_id| {
1643 try self.collectBindDataFromContainer(sect_id, bind, self.got_entries);1628 try MachO.collectBindDataFromTableSection(self.gpa, self, sect_id, bind, self.got_table);
1644 }1629 }
16451630
1646 // Next, unpack TLV pointers section1631 // Next, unpack TLV pointers section
...@@ -2237,7 +2222,7 @@ pub const Zld = struct {...@@ -2237,7 +2222,7 @@ pub const Zld = struct {
2237 fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void {2222 fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void {
2238 const gpa = self.gpa;2223 const gpa = self.gpa;
2239 const nstubs = @as(u32, @intCast(self.stubs.items.len));2224 const nstubs = @as(u32, @intCast(self.stubs.items.len));
2240 const ngot_entries = @as(u32, @intCast(self.got_entries.items.len));2225 const ngot_entries = @as(u32, @intCast(self.got_table.lookup.count()));
2241 const nindirectsyms = nstubs * 2 + ngot_entries;2226 const nindirectsyms = nstubs * 2 + ngot_entries;
2242 const iextdefsym = ctx.nlocalsym;2227 const iextdefsym = ctx.nlocalsym;
2243 const iundefsym = iextdefsym + ctx.nextdefsym;2228 const iundefsym = iextdefsym + ctx.nextdefsym;
...@@ -2266,13 +2251,14 @@ pub const Zld = struct {...@@ -2266,13 +2251,14 @@ pub const Zld = struct {
2266 }2251 }
2267 }2252 }
22682253
2269 if (self.getSectionByName("__DATA_CONST", "__got")) |sect_id| {2254 if (self.got_section_index) |sect_id| {
2270 const got = &self.sections.items(.header)[sect_id];2255 const got = &self.sections.items(.header)[sect_id];
2271 got.reserved1 = nstubs;2256 got.reserved1 = nstubs;
2272 for (self.got_entries.items) |entry| {2257 for (self.got_table.entries.items) |entry| {
2273 const target_sym = entry.getTargetSymbol(self);2258 if (!self.got_table.lookup.contains(entry)) continue;
2259 const target_sym = self.getSymbol(entry);
2274 if (target_sym.undf()) {2260 if (target_sym.undf()) {
2275 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);2261 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?);
2276 } else {2262 } else {
2277 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);2263 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
2278 }2264 }
...@@ -2496,12 +2482,10 @@ pub const Zld = struct {...@@ -2496,12 +2482,10 @@ pub const Zld = struct {
2496 }2482 }
2497 }2483 }
24982484
2499 /// Returns GOT atom that references `sym_with_loc` if one exists.2485 pub fn getGotEntryAddress(self: *Zld, sym_with_loc: SymbolWithLoc) ?u64 {
2500 /// Returns null otherwise.2486 const index = self.got_table.lookup.get(sym_with_loc) orelse return null;
2501 pub fn getGotAtomIndexForSymbol(self: *Zld, sym_with_loc: SymbolWithLoc) ?AtomIndex {2487 const header = self.sections.items(.header)[self.got_section_index.?];
2502 const index = self.got_table.get(sym_with_loc) orelse return null;2488 return header.addr + @sizeOf(u64) * index;
2503 const entry = self.got_entries.items[index];
2504 return entry.atom_index;
2505 }2489 }
25062490
2507 /// Returns stubs atom that references `sym_with_loc` if one exists.2491 /// Returns stubs atom that references `sym_with_loc` if one exists.
...@@ -2849,26 +2833,7 @@ pub const Zld = struct {...@@ -2849,26 +2833,7 @@ pub const Zld = struct {
2849 }2833 }
28502834
2851 scoped_log.debug("GOT entries:", .{});2835 scoped_log.debug("GOT entries:", .{});
2852 for (self.got_entries.items, 0..) |entry, i| {2836 scoped_log.debug("{}", .{self.got_table});
2853 const atom_sym = entry.getAtomSymbol(self);
2854 const target_sym = entry.getTargetSymbol(self);
2855 const target_sym_name = entry.getTargetSymbolName(self);
2856 if (target_sym.undf()) {
2857 scoped_log.debug(" {d}@{x} => import('{s}')", .{
2858 i,
2859 atom_sym.n_value,
2860 target_sym_name,
2861 });
2862 } else {
2863 scoped_log.debug(" {d}@{x} => local(%{d}) in object({?}) {s}", .{
2864 i,
2865 atom_sym.n_value,
2866 entry.target.sym_index,
2867 entry.target.file,
2868 logSymAttributes(target_sym, buf[0..4]),
2869 });
2870 }
2871 }
28722837
2873 scoped_log.debug("__thread_ptrs entries:", .{});2838 scoped_log.debug("__thread_ptrs entries:", .{});
2874 for (self.tlv_ptr_entries.items, 0..) |entry, i| {2839 for (self.tlv_ptr_entries.items, 0..) |entry, i| {
...@@ -3470,6 +3435,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3470,6 +3435,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3470 }3435 }
34713436
3472 try zld.writeAtoms();3437 try zld.writeAtoms();
3438 try zld.writeGotEntries();
3473 try eh_frame.write(&zld, &unwind_info);3439 try eh_frame.write(&zld, &unwind_info);
3474 try unwind_info.write(&zld);3440 try unwind_info.write(&zld);
3475 try zld.writeLinkeditSegmentData();3441 try zld.writeLinkeditSegmentData();