authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-07 07:37:35+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-13 11:47:51+02:00
log094ff60252cf57b2ae7bb69abb3e8e696873a3be
tree34b87d0d8962450c64de422fc2438236f3d70f8e
parent09b6bd86dea690aeb1fe1a832bb56b44b414120b

macho: emit TLV pointers and variables


3 files changed, 135 insertions(+), 36 deletions(-)

src/link.zig+2-2
......@@ -540,7 +540,7 @@ pub const File = struct {
540540 /// May be called before or after updateDeclExports for any given Decl.
541541 pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
542542 const decl = module.declPtr(decl_index);
543 log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmtDebug() });
543 log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmt(module) });
544544 assert(decl.has_tv);
545545 if (build_options.only_c) {
546546 assert(base.tag == .c);
......@@ -564,7 +564,7 @@ pub const File = struct {
564564 pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void {
565565 const owner_decl = module.declPtr(func.owner_decl);
566566 log.debug("updateFunc {*} ({s}), type={}", .{
567 owner_decl, owner_decl.name, owner_decl.ty.fmtDebug(),
567 owner_decl, owner_decl.name, owner_decl.ty.fmt(module),
568568 });
569569 if (build_options.only_c) {
570570 assert(base.tag == .c);
src/link/MachO.zig+119-31
......@@ -1338,13 +1338,12 @@ pub fn createAtom(self: *MachO) !Atom.Index {
13381338
13391339pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
13401340 const atom_index = try self.createAtom();
1341 const atom = self.getAtomPtr(atom_index);
1342 atom.size = @sizeOf(u64);
1341 self.getAtomPtr(atom_index).size = @sizeOf(u64);
13431342
1344 const sym = atom.getSymbolPtr(self);
1343 const sym = self.getAtom(atom_index).getSymbolPtr(self);
13451344 sym.n_type = macho.N_SECT;
13461345 sym.n_sect = self.got_section_index.? + 1;
1347 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));
1346 sym.n_value = try self.allocateAtom(atom_index, @sizeOf(u64), @alignOf(u64));
13481347
13491348 log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});
13501349
......@@ -1553,7 +1552,7 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {
15531552
15541553 try Atom.addRelocation(self, atom_index, .{
15551554 .type = .branch,
1556 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },
1555 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index },
15571556 .offset = 6,
15581557 .addend = 0,
15591558 .pcrel = true,
......@@ -1576,7 +1575,7 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {
15761575
15771576 try Atom.addRelocation(self, atom_index, .{
15781577 .type = .branch,
1579 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },
1578 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index },
15801579 .offset = 4,
15811580 .addend = 0,
15821581 .pcrel = true,
......@@ -1604,7 +1603,7 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLo
16041603
16051604 try Atom.addRelocation(self, atom_index, .{
16061605 .type = .unsigned,
1607 .target = .{ .sym_index = stub_sym_index, .file = null },
1606 .target = .{ .sym_index = stub_sym_index },
16081607 .offset = 0,
16091608 .addend = 0,
16101609 .pcrel = false,
......@@ -1658,7 +1657,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
16581657
16591658 try Atom.addRelocation(self, atom_index, .{
16601659 .type = .branch,
1661 .target = .{ .sym_index = laptr_sym_index, .file = null },
1660 .target = .{ .sym_index = laptr_sym_index },
16621661 .offset = 2,
16631662 .addend = 0,
16641663 .pcrel = true,
......@@ -1680,7 +1679,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
16801679 try Atom.addRelocations(self, atom_index, &[_]Relocation{
16811680 .{
16821681 .type = .page,
1683 .target = .{ .sym_index = laptr_sym_index, .file = null },
1682 .target = .{ .sym_index = laptr_sym_index },
16841683 .offset = 0,
16851684 .addend = 0,
16861685 .pcrel = true,
......@@ -1688,7 +1687,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
16881687 },
16891688 .{
16901689 .type = .pageoff,
1691 .target = .{ .sym_index = laptr_sym_index, .file = null },
1690 .target = .{ .sym_index = laptr_sym_index },
16921691 .offset = 4,
16931692 .addend = 0,
16941693 .pcrel = false,
......@@ -1706,6 +1705,67 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
17061705 return atom_index;
17071706}
17081707
1708fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1709 const gpa = self.base.allocator;
1710 const size = 3 * @sizeOf(u64);
1711 const required_alignment: u32 = 1;
1712 const atom_index = try self.createAtom();
1713 self.getAtomPtr(atom_index).size = size;
1714
1715 const target_sym_name = self.getSymbolName(target);
1716 const name_delimiter = mem.indexOf(u8, target_sym_name, "$").?;
1717 const sym_name = try gpa.dupe(u8, target_sym_name[0..name_delimiter]);
1718 defer gpa.free(sym_name);
1719
1720 const sym = self.getAtom(atom_index).getSymbolPtr(self);
1721 sym.n_type = macho.N_SECT;
1722 sym.n_sect = self.thread_vars_section_index.? + 1;
1723 sym.n_strx = try self.strtab.insert(gpa, sym_name);
1724 sym.n_value = try self.allocateAtom(atom_index, size, required_alignment);
1725
1726 log.debug("allocated threadlocal descriptor atom '{s}' at 0x{x}", .{ sym_name, sym.n_value });
1727
1728 try Atom.addRelocation(self, atom_index, .{
1729 .type = .tlv_initializer,
1730 .target = target,
1731 .offset = 0x10,
1732 .addend = 0,
1733 .pcrel = false,
1734 .length = 3,
1735 });
1736
1737 var code: [size]u8 = undefined;
1738 mem.set(u8, &code, 0);
1739 try self.writeAtom(atom_index, &code);
1740
1741 return atom_index;
1742}
1743
1744fn createThreadLocalPointerAtom(self: *MachO, tlv_desc_sym_index: u32) !Atom.Index {
1745 const atom_index = try self.createAtom();
1746 self.getAtomPtr(atom_index).size = @sizeOf(u64);
1747
1748 const sym = self.getAtom(atom_index).getSymbolPtr(self);
1749 sym.n_type = macho.N_SECT;
1750 sym.n_sect = self.thread_ptr_section_index.? + 1;
1751 sym.n_value = try self.allocateAtom(atom_index, @sizeOf(u64), @alignOf(u64));
1752
1753 log.debug("allocated threadlocal pointer atom at 0x{x}", .{sym.n_value});
1754
1755 try Atom.addRelocation(self, atom_index, .{
1756 .type = .unsigned,
1757 .target = .{ .sym_index = tlv_desc_sym_index },
1758 .offset = 0,
1759 .addend = 0,
1760 .pcrel = false,
1761 .length = 3,
1762 });
1763 try Atom.addRebase(self, atom_index, 0);
1764 try self.writePtrWidthAtom(atom_index);
1765
1766 return atom_index;
1767}
1768
17091769fn createMhExecuteHeaderSymbol(self: *MachO) !void {
17101770 if (self.base.options.output_mode != .Exe) return;
17111771 if (self.getGlobal("__mh_execute_header")) |global| {
......@@ -2091,6 +2151,13 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
20912151
20922152fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void {
20932153 if (self.tlvp_table.lookup.contains(target)) return;
2154 const tlvp_index = try self.tlvp_table.allocateEntry(self.base.allocator, target);
2155 const tlv_desc_atom_index = try self.createThreadLocalDescriptorAtom(target);
2156 const tlv_desc_atom = self.getAtom(tlv_desc_atom_index);
2157 const tlv_ptr_atom_index = try self.createThreadLocalPointerAtom(tlv_desc_atom.getSymbolIndex().?);
2158 const tlv_ptr_atom = self.getAtom(tlv_ptr_atom_index);
2159 self.tlvp_table.entries.items[tlvp_index].sym_index = tlv_ptr_atom.getSymbolIndex().?;
2160 self.markRelocsDirtyByTarget(target);
20942161}
20952162
20962163pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
......@@ -2444,16 +2511,28 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
24442511
24452512 const required_alignment = decl.getAlignment(self.base.options.target);
24462513
2447 const sym_name = try decl.getFullyQualifiedName(mod);
2448 defer self.base.allocator.free(sym_name);
2514 const decl_name = try decl.getFullyQualifiedName(mod);
2515 defer gpa.free(decl_name);
24492516
24502517 const decl_metadata = self.decls.get(decl_index).?;
24512518 const atom_index = decl_metadata.atom;
24522519 const atom = self.getAtom(atom_index);
24532520 const sym_index = atom.getSymbolIndex().?;
24542521 const sect_id = decl_metadata.section;
2522 const header = &self.sections.items(.header)[sect_id];
2523 const segment = self.getSegment(sect_id);
2524 const is_threadlocal = if (!self.base.options.single_threaded)
2525 header.flags == macho.S_THREAD_LOCAL_REGULAR or header.flags == macho.S_THREAD_LOCAL_ZEROFILL
2526 else
2527 false;
24552528 const code_len = code.len;
24562529
2530 const sym_name = if (is_threadlocal)
2531 try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{decl_name})
2532 else
2533 decl_name;
2534 defer if (is_threadlocal) gpa.free(sym_name);
2535
24572536 if (atom.size != 0) {
24582537 const sym = atom.getSymbolPtr(self);
24592538 sym.n_strx = try self.strtab.insert(gpa, sym_name);
......@@ -2471,25 +2550,29 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
24712550
24722551 if (vaddr != sym.n_value) {
24732552 sym.n_value = vaddr;
2474 log.debug(" (updating GOT entry)", .{});
2475 const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
2476 const got_atom_index = self.got_table.getAtomIndex(self, got_target).?;
2477 self.markRelocsDirtyByTarget(got_target);
2478 try self.writePtrWidthAtom(got_atom_index);
2553 const target = SymbolWithLoc{ .sym_index = sym_index };
2554 self.markRelocsDirtyByTarget(target);
2555 if (is_threadlocal) {
2556 @panic("TODO update the threadlocal variable's name also");
2557 // log.debug(" (updating threadlocal pointer entry)", .{});
2558 // const tlvp_atom_index = self.tlvp_table.getAtomIndex(self, target).?;
2559 // try self.writePtrWidthAtom(tlvp_atom_index);
2560 } else {
2561 log.debug(" (updating GOT entry)", .{});
2562 const got_atom_index = self.got_table.getAtomIndex(self, target).?;
2563 try self.writePtrWidthAtom(got_atom_index);
2564 }
24792565 }
24802566 } else if (code_len < atom.size) {
24812567 self.shrinkAtom(atom_index, code_len);
24822568 } else if (atom.next_index == null) {
2483 const header = &self.sections.items(.header)[sect_id];
2484 const segment = self.getSegment(sect_id);
24852569 const needed_size = (sym.n_value + code_len) - segment.vmaddr;
24862570 header.size = needed_size;
24872571 }
24882572 self.getAtomPtr(atom_index).size = code_len;
24892573 } else {
2490 const name_str_index = try self.strtab.insert(gpa, sym_name);
24912574 const sym = atom.getSymbolPtr(self);
2492 sym.n_strx = name_str_index;
2575 sym.n_strx = try self.strtab.insert(gpa, sym_name);
24932576 sym.n_type = macho.N_SECT;
24942577 sym.n_sect = sect_id + 1;
24952578 sym.n_desc = 0;
......@@ -2503,7 +2586,12 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
25032586 self.getAtomPtr(atom_index).size = code_len;
25042587 sym.n_value = vaddr;
25052588
2506 try self.addGotEntry(.{ .sym_index = sym_index });
2589 const target: SymbolWithLoc = .{ .sym_index = sym_index };
2590 if (is_threadlocal) {
2591 try self.addTlvEntry(target);
2592 } else {
2593 try self.addGotEntry(target);
2594 }
25072595 }
25082596
25092597 try self.writeAtom(atom_index, code);
......@@ -2851,7 +2939,7 @@ fn populateMissingMetadata(self: *MachO) !void {
28512939 if (self.thread_vars_section_index == null) {
28522940 self.thread_vars_section_index = try self.allocateSection("__DATA3", "__thread_vars", .{
28532941 .size = @sizeOf(u64) * 3,
2854 .alignment = @alignOf(u64),
2942 .alignment = @sizeOf(u64),
28552943 .flags = macho.S_THREAD_LOCAL_VARIABLES,
28562944 .prot = macho.PROT.READ | macho.PROT.WRITE,
28572945 });
......@@ -3650,6 +3738,10 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
36503738 var header: macho.mach_header_64 = .{};
36513739 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
36523740
3741 if (!self.base.options.single_threaded) {
3742 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;
3743 }
3744
36533745 switch (self.base.options.target.cpu.arch) {
36543746 .aarch64 => {
36553747 header.cputype = macho.CPU_TYPE_ARM64;
......@@ -3674,12 +3766,6 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
36743766 else => unreachable,
36753767 }
36763768
3677 if (self.getSectionByName("__DATA", "__thread_vars")) |sect_id| {
3678 if (self.sections.items(.header)[sect_id].size > 0) {
3679 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;
3680 }
3681 }
3682
36833769 header.ncmds = ncmds;
36843770 header.sizeofcmds = sizeofcmds;
36853771
......@@ -3859,8 +3945,7 @@ pub fn getSymbol(self: *const MachO, sym_with_loc: SymbolWithLoc) macho.nlist_64
38593945
38603946/// Returns name of the symbol described by `sym_with_loc` descriptor.
38613947pub fn getSymbolName(self: *const MachO, sym_with_loc: SymbolWithLoc) []const u8 {
3862 assert(sym_with_loc.file == null);
3863 const sym = self.locals.items[sym_with_loc.sym_index];
3948 const sym = self.getSymbol(sym_with_loc);
38643949 return self.strtab.get(sym.n_strx).?;
38653950}
38663951
......@@ -4274,6 +4359,9 @@ pub fn logSymtab(self: *MachO) void {
42744359
42754360 log.debug("stubs entries:", .{});
42764361 log.debug("{}", .{self.stubs_table.fmtDebug(self)});
4362
4363 log.debug("threadlocal entries:", .{});
4364 log.debug("{}", .{self.tlvp_table.fmtDebug(self)});
42774365}
42784366
42794367pub fn logAtoms(self: *MachO) void {
src/link/MachO/Relocation.zig+14-3
......@@ -37,6 +37,8 @@ pub const Type = enum {
3737 branch,
3838 /// Absolute pointer value
3939 unsigned,
40 /// Relative offset to TLV initializer
41 tlv_initializer,
4042};
4143
4244/// Returns true if and only if the reloc is dirty AND the target address is available.
......@@ -65,7 +67,16 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
6567
6668 const target_atom_index = self.getTargetAtomIndex(macho_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().
6769 const target_atom = macho_file.getAtom(target_atom_index);
68 const target_addr = @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend;
70
71 const target_addr: i64 = switch (self.type) {
72 .tlv_initializer => blk: {
73 assert(self.addend == 0); // Addend here makes no sense.
74 const header = macho_file.sections.items(.header)[macho_file.thread_data_section_index.?];
75 const target_sym = target_atom.getSymbol(macho_file);
76 break :blk @intCast(i64, target_sym.n_value - header.addr);
77 },
78 else => @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend,
79 };
6980
7081 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
7182 source_addr,
......@@ -190,7 +201,7 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
190201 };
191202 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
192203 },
193 .unsigned => switch (self.length) {
204 .tlv_initializer, .unsigned => switch (self.length) {
194205 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))),
195206 3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)),
196207 else => unreachable,
......@@ -205,7 +216,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8
205216 const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4);
206217 mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));
207218 },
208 .unsigned => {
219 .tlv_initializer, .unsigned => {
209220 switch (self.length) {
210221 2 => {
211222 mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr)));