authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-09 18:42:00+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-17 19:59:13+01:00
logde209afbba0984c66fc5c9d379192edec87f0681
treee0ec7334305776c4cb512d6c675b3a7765e482b4
parent349f878ecf0b6ad5eee6b1cdfdba90014cbcb619

zld: fix TLV initializers


1 files changed, 88 insertions(+), 27 deletions(-)

src/link/MachO/Zld.zig+88-27
......@@ -74,7 +74,8 @@ locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{},
7474exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{},
7575nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
7676lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
77threadlocal_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
77tlv_bootstrap: ?Import = null,
78threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
7879local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
7980
8081strtab: std.ArrayListUnmanaged(u8) = .{},
......@@ -202,16 +203,13 @@ pub fn init(allocator: *Allocator) Zld {
202203}
203204
204205pub fn deinit(self: *Zld) void {
206 self.threadlocal_offsets.deinit(self.allocator);
205207 self.strtab.deinit(self.allocator);
206208 self.local_rebases.deinit(self.allocator);
207209 for (self.lazy_imports.items()) |*entry| {
208210 self.allocator.free(entry.key);
209211 }
210212 self.lazy_imports.deinit(self.allocator);
211 for (self.threadlocal_imports.items()) |*entry| {
212 self.allocator.free(entry.key);
213 }
214 self.threadlocal_imports.deinit(self.allocator);
215213 for (self.nonlazy_imports.items()) |*entry| {
216214 self.allocator.free(entry.key);
217215 }
......@@ -780,12 +778,11 @@ fn resolveImports(self: *Zld) !void {
780778 });
781779 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
782780 log.debug("writing threadlocal symbol '{s}'", .{sym_name});
783 const index = @intCast(u32, self.threadlocal_imports.items().len);
784 try self.threadlocal_imports.putNoClobber(self.allocator, key, .{
781 self.tlv_bootstrap = .{
785782 .symbol = new_sym,
786783 .dylib_ordinal = dylib_ordinal,
787 .index = index,
788 });
784 .index = 0,
785 };
789786 } else {
790787 log.debug("writing lazy symbol '{s}'", .{sym_name});
791788 const index = @intCast(u32, self.lazy_imports.items().len);
......@@ -1463,7 +1460,7 @@ fn doRelocs(self: *Zld) !void {
14631460 mem.writeIntLittle(u64, inst, @bitCast(u64, result));
14641461 sub = null;
14651462
1466 outer: {
1463 rebases: {
14671464 var hit: bool = false;
14681465 if (target_mapping.target_seg_id == self.data_segment_cmd_index.?) {
14691466 if (self.data_section_index) |index| {
......@@ -1476,13 +1473,33 @@ fn doRelocs(self: *Zld) !void {
14761473 }
14771474 }
14781475
1479 if (!hit) break :outer;
1476 if (!hit) break :rebases;
14801477
14811478 try self.local_rebases.append(self.allocator, .{
14821479 .offset = this_addr - target_seg.inner.vmaddr,
14831480 .segment_id = target_mapping.target_seg_id,
14841481 });
14851482 }
1483 // TLV is handled via a separate offset mechanism.
1484 // Calculate the offset to the initializer.
1485 if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
1486 assert(rel.r_extern == 1);
1487 const sym = object.symtab.items[rel.r_symbolnum];
1488 if (isImport(&sym)) break :tlv;
1489
1490 const base_addr = blk: {
1491 if (self.tlv_data_section_index) |index| {
1492 const tlv_data = target_seg.sections.items[index];
1493 break :blk tlv_data.addr;
1494 } else {
1495 const tlv_bss = target_seg.sections.items[self.tlv_bss_section_index.?];
1496 break :blk tlv_bss.addr;
1497 }
1498 };
1499 // Since we require TLV data to always preceed TLV bss section, we calculate
1500 // offsets wrt to the former if it is defined; otherwise, wrt to the latter.
1501 try self.threadlocal_offsets.append(self.allocator, target_addr - base_addr);
1502 }
14861503 },
14871504 2 => {
14881505 const inst = code[off..][0..4];
......@@ -1646,7 +1663,7 @@ fn doRelocs(self: *Zld) !void {
16461663 mem.writeIntLittle(u64, inst, @bitCast(u64, result));
16471664 sub = null;
16481665
1649 outer: {
1666 rebases: {
16501667 var hit: bool = false;
16511668 if (target_mapping.target_seg_id == self.data_segment_cmd_index.?) {
16521669 if (self.data_section_index) |index| {
......@@ -1659,13 +1676,33 @@ fn doRelocs(self: *Zld) !void {
16591676 }
16601677 }
16611678
1662 if (!hit) break :outer;
1679 if (!hit) break :rebases;
16631680
16641681 try self.local_rebases.append(self.allocator, .{
16651682 .offset = this_addr - target_seg.inner.vmaddr,
16661683 .segment_id = target_mapping.target_seg_id,
16671684 });
16681685 }
1686 // TLV is handled via a separate offset mechanism.
1687 // Calculate the offset to the initializer.
1688 if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
1689 assert(rel.r_extern == 1);
1690 const sym = object.symtab.items[rel.r_symbolnum];
1691 if (isImport(&sym)) break :tlv;
1692
1693 const base_addr = blk: {
1694 if (self.tlv_data_section_index) |index| {
1695 const tlv_data = target_seg.sections.items[index];
1696 break :blk tlv_data.addr;
1697 } else {
1698 const tlv_bss = target_seg.sections.items[self.tlv_bss_section_index.?];
1699 break :blk tlv_bss.addr;
1700 }
1701 };
1702 // Since we require TLV data to always preceed TLV bss section, we calculate
1703 // offsets wrt to the former if it is defined; otherwise, wrt to the latter.
1704 try self.threadlocal_offsets.append(self.allocator, target_addr - base_addr);
1705 }
16691706 },
16701707 2 => {
16711708 const inst = code[off..][0..4];
......@@ -1771,10 +1808,10 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
17711808 const segment = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
17721809 const got = segment.sections.items[self.got_section_index.?];
17731810 break :blk got.addr + ext.index * @sizeOf(u64);
1774 } else if (self.threadlocal_imports.get(sym_name)) |ext| {
1811 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
17751812 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
17761813 const tlv = segment.sections.items[self.tlv_section_index.?];
1777 break :blk tlv.addr + ext.index * @sizeOf(u64);
1814 break :blk tlv.addr + self.tlv_bootstrap.?.index * @sizeOf(u64);
17781815 } else {
17791816 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
17801817 return error.FailedToResolveRelocationTarget;
......@@ -2207,11 +2244,33 @@ fn flush(self: *Zld) !void {
22072244 const sect = &seg.sections.items[index];
22082245 sect.offset = 0;
22092246 }
2247
22102248 if (self.tlv_bss_section_index) |index| {
22112249 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
22122250 const sect = &seg.sections.items[index];
22132251 sect.offset = 0;
22142252 }
2253
2254 if (self.tlv_section_index) |index| {
2255 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2256 const sect = &seg.sections.items[index];
2257
2258 var buffer = try self.allocator.alloc(u8, sect.size);
2259 defer self.allocator.free(buffer);
2260 _ = try self.file.?.preadAll(buffer, sect.offset);
2261
2262 var stream = std.io.fixedBufferStream(buffer);
2263 var writer = stream.writer();
2264
2265 const seek_amt = 2 * @sizeOf(u64);
2266 while (self.threadlocal_offsets.popOrNull()) |offset| {
2267 try writer.context.seekBy(seek_amt);
2268 try writer.writeIntLittle(u64, offset);
2269 }
2270
2271 try self.file.?.pwriteAll(buffer, sect.offset);
2272 }
2273
22152274 try self.setEntryPoint();
22162275 try self.writeRebaseInfoTable();
22172276 try self.writeBindInfoTable();
......@@ -2344,9 +2403,9 @@ fn pointerCmp(context: void, a: Pointer, b: Pointer) bool {
23442403fn writeBindInfoTable(self: *Zld) !void {
23452404 var pointers = std.ArrayList(Pointer).init(self.allocator);
23462405 defer pointers.deinit();
2347 try pointers.ensureCapacity(self.nonlazy_imports.items().len + self.threadlocal_imports.items().len);
23482406
23492407 if (self.got_section_index) |idx| {
2408 try pointers.ensureCapacity(pointers.items.len + self.nonlazy_imports.items().len);
23502409 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
23512410 const sect = seg.sections.items[idx];
23522411 const base_offset = sect.addr - seg.inner.vmaddr;
......@@ -2366,14 +2425,12 @@ fn writeBindInfoTable(self: *Zld) !void {
23662425 const sect = seg.sections.items[idx];
23672426 const base_offset = sect.addr - seg.inner.vmaddr;
23682427 const segment_id = @intCast(u16, self.data_segment_cmd_index.?);
2369 for (self.threadlocal_imports.items()) |entry| {
2370 pointers.appendAssumeCapacity(.{
2371 .offset = base_offset + entry.value.index * @sizeOf(u64),
2372 .segment_id = segment_id,
2373 .dylib_ordinal = entry.value.dylib_ordinal,
2374 .name = entry.key,
2375 });
2376 }
2428 try pointers.append(.{
2429 .offset = base_offset + self.tlv_bootstrap.?.index * @sizeOf(u64),
2430 .segment_id = segment_id,
2431 .dylib_ordinal = self.tlv_bootstrap.?.dylib_ordinal,
2432 .name = "__tlv_bootstrap",
2433 });
23772434 }
23782435
23792436 const size = try bindInfoSize(pointers.items);
......@@ -2701,7 +2758,11 @@ fn writeSymbolTable(self: *Zld) !void {
27012758 exports.appendAssumeCapacity(entry.value);
27022759 }
27032760
2704 const nundefs = self.lazy_imports.items().len + self.nonlazy_imports.items().len + self.threadlocal_imports.items().len;
2761 const has_tlv: bool = self.tlv_bootstrap != null;
2762
2763 var nundefs = self.lazy_imports.items().len + self.nonlazy_imports.items().len;
2764 if (has_tlv) nundefs += 1;
2765
27052766 var undefs = std.ArrayList(macho.nlist_64).init(self.allocator);
27062767 defer undefs.deinit();
27072768
......@@ -2712,8 +2773,8 @@ fn writeSymbolTable(self: *Zld) !void {
27122773 for (self.nonlazy_imports.items()) |entry| {
27132774 undefs.appendAssumeCapacity(entry.value.symbol);
27142775 }
2715 for (self.threadlocal_imports.items()) |entry| {
2716 undefs.appendAssumeCapacity(entry.value.symbol);
2776 if (has_tlv) {
2777 undefs.appendAssumeCapacity(self.tlv_bootstrap.?.symbol);
27172778 }
27182779
27192780 const locals_off = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64);