authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-12 10:43:42+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-13 11:47:51+02:00
log1f6165f6211885d3f5392cdfcc15f990284159de
treecd501801b1129835f9d0d0674aa9be7e837e917f
parent094ff60252cf57b2ae7bb69abb3e8e696873a3be

macho: reference TLV thunks via GOT table


2 files changed, 37 insertions(+), 113 deletions(-)

src/link/MachO.zig+28-62
...@@ -137,7 +137,6 @@ got_section_index: ?u8 = null,...@@ -137,7 +137,6 @@ got_section_index: ?u8 = null,
137data_const_section_index: ?u8 = null,137data_const_section_index: ?u8 = null,
138la_symbol_ptr_section_index: ?u8 = null,138la_symbol_ptr_section_index: ?u8 = null,
139data_section_index: ?u8 = null,139data_section_index: ?u8 = null,
140thread_ptr_section_index: ?u8 = null,
141thread_vars_section_index: ?u8 = null,140thread_vars_section_index: ?u8 = null,
142thread_data_section_index: ?u8 = null,141thread_data_section_index: ?u8 = null,
143142
...@@ -157,7 +156,7 @@ strtab: StringTable(.strtab) = .{},...@@ -157,7 +156,7 @@ strtab: StringTable(.strtab) = .{},
157156
158got_table: SectionTable = .{},157got_table: SectionTable = .{},
159stubs_table: SectionTable = .{},158stubs_table: SectionTable = .{},
160tlvp_table: SectionTable = .{},159tlv_table: SectionTable = .{},
161160
162error_flags: File.ErrorFlags = File.ErrorFlags{},161error_flags: File.ErrorFlags = File.ErrorFlags{},
163162
...@@ -1741,31 +1740,6 @@ fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.In...@@ -1741,31 +1740,6 @@ fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.In
1741 return atom_index;1740 return atom_index;
1742}1741}
17431742
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
1769fn createMhExecuteHeaderSymbol(self: *MachO) !void {1743fn createMhExecuteHeaderSymbol(self: *MachO) !void {
1770 if (self.base.options.output_mode != .Exe) return;1744 if (self.base.options.output_mode != .Exe) return;
1771 if (self.getGlobal("__mh_execute_header")) |global| {1745 if (self.getGlobal("__mh_execute_header")) |global| {
...@@ -1916,7 +1890,7 @@ pub fn deinit(self: *MachO) void {...@@ -1916,7 +1890,7 @@ pub fn deinit(self: *MachO) void {
19161890
1917 self.got_table.deinit(gpa);1891 self.got_table.deinit(gpa);
1918 self.stubs_table.deinit(gpa);1892 self.stubs_table.deinit(gpa);
1919 self.tlvp_table.deinit(gpa);1893 self.tlv_table.deinit(gpa);
1920 self.strtab.deinit(gpa);1894 self.strtab.deinit(gpa);
19211895
1922 self.locals.deinit(gpa);1896 self.locals.deinit(gpa);
...@@ -2150,13 +2124,11 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {...@@ -2150,13 +2124,11 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
2150}2124}
21512125
2152fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void {2126fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void {
2153 if (self.tlvp_table.lookup.contains(target)) return;2127 if (self.tlv_table.lookup.contains(target)) return;
2154 const tlvp_index = try self.tlvp_table.allocateEntry(self.base.allocator, target);2128 const tlv_index = try self.tlv_table.allocateEntry(self.base.allocator, target);
2155 const tlv_desc_atom_index = try self.createThreadLocalDescriptorAtom(target);2129 const tlv_atom_index = try self.createThreadLocalDescriptorAtom(target);
2156 const tlv_desc_atom = self.getAtom(tlv_desc_atom_index);2130 const tlv_atom = self.getAtom(tlv_atom_index);
2157 const tlv_ptr_atom_index = try self.createThreadLocalPointerAtom(tlv_desc_atom.getSymbolIndex().?);2131 self.tlv_table.entries.items[tlv_index].sym_index = tlv_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);2132 self.markRelocsDirtyByTarget(target);
2161}2133}
21622134
...@@ -2550,18 +2522,18 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64...@@ -2550,18 +2522,18 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
25502522
2551 if (vaddr != sym.n_value) {2523 if (vaddr != sym.n_value) {
2552 sym.n_value = vaddr;2524 sym.n_value = vaddr;
2553 const target = SymbolWithLoc{ .sym_index = sym_index };2525 // TODO: I think we should update the offset to the initializer here too.
2526 const target: SymbolWithLoc = if (is_threadlocal) blk: {
2527 const tlv_atom_index = self.tlv_table.getAtomIndex(self, .{
2528 .sym_index = sym_index,
2529 }).?;
2530 const tlv_atom = self.getAtom(tlv_atom_index);
2531 break :blk tlv_atom.getSymbolWithLoc();
2532 } else .{ .sym_index = sym_index };
2554 self.markRelocsDirtyByTarget(target);2533 self.markRelocsDirtyByTarget(target);
2555 if (is_threadlocal) {2534 log.debug(" (updating GOT entry)", .{});
2556 @panic("TODO update the threadlocal variable's name also");2535 const got_atom_index = self.got_table.getAtomIndex(self, target).?;
2557 // log.debug(" (updating threadlocal pointer entry)", .{});2536 try self.writePtrWidthAtom(got_atom_index);
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 }
2565 }2537 }
2566 } else if (code_len < atom.size) {2538 } else if (code_len < atom.size) {
2567 self.shrinkAtom(atom_index, code_len);2539 self.shrinkAtom(atom_index, code_len);
...@@ -2586,12 +2558,15 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64...@@ -2586,12 +2558,15 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
2586 self.getAtomPtr(atom_index).size = code_len;2558 self.getAtomPtr(atom_index).size = code_len;
2587 sym.n_value = vaddr;2559 sym.n_value = vaddr;
25882560
2589 const target: SymbolWithLoc = .{ .sym_index = sym_index };
2590 if (is_threadlocal) {2561 if (is_threadlocal) {
2591 try self.addTlvEntry(target);2562 try self.addTlvEntry(.{ .sym_index = sym_index });
2592 } else {
2593 try self.addGotEntry(target);
2594 }2563 }
2564 const target: SymbolWithLoc = if (is_threadlocal) blk: {
2565 const tlv_atom_index = self.tlv_table.getAtomIndex(self, .{ .sym_index = sym_index }).?;
2566 const tlv_atom = self.getAtom(tlv_atom_index);
2567 break :blk tlv_atom.getSymbolWithLoc();
2568 } else .{ .sym_index = sym_index };
2569 try self.addGotEntry(target);
2595 }2570 }
25962571
2597 try self.writeAtom(atom_index, code);2572 try self.writeAtom(atom_index, code);
...@@ -2927,17 +2902,8 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -2927,17 +2902,8 @@ fn populateMissingMetadata(self: *MachO) !void {
2927 }2902 }
29282903
2929 if (!self.base.options.single_threaded) {2904 if (!self.base.options.single_threaded) {
2930 if (self.thread_ptr_section_index == null) {
2931 self.thread_ptr_section_index = try self.allocateSection("__DATA2", "__thread_ptrs", .{
2932 .size = @sizeOf(u64),
2933 .alignment = @alignOf(u64),
2934 .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
2935 .prot = macho.PROT.READ | macho.PROT.WRITE,
2936 });
2937 self.segment_table_dirty = true;
2938 }
2939 if (self.thread_vars_section_index == null) {2905 if (self.thread_vars_section_index == null) {
2940 self.thread_vars_section_index = try self.allocateSection("__DATA3", "__thread_vars", .{2906 self.thread_vars_section_index = try self.allocateSection("__DATA2", "__thread_vars", .{
2941 .size = @sizeOf(u64) * 3,2907 .size = @sizeOf(u64) * 3,
2942 .alignment = @sizeOf(u64),2908 .alignment = @sizeOf(u64),
2943 .flags = macho.S_THREAD_LOCAL_VARIABLES,2909 .flags = macho.S_THREAD_LOCAL_VARIABLES,
...@@ -2947,7 +2913,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -2947,7 +2913,7 @@ fn populateMissingMetadata(self: *MachO) !void {
2947 }2913 }
29482914
2949 if (self.thread_data_section_index == null) {2915 if (self.thread_data_section_index == null) {
2950 self.thread_data_section_index = try self.allocateSection("__DATA4", "__thread_data", .{2916 self.thread_data_section_index = try self.allocateSection("__DATA3", "__thread_data", .{
2951 .size = @sizeOf(u64),2917 .size = @sizeOf(u64),
2952 .alignment = @alignOf(u64),2918 .alignment = @alignOf(u64),
2953 .flags = macho.S_THREAD_LOCAL_REGULAR,2919 .flags = macho.S_THREAD_LOCAL_REGULAR,
...@@ -4361,7 +4327,7 @@ pub fn logSymtab(self: *MachO) void {...@@ -4361,7 +4327,7 @@ pub fn logSymtab(self: *MachO) void {
4361 log.debug("{}", .{self.stubs_table.fmtDebug(self)});4327 log.debug("{}", .{self.stubs_table.fmtDebug(self)});
43624328
4363 log.debug("threadlocal entries:", .{});4329 log.debug("threadlocal entries:", .{});
4364 log.debug("{}", .{self.tlvp_table.fmtDebug(self)});4330 log.debug("{}", .{self.tlv_table.fmtDebug(self)});
4365}4331}
43664332
4367pub fn logAtoms(self: *MachO) void {4333pub fn logAtoms(self: *MachO) void {
src/link/MachO/Relocation.zig+9-51
...@@ -15,7 +15,7 @@ pub const Type = enum {...@@ -15,7 +15,7 @@ pub const Type = enum {
15 got,15 got,
16 /// RIP-relative displacement16 /// RIP-relative displacement
17 signed,17 signed,
18 /// RIP-relative displacemen to threadlocal variable descriptor18 /// RIP-relative displacement to GOT pointer to TLV thunk
19 tlv,19 tlv,
2020
21 // aarch6421 // aarch64
...@@ -27,10 +27,6 @@ pub const Type = enum {...@@ -27,10 +27,6 @@ pub const Type = enum {
27 page,27 page,
28 /// Offset to a pointer relative to the start of a page in a section28 /// Offset to a pointer relative to the start of a page in a section
29 pageoff,29 pageoff,
30 /// PC-relative distance to target page in TLV section
31 tlv_page,
32 /// Offset to a pointer relative to the start of a page in TLV section
33 tlv_pageoff,
3430
35 // common31 // common
36 /// PC/RIP-relative displacement B/BL/CALL32 /// PC/RIP-relative displacement B/BL/CALL
...@@ -50,7 +46,12 @@ pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {...@@ -50,7 +46,12 @@ pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
50pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {46pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
51 return switch (self.type) {47 return switch (self.type) {
52 .got, .got_page, .got_pageoff => macho_file.got_table.getAtomIndex(macho_file, self.target),48 .got, .got_page, .got_pageoff => macho_file.got_table.getAtomIndex(macho_file, self.target),
53 .tlv, .tlv_page, .tlv_pageoff => macho_file.tlvp_table.getAtomIndex(macho_file, self.target),49 .tlv => {
50 const thunk_atom_index = macho_file.tlv_table.getAtomIndex(macho_file, self.target) orelse
51 return null;
52 const thunk_atom = macho_file.getAtom(thunk_atom_index);
53 return macho_file.got_table.getAtomIndex(macho_file, thunk_atom.getSymbolWithLoc());
54 },
54 .branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index|55 .branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index|
55 index56 index
56 else57 else
...@@ -109,7 +110,7 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -109,7 +110,7 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
109 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));110 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
110 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());111 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
111 },112 },
112 .page, .got_page, .tlv_page => {113 .page, .got_page => {
113 const source_page = @intCast(i32, source_addr >> 12);114 const source_page = @intCast(i32, source_addr >> 12);
114 const target_page = @intCast(i32, target_addr >> 12);115 const target_page = @intCast(i32, target_addr >> 12);
115 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));116 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
...@@ -158,49 +159,6 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -158,49 +159,6 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
158 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());159 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
159 }160 }
160 },161 },
161 .tlv_pageoff => {
162 const RegInfo = struct {
163 rd: u5,
164 rn: u5,
165 size: u2,
166 };
167 const reg_info: RegInfo = blk: {
168 if (isArithmeticOp(buffer[0..4])) {
169 const inst = mem.bytesToValue(meta.TagPayload(
170 aarch64.Instruction,
171 aarch64.Instruction.add_subtract_immediate,
172 ), buffer[0..4]);
173 break :blk .{
174 .rd = inst.rd,
175 .rn = inst.rn,
176 .size = inst.sf,
177 };
178 } else {
179 const inst = mem.bytesToValue(meta.TagPayload(
180 aarch64.Instruction,
181 aarch64.Instruction.load_store_register,
182 ), buffer[0..4]);
183 break :blk .{
184 .rd = inst.rt,
185 .rn = inst.rn,
186 .size = inst.size,
187 };
188 }
189 };
190 const narrowed = @truncate(u12, @intCast(u64, target_addr));
191 var inst = aarch64.Instruction{
192 .add_subtract_immediate = .{
193 .rd = reg_info.rd,
194 .rn = reg_info.rn,
195 .imm12 = narrowed,
196 .sh = 0,
197 .s = 0,
198 .op = 0,
199 .sf = @truncate(u1, reg_info.size),
200 },
201 };
202 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
203 },
204 .tlv_initializer, .unsigned => switch (self.length) {162 .tlv_initializer, .unsigned => switch (self.length) {
205 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))),163 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))),
206 3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)),164 3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)),
...@@ -227,7 +185,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8...@@ -227,7 +185,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8
227 else => unreachable,185 else => unreachable,
228 }186 }
229 },187 },
230 .got_page, .got_pageoff, .page, .pageoff, .tlv_page, .tlv_pageoff => unreachable, // Invalid target architecture.188 .got_page, .got_pageoff, .page, .pageoff => unreachable, // Invalid target architecture.
231 }189 }
232}190}
233191