authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-10 14:07:56+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
logdd5c7588d105c544289b6344b652133538e7e898
tree5201e724d6a742c08871015301294894d08febf6
parent322be2698d78836e94b54da959eb28476530b822

zld: fix resolving TLV offset relocations


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

src/link/MachO/Zld.zig+1-50
......@@ -131,7 +131,6 @@ pub const TextBlock = struct {
131131 size: u64,
132132 alignment: u32,
133133 rebases: std.ArrayList(u64),
134 tlv_offsets: std.ArrayList(TlvOffset),
135134 next: ?*TextBlock = null,
136135 prev: ?*TextBlock = null,
137136
......@@ -140,11 +139,6 @@ pub const TextBlock = struct {
140139 offset: u64,
141140 };
142141
143 pub const TlvOffset = struct {
144 local_sym_index: u32,
145 offset: u64,
146 };
147
148142 pub fn init(allocator: *Allocator) TextBlock {
149143 return .{
150144 .allocator = allocator,
......@@ -155,7 +149,6 @@ pub const TextBlock = struct {
155149 .size = undefined,
156150 .alignment = undefined,
157151 .rebases = std.ArrayList(u64).init(allocator),
158 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(allocator),
159152 };
160153 }
161154
......@@ -170,7 +163,6 @@ pub const TextBlock = struct {
170163 self.allocator.free(self.code);
171164 self.relocs.deinit();
172165 self.rebases.deinit();
173 self.tlv_offsets.deinit();
174166 }
175167
176168 pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
......@@ -210,9 +202,6 @@ pub const TextBlock = struct {
210202 if (self.rebases.items.len > 0) {
211203 log.warn(" | rebases: {any}", .{self.rebases.items});
212204 }
213 if (self.tlv_offsets.items.len > 0) {
214 log.warn(" | TLV offsets: {any}", .{self.tlv_offsets.items});
215 }
216205 log.warn(" | size = {}", .{self.size});
217206 log.warn(" | align = {}", .{self.alignment});
218207 }
......@@ -1120,10 +1109,7 @@ fn writeTextBlocks(self: *Zld) !void {
11201109 var code = try self.allocator.alloc(u8, sect.size);
11211110 defer self.allocator.free(code);
11221111
1123 if (sect_type == macho.S_ZEROFILL or
1124 sect_type == macho.S_THREAD_LOCAL_ZEROFILL or
1125 sect_type == macho.S_THREAD_LOCAL_VARIABLES)
1126 {
1112 if (sect_type == macho.S_ZEROFILL or sect_type == macho.S_THREAD_LOCAL_ZEROFILL) {
11271113 mem.set(u8, code, 0);
11281114 } else {
11291115 var base_off: u64 = sect.size;
......@@ -2051,41 +2037,6 @@ fn flush(self: *Zld) !void {
20512037 sect.offset = 0;
20522038 }
20532039
2054 if (self.tlv_section_index) |index| {
2055 // TODO this should be part of relocation resolution routine.
2056 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2057 const sect = &seg.sections.items[index];
2058
2059 const base_addr = if (self.tlv_data_section_index) |i|
2060 seg.sections.items[i].addr
2061 else
2062 seg.sections.items[self.tlv_bss_section_index.?].addr;
2063
2064 var block: *TextBlock = self.blocks.get(.{
2065 .seg = self.data_segment_cmd_index.?,
2066 .sect = index,
2067 }) orelse unreachable;
2068
2069 var buffer = try self.allocator.alloc(u8, @intCast(usize, sect.size));
2070 defer self.allocator.free(buffer);
2071 _ = try self.file.?.preadAll(buffer, sect.offset);
2072
2073 while (true) {
2074 for (block.tlv_offsets.items) |tlv_offset| {
2075 const sym = self.locals.items[tlv_offset.local_sym_index];
2076 assert(sym.payload == .regular);
2077 const offset = sym.payload.regular.address - base_addr;
2078 mem.writeIntLittle(u64, buffer[tlv_offset.offset..][0..@sizeOf(u64)], offset);
2079 }
2080
2081 if (block.prev) |prev| {
2082 block = prev;
2083 } else break;
2084 }
2085
2086 try self.file.?.pwriteAll(buffer, sect.offset);
2087 }
2088
20892040 try self.writeGotEntries();
20902041 try self.setEntryPoint();
20912042 try self.writeRebaseInfoTable();
src/link/MachO/reloc.zig+36-13
......@@ -50,7 +50,7 @@ pub const Relocation = struct {
5050
5151 source_sect_addr: ?u64 = null,
5252
53 pub fn resolve(self: Unsigned, base: Relocation, source_addr: u64, target_addr: u64) !void {
53 pub fn resolve(self: Unsigned, base: Relocation, _: u64, target_addr: u64) !void {
5454 const addend = if (self.source_sect_addr) |addr|
5555 self.addend - @intCast(i64, addr)
5656 else
......@@ -430,12 +430,43 @@ pub const Relocation = struct {
430430 }
431431
432432 switch (self.target.payload) {
433 .regular => |reg| break :blk reg.address,
433 .regular => |reg| {
434 const is_tlv = is_tlv: {
435 const sym = zld.locals.items[self.block.local_sym_index];
436 const seg = zld.load_commands.items[sym.payload.regular.segment_id].Segment;
437 const sect = seg.sections.items[sym.payload.regular.section_id];
438 break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
439 };
440 if (is_tlv) {
441 // For TLV relocations, the value specified as a relocation is the displacement from the
442 // TLV initializer (either value in __thread_data or zero-init in __thread_bss) to the first
443 // defined TLV template init section in the following order:
444 // * wrt to __thread_data if defined, then
445 // * wrt to __thread_bss
446 const seg = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;
447 const base_address = inner: {
448 if (zld.tlv_data_section_index) |i| {
449 break :inner seg.sections.items[i].addr;
450 } else if (zld.tlv_bss_section_index) |i| {
451 break :inner seg.sections.items[i].addr;
452 } else {
453 log.err("threadlocal variables present but no initializer sections found", .{});
454 log.err(" __thread_data not found", .{});
455 log.err(" __thread_bss not found", .{});
456 return error.FailedToResolveRelocationTarget;
457 }
458 };
459 break :blk reg.address - base_address;
460 }
461
462 break :blk reg.address;
463 },
434464 .proxy => |proxy| {
435465 if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) {
436 const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;
437 const tlv = segment.sections.items[zld.tlv_section_index.?];
438 break :blk tlv.addr;
466 break :blk 0; // Dynamically bound by dyld.
467 // const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;
468 // const tlv = segment.sections.items[zld.tlv_section_index.?];
469 // break :blk tlv.addr;
439470 }
440471
441472 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
......@@ -677,14 +708,6 @@ pub const Parser = struct {
677708 if (should_rebase) {
678709 try self.block.rebases.append(out_rel.offset);
679710 }
680
681 // TLV is handled via a separate offset mechanism.
682 if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) {
683 try self.block.tlv_offsets.append(.{
684 .local_sym_index = out_rel.target.payload.regular.local_sym_index,
685 .offset = out_rel.offset,
686 });
687 }
688711 },
689712 }
690713 } else if (out_rel.payload == .branch) blk: {