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 {...@@ -131,7 +131,6 @@ pub const TextBlock = struct {
131 size: u64,131 size: u64,
132 alignment: u32,132 alignment: u32,
133 rebases: std.ArrayList(u64),133 rebases: std.ArrayList(u64),
134 tlv_offsets: std.ArrayList(TlvOffset),
135 next: ?*TextBlock = null,134 next: ?*TextBlock = null,
136 prev: ?*TextBlock = null,135 prev: ?*TextBlock = null,
137136
...@@ -140,11 +139,6 @@ pub const TextBlock = struct {...@@ -140,11 +139,6 @@ pub const TextBlock = struct {
140 offset: u64,139 offset: u64,
141 };140 };
142141
143 pub const TlvOffset = struct {
144 local_sym_index: u32,
145 offset: u64,
146 };
147
148 pub fn init(allocator: *Allocator) TextBlock {142 pub fn init(allocator: *Allocator) TextBlock {
149 return .{143 return .{
150 .allocator = allocator,144 .allocator = allocator,
...@@ -155,7 +149,6 @@ pub const TextBlock = struct {...@@ -155,7 +149,6 @@ pub const TextBlock = struct {
155 .size = undefined,149 .size = undefined,
156 .alignment = undefined,150 .alignment = undefined,
157 .rebases = std.ArrayList(u64).init(allocator),151 .rebases = std.ArrayList(u64).init(allocator),
158 .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(allocator),
159 };152 };
160 }153 }
161154
...@@ -170,7 +163,6 @@ pub const TextBlock = struct {...@@ -170,7 +163,6 @@ pub const TextBlock = struct {
170 self.allocator.free(self.code);163 self.allocator.free(self.code);
171 self.relocs.deinit();164 self.relocs.deinit();
172 self.rebases.deinit();165 self.rebases.deinit();
173 self.tlv_offsets.deinit();
174 }166 }
175167
176 pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {168 pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
...@@ -210,9 +202,6 @@ pub const TextBlock = struct {...@@ -210,9 +202,6 @@ pub const TextBlock = struct {
210 if (self.rebases.items.len > 0) {202 if (self.rebases.items.len > 0) {
211 log.warn(" | rebases: {any}", .{self.rebases.items});203 log.warn(" | rebases: {any}", .{self.rebases.items});
212 }204 }
213 if (self.tlv_offsets.items.len > 0) {
214 log.warn(" | TLV offsets: {any}", .{self.tlv_offsets.items});
215 }
216 log.warn(" | size = {}", .{self.size});205 log.warn(" | size = {}", .{self.size});
217 log.warn(" | align = {}", .{self.alignment});206 log.warn(" | align = {}", .{self.alignment});
218 }207 }
...@@ -1120,10 +1109,7 @@ fn writeTextBlocks(self: *Zld) !void {...@@ -1120,10 +1109,7 @@ fn writeTextBlocks(self: *Zld) !void {
1120 var code = try self.allocator.alloc(u8, sect.size);1109 var code = try self.allocator.alloc(u8, sect.size);
1121 defer self.allocator.free(code);1110 defer self.allocator.free(code);
11221111
1123 if (sect_type == macho.S_ZEROFILL or1112 if (sect_type == macho.S_ZEROFILL or sect_type == macho.S_THREAD_LOCAL_ZEROFILL) {
1124 sect_type == macho.S_THREAD_LOCAL_ZEROFILL or
1125 sect_type == macho.S_THREAD_LOCAL_VARIABLES)
1126 {
1127 mem.set(u8, code, 0);1113 mem.set(u8, code, 0);
1128 } else {1114 } else {
1129 var base_off: u64 = sect.size;1115 var base_off: u64 = sect.size;
...@@ -2051,41 +2037,6 @@ fn flush(self: *Zld) !void {...@@ -2051,41 +2037,6 @@ fn flush(self: *Zld) !void {
2051 sect.offset = 0;2037 sect.offset = 0;
2052 }2038 }
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
2089 try self.writeGotEntries();2040 try self.writeGotEntries();
2090 try self.setEntryPoint();2041 try self.setEntryPoint();
2091 try self.writeRebaseInfoTable();2042 try self.writeRebaseInfoTable();
src/link/MachO/reloc.zig+36-13
...@@ -50,7 +50,7 @@ pub const Relocation = struct {...@@ -50,7 +50,7 @@ pub const Relocation = struct {
5050
51 source_sect_addr: ?u64 = null,51 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 {
54 const addend = if (self.source_sect_addr) |addr|54 const addend = if (self.source_sect_addr) |addr|
55 self.addend - @intCast(i64, addr)55 self.addend - @intCast(i64, addr)
56 else56 else
...@@ -430,12 +430,43 @@ pub const Relocation = struct {...@@ -430,12 +430,43 @@ pub const Relocation = struct {
430 }430 }
431431
432 switch (self.target.payload) {432 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 },
434 .proxy => |proxy| {464 .proxy => |proxy| {
435 if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) {465 if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) {
436 const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;466 break :blk 0; // Dynamically bound by dyld.
437 const tlv = segment.sections.items[zld.tlv_section_index.?];467 // const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;
438 break :blk tlv.addr;468 // const tlv = segment.sections.items[zld.tlv_section_index.?];
469 // break :blk tlv.addr;
439 }470 }
440471
441 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;472 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
...@@ -677,14 +708,6 @@ pub const Parser = struct {...@@ -677,14 +708,6 @@ pub const Parser = struct {
677 if (should_rebase) {708 if (should_rebase) {
678 try self.block.rebases.append(out_rel.offset);709 try self.block.rebases.append(out_rel.offset);
679 }710 }
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 }
688 },711 },
689 }712 }
690 } else if (out_rel.payload == .branch) blk: {713 } else if (out_rel.payload == .branch) blk: {