authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:25:10+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
logc47ce310716de806b3d95c328a9c2f9735221806
treed671bf86a46084c5068933fd9fbe8b10d9b173ae
parentf8678c48ff43879d043b626031f7a5c92303fdea

zld: thin out Relocation by not storing *TextBlock

this way we shave off 8 bytes per Relocation structure, and instead we can pass the *TextBlock as args to resolve function.

2 files changed, 178 insertions(+), 181 deletions(-)

src/link/MachO/Zld.zig+85-1
...@@ -246,7 +246,91 @@ pub const TextBlock = struct {...@@ -246,7 +246,91 @@ pub const TextBlock = struct {
246246
247 pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {247 pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
248 for (self.relocs.items) |rel| {248 for (self.relocs.items) |rel| {
249 try rel.resolve(zld);249 log.debug("relocating {}", .{rel});
250
251 const source_addr = blk: {
252 const sym = zld.locals.items[self.local_sym_index];
253 break :blk sym.payload.regular.address + rel.offset;
254 };
255 const target_addr = blk: {
256 const is_via_got = switch (rel.payload) {
257 .pointer_to_got => true,
258 .page => |page| page.kind == .got,
259 .page_off => |page_off| page_off.kind == .got,
260 .load => |load| load.kind == .got,
261 else => false,
262 };
263
264 if (is_via_got) {
265 const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;
266 const got = dc_seg.sections.items[zld.got_section_index.?];
267 const got_index = rel.target.got_index orelse {
268 log.err("expected GOT entry for symbol '{s}'", .{zld.getString(rel.target.strx)});
269 log.err(" this is an internal linker error", .{});
270 return error.FailedToResolveRelocationTarget;
271 };
272 break :blk got.addr + got_index * @sizeOf(u64);
273 }
274
275 switch (rel.target.payload) {
276 .regular => |reg| {
277 const is_tlv = is_tlv: {
278 const sym = zld.locals.items[self.local_sym_index];
279 const seg = zld.load_commands.items[sym.payload.regular.segment_id].Segment;
280 const sect = seg.sections.items[sym.payload.regular.section_id];
281 break :is_tlv sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
282 };
283 if (is_tlv) {
284 // For TLV relocations, the value specified as a relocation is the displacement from the
285 // TLV initializer (either value in __thread_data or zero-init in __thread_bss) to the first
286 // defined TLV template init section in the following order:
287 // * wrt to __thread_data if defined, then
288 // * wrt to __thread_bss
289 const seg = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;
290 const base_address = inner: {
291 if (zld.tlv_data_section_index) |i| {
292 break :inner seg.sections.items[i].addr;
293 } else if (zld.tlv_bss_section_index) |i| {
294 break :inner seg.sections.items[i].addr;
295 } else {
296 log.err("threadlocal variables present but no initializer sections found", .{});
297 log.err(" __thread_data not found", .{});
298 log.err(" __thread_bss not found", .{});
299 return error.FailedToResolveRelocationTarget;
300 }
301 };
302 break :blk reg.address - base_address;
303 }
304
305 break :blk reg.address;
306 },
307 .proxy => {
308 if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) {
309 break :blk 0; // Dynamically bound by dyld.
310 }
311
312 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
313 const stubs = segment.sections.items[zld.stubs_section_index.?];
314 const stubs_index = rel.target.stubs_index orelse {
315 // TODO verify in TextBlock that the symbol is indeed dynamically bound.
316 break :blk 0; // Dynamically bound by dyld.
317 };
318 break :blk stubs.addr + stubs_index * stubs.reserved2;
319 },
320 else => {
321 log.err("failed to resolve symbol '{s}' as a relocation target", .{
322 zld.getString(rel.target.strx),
323 });
324 log.err(" this is an internal linker error", .{});
325 return error.FailedToResolveRelocationTarget;
326 },
327 }
328 };
329
330 log.debug(" | source_addr = 0x{x}", .{source_addr});
331 log.debug(" | target_addr = 0x{x}", .{target_addr});
332
333 try rel.resolve(self, source_addr, target_addr);
250 }334 }
251 }335 }
252336
src/link/MachO/reloc.zig+93-180
...@@ -20,9 +20,6 @@ pub const Relocation = struct {...@@ -20,9 +20,6 @@ pub const Relocation = struct {
20 /// Note relocation size can be inferred by relocation's kind.20 /// Note relocation size can be inferred by relocation's kind.
21 offset: u32,21 offset: u32,
2222
23 /// Parent block containing this relocation.
24 block: *TextBlock,
25
26 /// Target symbol: either a regular or a proxy.23 /// Target symbol: either a regular or a proxy.
27 target: *Symbol,24 target: *Symbol,
2825
...@@ -36,6 +33,13 @@ pub const Relocation = struct {...@@ -36,6 +33,13 @@ pub const Relocation = struct {
36 load: Load,33 load: Load,
37 },34 },
3835
36 const ResolveArgs = struct {
37 block: *TextBlock,
38 offset: u32,
39 source_addr: u64,
40 target_addr: u64,
41 };
42
39 pub const Unsigned = struct {43 pub const Unsigned = struct {
40 subtractor: ?*Symbol = null,44 subtractor: ?*Symbol = null,
4145
...@@ -48,16 +52,16 @@ pub const Relocation = struct {...@@ -48,16 +52,16 @@ pub const Relocation = struct {
48 /// => * is unreachable52 /// => * is unreachable
49 is_64bit: bool,53 is_64bit: bool,
5054
51 pub fn resolve(self: Unsigned, base: Relocation, _: u64, target_addr: u64) !void {55 pub fn resolve(self: Unsigned, args: ResolveArgs) !void {
52 const result = if (self.subtractor) |subtractor|56 const result = if (self.subtractor) |subtractor|
53 @intCast(i64, target_addr) - @intCast(i64, subtractor.payload.regular.address) + self.addend57 @intCast(i64, args.target_addr) - @intCast(i64, subtractor.payload.regular.address) + self.addend
54 else58 else
55 @intCast(i64, target_addr) + self.addend;59 @intCast(i64, args.target_addr) + self.addend;
5660
57 if (self.is_64bit) {61 if (self.is_64bit) {
58 mem.writeIntLittle(u64, base.block.code[base.offset..][0..8], @bitCast(u64, result));62 mem.writeIntLittle(u64, args.block.code[args.offset..][0..8], @bitCast(u64, result));
59 } else {63 } else {
60 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], @truncate(u32, @bitCast(u64, result)));64 mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @truncate(u32, @bitCast(u64, result)));
61 }65 }
62 }66 }
6367
...@@ -78,25 +82,29 @@ pub const Relocation = struct {...@@ -78,25 +82,29 @@ pub const Relocation = struct {
78 pub const Branch = struct {82 pub const Branch = struct {
79 arch: Arch,83 arch: Arch,
8084
81 pub fn resolve(self: Branch, base: Relocation, source_addr: u64, target_addr: u64) !void {85 pub fn resolve(self: Branch, args: ResolveArgs) !void {
82 switch (self.arch) {86 switch (self.arch) {
83 .aarch64 => {87 .aarch64 => {
84 const displacement = try math.cast(i28, @intCast(i64, target_addr) - @intCast(i64, source_addr));88 const displacement = try math.cast(
89 i28,
90 @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr),
91 );
92 const code = args.block.code[args.offset..][0..4];
85 var inst = aarch64.Instruction{93 var inst = aarch64.Instruction{
86 .unconditional_branch_immediate = mem.bytesToValue(94 .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload(
87 meta.TagPayload(95 aarch64.Instruction,
88 aarch64.Instruction,96 aarch64.Instruction.unconditional_branch_immediate,
89 aarch64.Instruction.unconditional_branch_immediate,97 ), code),
90 ),
91 base.block.code[base.offset..][0..4],
92 ),
93 };98 };
94 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));99 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
95 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());100 mem.writeIntLittle(u32, code, inst.toU32());
96 },101 },
97 .x86_64 => {102 .x86_64 => {
98 const displacement = try math.cast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4);103 const displacement = try math.cast(
99 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], @bitCast(u32, displacement));104 i32,
105 @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4,
106 );
107 mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @bitCast(u32, displacement));
100 },108 },
101 else => return error.UnsupportedCpuArchitecture,109 else => return error.UnsupportedCpuArchitecture,
102 }110 }
...@@ -118,25 +126,23 @@ pub const Relocation = struct {...@@ -118,25 +126,23 @@ pub const Relocation = struct {
118 },126 },
119 addend: ?u32 = null,127 addend: ?u32 = null,
120128
121 pub fn resolve(self: Page, base: Relocation, source_addr: u64, target_addr: u64) !void {129 pub fn resolve(self: Page, args: ResolveArgs) !void {
122 const actual_target_addr = if (self.addend) |addend| target_addr + addend else target_addr;130 const target_addr = if (self.addend) |addend| args.target_addr + addend else args.target_addr;
123 const source_page = @intCast(i32, source_addr >> 12);131 const source_page = @intCast(i32, args.source_addr >> 12);
124 const target_page = @intCast(i32, actual_target_addr >> 12);132 const target_page = @intCast(i32, target_addr >> 12);
125 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));133 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
126134
135 const code = args.block.code[args.offset..][0..4];
127 var inst = aarch64.Instruction{136 var inst = aarch64.Instruction{
128 .pc_relative_address = mem.bytesToValue(137 .pc_relative_address = mem.bytesToValue(meta.TagPayload(
129 meta.TagPayload(138 aarch64.Instruction,
130 aarch64.Instruction,139 aarch64.Instruction.pc_relative_address,
131 aarch64.Instruction.pc_relative_address,140 ), code),
132 ),
133 base.block.code[base.offset..][0..4],
134 ),
135 };141 };
136 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);142 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
137 inst.pc_relative_address.immlo = @truncate(u2, pages);143 inst.pc_relative_address.immlo = @truncate(u2, pages);
138144
139 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());145 mem.writeIntLittle(u32, code, inst.toU32());
140 }146 }
141147
142 pub fn format(self: Page, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {148 pub fn format(self: Page, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
...@@ -173,35 +179,31 @@ pub const Relocation = struct {...@@ -173,35 +179,31 @@ pub const Relocation = struct {
173 load,179 load,
174 };180 };
175181
176 pub fn resolve(self: PageOff, base: Relocation, _: u64, target_addr: u64) !void {182 pub fn resolve(self: PageOff, args: ResolveArgs) !void {
183 const code = args.block.code[args.offset..][0..4];
184
177 switch (self.kind) {185 switch (self.kind) {
178 .page => {186 .page => {
179 const actual_target_addr = if (self.addend) |addend| target_addr + addend else target_addr;187 const target_addr = if (self.addend) |addend| args.target_addr + addend else args.target_addr;
180 const narrowed = @truncate(u12, actual_target_addr);188 const narrowed = @truncate(u12, target_addr);
181189
182 const op_kind = self.op_kind orelse unreachable;190 const op_kind = self.op_kind orelse unreachable;
183 var inst: aarch64.Instruction = blk: {191 var inst: aarch64.Instruction = blk: {
184 switch (op_kind) {192 switch (op_kind) {
185 .arithmetic => {193 .arithmetic => {
186 break :blk .{194 break :blk .{
187 .add_subtract_immediate = mem.bytesToValue(195 .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(
188 meta.TagPayload(196 aarch64.Instruction,
189 aarch64.Instruction,197 aarch64.Instruction.add_subtract_immediate,
190 aarch64.Instruction.add_subtract_immediate,198 ), code),
191 ),
192 base.block.code[base.offset..][0..4],
193 ),
194 };199 };
195 },200 },
196 .load => {201 .load => {
197 break :blk .{202 break :blk .{
198 .load_store_register = mem.bytesToValue(203 .load_store_register = mem.bytesToValue(meta.TagPayload(
199 meta.TagPayload(204 aarch64.Instruction,
200 aarch64.Instruction,205 aarch64.Instruction.load_store_register,
201 aarch64.Instruction.load_store_register,206 ), code),
202 ),
203 base.block.code[base.offset..][0..4],
204 ),
205 };207 };
206 },208 },
207 }209 }
...@@ -226,22 +228,19 @@ pub const Relocation = struct {...@@ -226,22 +228,19 @@ pub const Relocation = struct {
226 inst.load_store_register.offset = offset;228 inst.load_store_register.offset = offset;
227 }229 }
228230
229 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());231 mem.writeIntLittle(u32, code, inst.toU32());
230 },232 },
231 .got => {233 .got => {
232 const narrowed = @truncate(u12, target_addr);234 const narrowed = @truncate(u12, args.target_addr);
233 var inst: aarch64.Instruction = .{235 var inst: aarch64.Instruction = .{
234 .load_store_register = mem.bytesToValue(236 .load_store_register = mem.bytesToValue(meta.TagPayload(
235 meta.TagPayload(237 aarch64.Instruction,
236 aarch64.Instruction,238 aarch64.Instruction.load_store_register,
237 aarch64.Instruction.load_store_register,239 ), code),
238 ),
239 base.block.code[base.offset..][0..4],
240 ),
241 };240 };
242 const offset = try math.divExact(u12, narrowed, 8);241 const offset = try math.divExact(u12, narrowed, 8);
243 inst.load_store_register.offset = offset;242 inst.load_store_register.offset = offset;
244 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());243 mem.writeIntLittle(u32, code, inst.toU32());
245 },244 },
246 .tlvp => {245 .tlvp => {
247 const RegInfo = struct {246 const RegInfo = struct {
...@@ -250,27 +249,21 @@ pub const Relocation = struct {...@@ -250,27 +249,21 @@ pub const Relocation = struct {
250 size: u1,249 size: u1,
251 };250 };
252 const reg_info: RegInfo = blk: {251 const reg_info: RegInfo = blk: {
253 if (isArithmeticOp(base.block.code[base.offset..][0..4])) {252 if (isArithmeticOp(code)) {
254 const inst = mem.bytesToValue(253 const inst = mem.bytesToValue(meta.TagPayload(
255 meta.TagPayload(254 aarch64.Instruction,
256 aarch64.Instruction,255 aarch64.Instruction.add_subtract_immediate,
257 aarch64.Instruction.add_subtract_immediate,256 ), code);
258 ),
259 base.block.code[base.offset..][0..4],
260 );
261 break :blk .{257 break :blk .{
262 .rd = inst.rd,258 .rd = inst.rd,
263 .rn = inst.rn,259 .rn = inst.rn,
264 .size = inst.sf,260 .size = inst.sf,
265 };261 };
266 } else {262 } else {
267 const inst = mem.bytesToValue(263 const inst = mem.bytesToValue(meta.TagPayload(
268 meta.TagPayload(264 aarch64.Instruction,
269 aarch64.Instruction,265 aarch64.Instruction.load_store_register,
270 aarch64.Instruction.load_store_register,266 ), code);
271 ),
272 base.block.code[base.offset..][0..4],
273 );
274 break :blk .{267 break :blk .{
275 .rd = inst.rt,268 .rd = inst.rt,
276 .rn = inst.rn,269 .rn = inst.rn,
...@@ -278,7 +271,7 @@ pub const Relocation = struct {...@@ -278,7 +271,7 @@ pub const Relocation = struct {
278 };271 };
279 }272 }
280 };273 };
281 const narrowed = @truncate(u12, target_addr);274 const narrowed = @truncate(u12, args.target_addr);
282 var inst = aarch64.Instruction{275 var inst = aarch64.Instruction{
283 .add_subtract_immediate = .{276 .add_subtract_immediate = .{
284 .rd = reg_info.rd,277 .rd = reg_info.rd,
...@@ -290,7 +283,7 @@ pub const Relocation = struct {...@@ -290,7 +283,7 @@ pub const Relocation = struct {
290 .sf = reg_info.size,283 .sf = reg_info.size,
291 },284 },
292 };285 };
293 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());286 mem.writeIntLittle(u32, code, inst.toU32());
294 },287 },
295 }288 }
296 }289 }
...@@ -319,9 +312,9 @@ pub const Relocation = struct {...@@ -319,9 +312,9 @@ pub const Relocation = struct {
319 };312 };
320313
321 pub const PointerToGot = struct {314 pub const PointerToGot = struct {
322 pub fn resolve(_: PointerToGot, base: Relocation, source_addr: u64, target_addr: u64) !void {315 pub fn resolve(_: PointerToGot, args: ResolveArgs) !void {
323 const result = try math.cast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr));316 const result = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr));
324 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], @bitCast(u32, result));317 mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @bitCast(u32, result));
325 }318 }
326319
327 pub fn format(self: PointerToGot, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {320 pub fn format(self: PointerToGot, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
...@@ -336,13 +329,13 @@ pub const Relocation = struct {...@@ -336,13 +329,13 @@ pub const Relocation = struct {
336 addend: i64,329 addend: i64,
337 correction: i4,330 correction: i4,
338331
339 pub fn resolve(self: Signed, base: Relocation, source_addr: u64, target_addr: u64) !void {332 pub fn resolve(self: Signed, args: ResolveArgs) !void {
340 const actual_target_addr = @intCast(i64, target_addr) + self.addend;333 const target_addr = @intCast(i64, args.target_addr) + self.addend;
341 const displacement = try math.cast(334 const displacement = try math.cast(
342 i32,335 i32,
343 actual_target_addr - @intCast(i64, source_addr) - self.correction - 4,336 target_addr - @intCast(i64, args.source_addr) - self.correction - 4,
344 );337 );
345 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], @bitCast(u32, displacement));338 mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @bitCast(u32, displacement));
346 }339 }
347340
348 pub fn format(self: Signed, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {341 pub fn format(self: Signed, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
...@@ -362,17 +355,17 @@ pub const Relocation = struct {...@@ -362,17 +355,17 @@ pub const Relocation = struct {
362 },355 },
363 addend: ?i32 = null,356 addend: ?i32 = null,
364357
365 pub fn resolve(self: Load, base: Relocation, source_addr: u64, target_addr: u64) !void {358 pub fn resolve(self: Load, args: ResolveArgs) !void {
366 if (self.kind == .tlvp) {359 if (self.kind == .tlvp) {
367 // We need to rewrite the opcode from movq to leaq.360 // We need to rewrite the opcode from movq to leaq.
368 base.block.code[base.offset - 2] = 0x8d;361 args.block.code[args.offset - 2] = 0x8d;
369 }362 }
370 const addend = if (self.addend) |addend| addend else 0;363 const addend = if (self.addend) |addend| addend else 0;
371 const displacement = try math.cast(364 const displacement = try math.cast(
372 i32,365 i32,
373 @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4 + addend,366 @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + addend,
374 );367 );
375 mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], @bitCast(u32, displacement));368 mem.writeIntLittle(u32, args.block.code[args.offset..][0..4], @bitCast(u32, displacement));
376 }369 }
377370
378 pub fn format(self: Load, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {371 pub fn format(self: Load, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
...@@ -387,106 +380,27 @@ pub const Relocation = struct {...@@ -387,106 +380,27 @@ pub const Relocation = struct {
387 }380 }
388 };381 };
389382
390 pub fn resolve(self: Relocation, zld: *Zld) !void {383 pub fn resolve(self: Relocation, block: *TextBlock, source_addr: u64, target_addr: u64) !void {
391 log.debug("relocating {}", .{self});384 const args = ResolveArgs{
392385 .block = block,
393 const source_addr = blk: {386 .offset = self.offset,
394 const sym = zld.locals.items[self.block.local_sym_index];387 .source_addr = source_addr,
395 break :blk sym.payload.regular.address + self.offset;388 .target_addr = target_addr,
396 };
397 const target_addr = blk: {
398 const is_via_got = switch (self.payload) {
399 .pointer_to_got => true,
400 .page => |page| page.kind == .got,
401 .page_off => |page_off| page_off.kind == .got,
402 .load => |load| load.kind == .got,
403 else => false,
404 };
405
406 if (is_via_got) {
407 const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;
408 const got = dc_seg.sections.items[zld.got_section_index.?];
409 const got_index = self.target.got_index orelse {
410 log.err("expected GOT entry for symbol '{s}'", .{zld.getString(self.target.strx)});
411 log.err(" this is an internal linker error", .{});
412 return error.FailedToResolveRelocationTarget;
413 };
414 break :blk got.addr + got_index * @sizeOf(u64);
415 }
416
417 switch (self.target.payload) {
418 .regular => |reg| {
419 const is_tlv = is_tlv: {
420 const sym = zld.locals.items[self.block.local_sym_index];
421 const seg = zld.load_commands.items[sym.payload.regular.segment_id].Segment;
422 const sect = seg.sections.items[sym.payload.regular.section_id];
423 break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
424 };
425 if (is_tlv) {
426 // For TLV relocations, the value specified as a relocation is the displacement from the
427 // TLV initializer (either value in __thread_data or zero-init in __thread_bss) to the first
428 // defined TLV template init section in the following order:
429 // * wrt to __thread_data if defined, then
430 // * wrt to __thread_bss
431 const seg = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment;
432 const base_address = inner: {
433 if (zld.tlv_data_section_index) |i| {
434 break :inner seg.sections.items[i].addr;
435 } else if (zld.tlv_bss_section_index) |i| {
436 break :inner seg.sections.items[i].addr;
437 } else {
438 log.err("threadlocal variables present but no initializer sections found", .{});
439 log.err(" __thread_data not found", .{});
440 log.err(" __thread_bss not found", .{});
441 return error.FailedToResolveRelocationTarget;
442 }
443 };
444 break :blk reg.address - base_address;
445 }
446
447 break :blk reg.address;
448 },
449 .proxy => {
450 if (mem.eql(u8, zld.getString(self.target.strx), "__tlv_bootstrap")) {
451 break :blk 0; // Dynamically bound by dyld.
452 }
453
454 const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment;
455 const stubs = segment.sections.items[zld.stubs_section_index.?];
456 const stubs_index = self.target.stubs_index orelse {
457 // TODO verify in TextBlock that the symbol is indeed dynamically bound.
458 break :blk 0; // Dynamically bound by dyld.
459 };
460 break :blk stubs.addr + stubs_index * stubs.reserved2;
461 },
462 else => {
463 log.err("failed to resolve symbol '{s}' as a relocation target", .{
464 zld.getString(self.target.strx),
465 });
466 log.err(" this is an internal linker error", .{});
467 return error.FailedToResolveRelocationTarget;
468 },
469 }
470 };389 };
471
472 log.debug(" | source_addr = 0x{x}", .{source_addr});
473 log.debug(" | target_addr = 0x{x}", .{target_addr});
474
475 switch (self.payload) {390 switch (self.payload) {
476 .unsigned => |unsigned| try unsigned.resolve(self, source_addr, target_addr),391 .unsigned => |unsigned| try unsigned.resolve(args),
477 .branch => |branch| try branch.resolve(self, source_addr, target_addr),392 .branch => |branch| try branch.resolve(args),
478 .page => |page| try page.resolve(self, source_addr, target_addr),393 .page => |page| try page.resolve(args),
479 .page_off => |page_off| try page_off.resolve(self, source_addr, target_addr),394 .page_off => |page_off| try page_off.resolve(args),
480 .pointer_to_got => |pointer_to_got| try pointer_to_got.resolve(self, source_addr, target_addr),395 .pointer_to_got => |pointer_to_got| try pointer_to_got.resolve(args),
481 .signed => |signed| try signed.resolve(self, source_addr, target_addr),396 .signed => |signed| try signed.resolve(args),
482 .load => |load| try load.resolve(self, source_addr, target_addr),397 .load => |load| try load.resolve(args),
483 }398 }
484 }399 }
485400
486 pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {401 pub fn format(self: Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
487 try std.fmt.format(writer, "Relocation {{ ", .{});402 try std.fmt.format(writer, "Relocation {{ ", .{});
488 try std.fmt.format(writer, ".offset = {}, ", .{self.offset});403 try std.fmt.format(writer, ".offset = {}, ", .{self.offset});
489 try std.fmt.format(writer, ".block = {}", .{self.block.local_sym_index});
490 try std.fmt.format(writer, ".target = {}, ", .{self.target});404 try std.fmt.format(writer, ".target = {}, ", .{self.target});
491405
492 switch (self.payload) {406 switch (self.payload) {
...@@ -713,7 +627,6 @@ pub const Parser = struct {...@@ -713,7 +627,6 @@ pub const Parser = struct {
713 return Relocation{627 return Relocation{
714 .offset = offset,628 .offset = offset,
715 .target = target,629 .target = target,
716 .block = self.block,
717 .payload = undefined,630 .payload = undefined,
718 };631 };
719 }632 }