| ... | @@ -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, |
| 22 | | 22 | |
| 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, |
| 28 | | 25 | |
| ... | @@ -36,6 +33,13 @@ pub const Relocation = struct { | ... | @@ -36,6 +33,13 @@ pub const Relocation = struct { |
| 36 | load: Load, | 33 | load: Load, |
| 37 | }, | 34 | }, |
| 38 | | 35 | |
| | 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, |
| 41 | | 45 | |
| ... | @@ -48,16 +52,16 @@ pub const Relocation = struct { | ... | @@ -48,16 +52,16 @@ pub const Relocation = struct { |
| 48 | /// => * is unreachable | 52 | /// => * is unreachable |
| 49 | is_64bit: bool, | 53 | is_64bit: bool, |
| 50 | | 54 | |
| 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.addend | 57 | @intCast(i64, args.target_addr) - @intCast(i64, subtractor.payload.regular.address) + self.addend |
| 54 | else | 58 | else |
| 55 | @intCast(i64, target_addr) + self.addend; | 59 | @intCast(i64, args.target_addr) + self.addend; |
| 56 | | 60 | |
| 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 | } |
| 63 | | 67 | |
| ... | @@ -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, |
| 80 | | 84 | |
| 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, |
| 120 | | 128 | |
| 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)); |
| 126 | | 134 | |
| | 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); |
| 138 | | 144 | |
| 139 | mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32()); | 145 | mem.writeIntLittle(u32, code, inst.toU32()); |
| 140 | } | 146 | } |
| 141 | | 147 | |
| 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 | }; |
| 175 | | 181 | |
| 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); |
| 181 | | 189 | |
| 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 | } |
| 228 | | 230 | |
| 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 | }; |
| 320 | | 313 | |
| 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 | } |
| 326 | | 319 | |
| 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, |
| 338 | | 331 | |
| 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 | } |
| 347 | | 340 | |
| 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, |
| 364 | | 357 | |
| 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 | } |
| 377 | | 370 | |
| 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 | }; |
| 389 | | 382 | |
| 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{ |
| 392 | | 385 | .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 | } |
| 485 | | 400 | |
| 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}); |
| 491 | | 405 | |
| 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 | } |