| author | |
| committer | |
| log | fc7dd3e285889cd0f75e7270bb0021ad32f73ca3 |
| tree | f3417c9239b2a45148564fbbb16eef9c2826dc28 |
| parent | 88d4b5cb18bdc68099162f1db8103d614025659c |
9 files changed, 863 insertions(+), 565 deletions(-)
CMakeLists.txt+1| ... | @@ -594,6 +594,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -594,6 +594,7 @@ set(ZIG_STAGE2_SOURCES |
| 594 | "${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig" | 594 | "${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig" |
| 595 | "${CMAKE_SOURCE_DIR}/src/link/Elf/gc.zig" | 595 | "${CMAKE_SOURCE_DIR}/src/link/Elf/gc.zig" |
| 596 | "${CMAKE_SOURCE_DIR}/src/link/Elf/relocatable.zig" | 596 | "${CMAKE_SOURCE_DIR}/src/link/Elf/relocatable.zig" |
| 597 | "${CMAKE_SOURCE_DIR}/src/link/Elf/relocation.zig" | ||
| 597 | "${CMAKE_SOURCE_DIR}/src/link/Elf/synthetic_sections.zig" | 598 | "${CMAKE_SOURCE_DIR}/src/link/Elf/synthetic_sections.zig" |
| 598 | "${CMAKE_SOURCE_DIR}/src/link/MachO.zig" | 599 | "${CMAKE_SOURCE_DIR}/src/link/MachO.zig" |
| 599 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig" | 600 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig" |
src/link/Elf.zig+63-27| ... | @@ -1357,6 +1357,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1357,6 +1357,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1357 | error.RelaxFail, error.InvalidInstruction, error.CannotEncode => { | 1357 | error.RelaxFail, error.InvalidInstruction, error.CannotEncode => { |
| 1358 | log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{}); | 1358 | log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{}); |
| 1359 | }, | 1359 | }, |
| 1360 | error.UnsupportedCpuArch => { | ||
| 1361 | try self.reportUnsupportedCpuArch(); | ||
| 1362 | return error.FlushFailure; | ||
| 1363 | }, | ||
| 1360 | else => |e| return e, | 1364 | else => |e| return e, |
| 1361 | }; | 1365 | }; |
| 1362 | try self.base.file.?.pwriteAll(code, file_offset); | 1366 | try self.base.file.?.pwriteAll(code, file_offset); |
| ... | @@ -1366,7 +1370,14 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1366,7 +1370,14 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1366 | try self.writePhdrTable(); | 1370 | try self.writePhdrTable(); |
| 1367 | try self.writeShdrTable(); | 1371 | try self.writeShdrTable(); |
| 1368 | try self.writeAtoms(); | 1372 | try self.writeAtoms(); |
| 1369 | try self.writeSyntheticSections(); | 1373 | |
| 1374 | self.writeSyntheticSections() catch |err| switch (err) { | ||
| 1375 | error.UnsupportedCpuArch => { | ||
| 1376 | try self.reportUnsupportedCpuArch(); | ||
| 1377 | return error.FlushFailure; | ||
| 1378 | }, | ||
| 1379 | else => |e| return e, | ||
| 1380 | }; | ||
| 1370 | 1381 | ||
| 1371 | if (self.entry_index == null and self.base.isExe()) { | 1382 | if (self.entry_index == null and self.base.isExe()) { |
| 1372 | log.debug("flushing. no_entry_point_found = true", .{}); | 1383 | log.debug("flushing. no_entry_point_found = true", .{}); |
| ... | @@ -2032,12 +2043,19 @@ fn scanRelocs(self: *Elf) !void { | ... | @@ -2032,12 +2043,19 @@ fn scanRelocs(self: *Elf) !void { |
| 2032 | undefs.deinit(); | 2043 | undefs.deinit(); |
| 2033 | } | 2044 | } |
| 2034 | 2045 | ||
| 2035 | if (self.zigObjectPtr()) |zig_object| { | 2046 | var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1); |
| 2036 | try zig_object.scanRelocs(self, &undefs); | 2047 | defer objects.deinit(); |
| 2037 | } | 2048 | if (self.zigObjectPtr()) |zo| objects.appendAssumeCapacity(zo.index); |
| 2038 | for (self.objects.items) |index| { | 2049 | objects.appendSliceAssumeCapacity(self.objects.items); |
| 2039 | const object = self.file(index).?.object; | 2050 | |
| 2040 | try object.scanRelocs(self, &undefs); | 2051 | for (objects.items) |index| { |
| 2052 | self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) { | ||
| 2053 | error.UnsupportedCpuArch => { | ||
| 2054 | try self.reportUnsupportedCpuArch(); | ||
| 2055 | return error.FlushFailure; | ||
| 2056 | }, | ||
| 2057 | else => |e| return e, | ||
| 2058 | }; | ||
| 2041 | } | 2059 | } |
| 2042 | 2060 | ||
| 2043 | try self.reportUndefinedSymbols(&undefs); | 2061 | try self.reportUndefinedSymbols(&undefs); |
| ... | @@ -4470,17 +4488,21 @@ fn writeAtoms(self: *Elf) !void { | ... | @@ -4470,17 +4488,21 @@ fn writeAtoms(self: *Elf) !void { |
| 4470 | defer gpa.free(in_code); | 4488 | defer gpa.free(in_code); |
| 4471 | @memcpy(out_code, in_code); | 4489 | @memcpy(out_code, in_code); |
| 4472 | 4490 | ||
| 4473 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) { | 4491 | const res = if (shdr.sh_flags & elf.SHF_ALLOC == 0) |
| 4474 | try atom_ptr.resolveRelocsNonAlloc(self, out_code, &undefs); | 4492 | atom_ptr.resolveRelocsNonAlloc(self, out_code, &undefs) |
| 4475 | } else { | 4493 | else |
| 4476 | atom_ptr.resolveRelocsAlloc(self, out_code) catch |err| switch (err) { | 4494 | atom_ptr.resolveRelocsAlloc(self, out_code); |
| 4477 | // TODO | 4495 | _ = res catch |err| switch (err) { |
| 4478 | error.RelaxFail, error.InvalidInstruction, error.CannotEncode => { | 4496 | // TODO |
| 4479 | log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{}); | 4497 | error.RelaxFail, error.InvalidInstruction, error.CannotEncode => { |
| 4480 | }, | 4498 | log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{}); |
| 4481 | else => |e| return e, | 4499 | }, |
| 4482 | }; | 4500 | error.UnsupportedCpuArch => { |
| 4483 | } | 4501 | try self.reportUnsupportedCpuArch(); |
| 4502 | return error.FlushFailure; | ||
| 4503 | }, | ||
| 4504 | else => |e| return e, | ||
| 4505 | }; | ||
| 4484 | } | 4506 | } |
| 4485 | 4507 | ||
| 4486 | try self.base.file.?.pwriteAll(buffer, sh_offset); | 4508 | try self.base.file.?.pwriteAll(buffer, sh_offset); |
| ... | @@ -5271,24 +5293,26 @@ pub fn addRelaDynAssumeCapacity(self: *Elf, opts: RelaDyn) void { | ... | @@ -5271,24 +5293,26 @@ pub fn addRelaDynAssumeCapacity(self: *Elf, opts: RelaDyn) void { |
| 5271 | 5293 | ||
| 5272 | fn sortRelaDyn(self: *Elf) void { | 5294 | fn sortRelaDyn(self: *Elf) void { |
| 5273 | const Sort = struct { | 5295 | const Sort = struct { |
| 5274 | fn rank(rel: elf.Elf64_Rela) u2 { | 5296 | fn rank(rel: elf.Elf64_Rela, ctx: *Elf) u2 { |
| 5275 | return switch (rel.r_type()) { | 5297 | const cpu_arch = ctx.getTarget().cpu.arch; |
| 5276 | elf.R_X86_64_RELATIVE => 0, | 5298 | const r_type = rel.r_type(); |
| 5277 | elf.R_X86_64_IRELATIVE => 2, | 5299 | const r_kind = relocation.decode(r_type, cpu_arch).?; |
| 5300 | return switch (r_kind) { | ||
| 5301 | .rel => 0, | ||
| 5302 | .irel => 2, | ||
| 5278 | else => 1, | 5303 | else => 1, |
| 5279 | }; | 5304 | }; |
| 5280 | } | 5305 | } |
| 5281 | 5306 | ||
| 5282 | pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool { | 5307 | pub fn lessThan(ctx: *Elf, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool { |
| 5283 | _ = ctx; | 5308 | if (rank(lhs, ctx) == rank(rhs, ctx)) { |
| 5284 | if (rank(lhs) == rank(rhs)) { | ||
| 5285 | if (lhs.r_sym() == rhs.r_sym()) return lhs.r_offset < rhs.r_offset; | 5309 | if (lhs.r_sym() == rhs.r_sym()) return lhs.r_offset < rhs.r_offset; |
| 5286 | return lhs.r_sym() < rhs.r_sym(); | 5310 | return lhs.r_sym() < rhs.r_sym(); |
| 5287 | } | 5311 | } |
| 5288 | return rank(lhs) < rank(rhs); | 5312 | return rank(lhs, ctx) < rank(rhs, ctx); |
| 5289 | } | 5313 | } |
| 5290 | }; | 5314 | }; |
| 5291 | mem.sort(elf.Elf64_Rela, self.rela_dyn.items, {}, Sort.lessThan); | 5315 | mem.sort(elf.Elf64_Rela, self.rela_dyn.items, self, Sort.lessThan); |
| 5292 | } | 5316 | } |
| 5293 | 5317 | ||
| 5294 | fn calcNumIRelativeRelocs(self: *Elf) usize { | 5318 | fn calcNumIRelativeRelocs(self: *Elf) usize { |
| ... | @@ -5667,6 +5691,13 @@ fn reportMissingLibraryError( | ... | @@ -5667,6 +5691,13 @@ fn reportMissingLibraryError( |
| 5667 | } | 5691 | } |
| 5668 | } | 5692 | } |
| 5669 | 5693 | ||
| 5694 | pub fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void { | ||
| 5695 | var err = try self.addErrorWithNotes(0); | ||
| 5696 | try err.addMsg(self, "fatal linker error: unsupported CPU architecture {s}", .{ | ||
| 5697 | @tagName(self.getTarget().cpu.arch), | ||
| 5698 | }); | ||
| 5699 | } | ||
| 5700 | |||
| 5670 | pub fn reportParseError( | 5701 | pub fn reportParseError( |
| 5671 | self: *Elf, | 5702 | self: *Elf, |
| 5672 | path: []const u8, | 5703 | path: []const u8, |
| ... | @@ -5932,6 +5963,10 @@ pub fn lsearch(comptime T: type, haystack: []align(1) const T, predicate: anytyp | ... | @@ -5932,6 +5963,10 @@ pub fn lsearch(comptime T: type, haystack: []align(1) const T, predicate: anytyp |
| 5932 | return i; | 5963 | return i; |
| 5933 | } | 5964 | } |
| 5934 | 5965 | ||
| 5966 | pub fn getTarget(self: Elf) std.Target { | ||
| 5967 | return self.base.comp.root_mod.resolved_target.result; | ||
| 5968 | } | ||
| 5969 | |||
| 5935 | /// The following three values are only observed at compile-time and used to emit a compile error | 5970 | /// The following three values are only observed at compile-time and used to emit a compile error |
| 5936 | /// to remind the programmer to update expected maximum numbers of different program header types | 5971 | /// to remind the programmer to update expected maximum numbers of different program header types |
| 5937 | /// so that we reserve enough space for the program header table up-front. | 5972 | /// so that we reserve enough space for the program header table up-front. |
| ... | @@ -6059,6 +6094,7 @@ const link = @import("../link.zig"); | ... | @@ -6059,6 +6094,7 @@ const link = @import("../link.zig"); |
| 6059 | const lldMain = @import("../main.zig").lldMain; | 6094 | const lldMain = @import("../main.zig").lldMain; |
| 6060 | const musl = @import("../musl.zig"); | 6095 | const musl = @import("../musl.zig"); |
| 6061 | const relocatable = @import("Elf/relocatable.zig"); | 6096 | const relocatable = @import("Elf/relocatable.zig"); |
| 6097 | const relocation = @import("Elf/relocation.zig"); | ||
| 6062 | const target_util = @import("../target.zig"); | 6098 | const target_util = @import("../target.zig"); |
| 6063 | const trace = @import("../tracy.zig").trace; | 6099 | const trace = @import("../tracy.zig").trace; |
| 6064 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); | 6100 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); |
src/link/Elf/Atom.zig+457-497| ... | @@ -312,6 +312,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela { | ... | @@ -312,6 +312,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela { |
| 312 | pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void { | 312 | pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void { |
| 313 | relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) }); | 313 | relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) }); |
| 314 | 314 | ||
| 315 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 315 | const file_ptr = self.file(elf_file).?; | 316 | const file_ptr = self.file(elf_file).?; |
| 316 | for (self.relocs(elf_file)) |rel| { | 317 | for (self.relocs(elf_file)) |rel| { |
| 317 | const target_index = switch (file_ptr) { | 318 | const target_index = switch (file_ptr) { |
| ... | @@ -320,12 +321,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El | ... | @@ -320,12 +321,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El |
| 320 | else => unreachable, | 321 | else => unreachable, |
| 321 | }; | 322 | }; |
| 322 | const target = elf_file.symbol(target_index); | 323 | const target = elf_file.symbol(target_index); |
| 323 | const r_type = switch (rel.r_type()) { | 324 | const r_type = rel.r_type(); |
| 324 | Elf.R_X86_64_ZIG_GOT32, | ||
| 325 | Elf.R_X86_64_ZIG_GOTPCREL, | ||
| 326 | => unreachable, // Sanity check if we accidentally emitted those. | ||
| 327 | else => |r_type| r_type, | ||
| 328 | }; | ||
| 329 | const r_offset = self.value + rel.r_offset; | 325 | const r_offset = self.value + rel.r_offset; |
| 330 | var r_addend = rel.r_addend; | 326 | var r_addend = rel.r_addend; |
| 331 | var r_sym: u32 = 0; | 327 | var r_sym: u32 = 0; |
| ... | @@ -340,7 +336,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El | ... | @@ -340,7 +336,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El |
| 340 | } | 336 | } |
| 341 | 337 | ||
| 342 | relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ | 338 | relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ |
| 343 | fmtRelocType(r_type), | 339 | relocation.fmtRelocType(r_type, cpu_arch), |
| 344 | r_offset, | 340 | r_offset, |
| 345 | r_sym, | 341 | r_sym, |
| 346 | target.name(elf_file), | 342 | target.name(elf_file), |
| ... | @@ -385,155 +381,20 @@ pub fn freeRelocs(self: Atom, elf_file: *Elf) void { | ... | @@ -385,155 +381,20 @@ pub fn freeRelocs(self: Atom, elf_file: *Elf) void { |
| 385 | } | 381 | } |
| 386 | 382 | ||
| 387 | pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool { | 383 | pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool { |
| 384 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 388 | for (self.relocs(elf_file)) |rel| { | 385 | for (self.relocs(elf_file)) |rel| { |
| 389 | if (rel.r_type() == elf.R_X86_64_GOTTPOFF) return true; | 386 | switch (cpu_arch) { |
| 387 | .x86_64 => if (rel.r_type() == elf.R_X86_64_GOTTPOFF) return true, | ||
| 388 | else => {}, | ||
| 389 | } | ||
| 390 | } | 390 | } |
| 391 | return false; | 391 | return false; |
| 392 | } | 392 | } |
| 393 | 393 | ||
| 394 | pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void { | 394 | pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void { |
| 395 | const is_static = elf_file.base.isStatic(); | 395 | switch (elf_file.getTarget().cpu.arch) { |
| 396 | const is_dyn_lib = elf_file.base.isDynLib(); | 396 | .x86_64 => try x86_64.scanRelocs(self, elf_file, code, undefs), |
| 397 | const file_ptr = self.file(elf_file).?; | 397 | else => return error.UnsupportedCpuArch, |
| 398 | const rels = self.relocs(elf_file); | ||
| 399 | var i: usize = 0; | ||
| 400 | while (i < rels.len) : (i += 1) { | ||
| 401 | const rel = rels[i]; | ||
| 402 | |||
| 403 | if (rel.r_type() == elf.R_X86_64_NONE) continue; | ||
| 404 | |||
| 405 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; | ||
| 406 | |||
| 407 | const symbol_index = switch (file_ptr) { | ||
| 408 | .zig_object => |x| x.symbol(rel.r_sym()), | ||
| 409 | .object => |x| x.symbols.items[rel.r_sym()], | ||
| 410 | else => unreachable, | ||
| 411 | }; | ||
| 412 | const symbol = elf_file.symbol(symbol_index); | ||
| 413 | |||
| 414 | // Check for violation of One Definition Rule for COMDATs. | ||
| 415 | if (symbol.file(elf_file) == null) { | ||
| 416 | // TODO convert into an error | ||
| 417 | log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ | ||
| 418 | file_ptr.fmtPath(), | ||
| 419 | self.name(elf_file), | ||
| 420 | symbol.name(elf_file), | ||
| 421 | }); | ||
| 422 | continue; | ||
| 423 | } | ||
| 424 | |||
| 425 | // Report an undefined symbol. | ||
| 426 | try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs); | ||
| 427 | |||
| 428 | if (symbol.isIFunc(elf_file)) { | ||
| 429 | symbol.flags.needs_got = true; | ||
| 430 | symbol.flags.needs_plt = true; | ||
| 431 | } | ||
| 432 | |||
| 433 | // While traversing relocations, mark symbols that require special handling such as | ||
| 434 | // pointer indirection via GOT, or a stub trampoline via PLT. | ||
| 435 | switch (rel.r_type()) { | ||
| 436 | elf.R_X86_64_64 => { | ||
| 437 | try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); | ||
| 438 | }, | ||
| 439 | |||
| 440 | elf.R_X86_64_32, | ||
| 441 | elf.R_X86_64_32S, | ||
| 442 | => { | ||
| 443 | try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); | ||
| 444 | }, | ||
| 445 | |||
| 446 | elf.R_X86_64_GOT32, | ||
| 447 | elf.R_X86_64_GOTPC32, | ||
| 448 | elf.R_X86_64_GOTPC64, | ||
| 449 | elf.R_X86_64_GOTPCREL, | ||
| 450 | elf.R_X86_64_GOTPCREL64, | ||
| 451 | elf.R_X86_64_GOTPCRELX, | ||
| 452 | elf.R_X86_64_REX_GOTPCRELX, | ||
| 453 | => { | ||
| 454 | symbol.flags.needs_got = true; | ||
| 455 | }, | ||
| 456 | |||
| 457 | elf.R_X86_64_PLT32, | ||
| 458 | elf.R_X86_64_PLTOFF64, | ||
| 459 | => { | ||
| 460 | if (symbol.flags.import) { | ||
| 461 | symbol.flags.needs_plt = true; | ||
| 462 | } | ||
| 463 | }, | ||
| 464 | |||
| 465 | elf.R_X86_64_PC32 => { | ||
| 466 | try self.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file); | ||
| 467 | }, | ||
| 468 | |||
| 469 | elf.R_X86_64_TLSGD => { | ||
| 470 | // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr | ||
| 471 | |||
| 472 | if (is_static or (!symbol.flags.import and !is_dyn_lib)) { | ||
| 473 | // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a | ||
| 474 | // We skip the next relocation. | ||
| 475 | i += 1; | ||
| 476 | } else if (!symbol.flags.import and is_dyn_lib) { | ||
| 477 | symbol.flags.needs_gottp = true; | ||
| 478 | i += 1; | ||
| 479 | } else { | ||
| 480 | symbol.flags.needs_tlsgd = true; | ||
| 481 | } | ||
| 482 | }, | ||
| 483 | |||
| 484 | elf.R_X86_64_TLSLD => { | ||
| 485 | // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr | ||
| 486 | |||
| 487 | if (is_static or !is_dyn_lib) { | ||
| 488 | // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a | ||
| 489 | // We skip the next relocation. | ||
| 490 | i += 1; | ||
| 491 | } else { | ||
| 492 | elf_file.got.flags.needs_tlsld = true; | ||
| 493 | } | ||
| 494 | }, | ||
| 495 | |||
| 496 | elf.R_X86_64_GOTTPOFF => { | ||
| 497 | const should_relax = blk: { | ||
| 498 | if (is_dyn_lib or symbol.flags.import) break :blk false; | ||
| 499 | if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..])) break :blk false; | ||
| 500 | break :blk true; | ||
| 501 | }; | ||
| 502 | if (!should_relax) { | ||
| 503 | symbol.flags.needs_gottp = true; | ||
| 504 | } | ||
| 505 | }, | ||
| 506 | |||
| 507 | elf.R_X86_64_GOTPC32_TLSDESC => { | ||
| 508 | const should_relax = is_static or (!is_dyn_lib and !symbol.flags.import); | ||
| 509 | if (!should_relax) { | ||
| 510 | symbol.flags.needs_tlsdesc = true; | ||
| 511 | } | ||
| 512 | }, | ||
| 513 | |||
| 514 | elf.R_X86_64_TPOFF32, | ||
| 515 | elf.R_X86_64_TPOFF64, | ||
| 516 | => { | ||
| 517 | if (is_dyn_lib) try self.reportPicError(symbol, rel, elf_file); | ||
| 518 | }, | ||
| 519 | |||
| 520 | elf.R_X86_64_GOTOFF64, | ||
| 521 | elf.R_X86_64_DTPOFF32, | ||
| 522 | elf.R_X86_64_DTPOFF64, | ||
| 523 | elf.R_X86_64_SIZE32, | ||
| 524 | elf.R_X86_64_SIZE64, | ||
| 525 | elf.R_X86_64_TLSDESC_CALL, | ||
| 526 | => {}, | ||
| 527 | |||
| 528 | // Zig custom relocations | ||
| 529 | Elf.R_X86_64_ZIG_GOT32, | ||
| 530 | Elf.R_X86_64_ZIG_GOTPCREL, | ||
| 531 | => { | ||
| 532 | assert(symbol.flags.has_zig_got); | ||
| 533 | }, | ||
| 534 | |||
| 535 | else => try self.reportUnhandledRelocError(rel, elf_file), | ||
| 536 | } | ||
| 537 | } | 398 | } |
| 538 | } | 399 | } |
| 539 | 400 | ||
| ... | @@ -693,7 +554,7 @@ fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 { | ... | @@ -693,7 +554,7 @@ fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 { |
| 693 | fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) error{OutOfMemory}!void { | 554 | fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) error{OutOfMemory}!void { |
| 694 | var err = try elf_file.addErrorWithNotes(1); | 555 | var err = try elf_file.addErrorWithNotes(1); |
| 695 | try err.addMsg(elf_file, "fatal linker error: unhandled relocation type {} at offset 0x{x}", .{ | 556 | try err.addMsg(elf_file, "fatal linker error: unhandled relocation type {} at offset 0x{x}", .{ |
| 696 | fmtRelocType(rel.r_type()), | 557 | relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch), |
| 697 | rel.r_offset, | 558 | rel.r_offset, |
| 698 | }); | 559 | }); |
| 699 | try err.addNote(elf_file, "in {}:{s}", .{ | 560 | try err.addNote(elf_file, "in {}:{s}", .{ |
| ... | @@ -789,182 +650,9 @@ fn reportUndefined( | ... | @@ -789,182 +650,9 @@ fn reportUndefined( |
| 789 | pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { | 650 | pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 790 | relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) }); | 651 | relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) }); |
| 791 | 652 | ||
| 792 | const file_ptr = self.file(elf_file).?; | 653 | switch (elf_file.getTarget().cpu.arch) { |
| 793 | var stream = std.io.fixedBufferStream(code); | 654 | .x86_64 => try x86_64.resolveRelocsAlloc(self, elf_file, code), |
| 794 | const cwriter = stream.writer(); | 655 | else => return error.UnsupportedCpuArch, |
| 795 | |||
| 796 | const rels = self.relocs(elf_file); | ||
| 797 | var i: usize = 0; | ||
| 798 | while (i < rels.len) : (i += 1) { | ||
| 799 | const rel = rels[i]; | ||
| 800 | const r_type = rel.r_type(); | ||
| 801 | if (r_type == elf.R_X86_64_NONE) continue; | ||
| 802 | |||
| 803 | const target = switch (file_ptr) { | ||
| 804 | .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())), | ||
| 805 | .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]), | ||
| 806 | else => unreachable, | ||
| 807 | }; | ||
| 808 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; | ||
| 809 | |||
| 810 | // We will use equation format to resolve relocations: | ||
| 811 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ | ||
| 812 | // | ||
| 813 | // Address of the source atom. | ||
| 814 | const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset)); | ||
| 815 | // Addend from the relocation. | ||
| 816 | const A = rel.r_addend; | ||
| 817 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. | ||
| 818 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | ||
| 819 | // Address of the global offset table. | ||
| 820 | const GOT = blk: { | ||
| 821 | const shndx = if (elf_file.got_plt_section_index) |shndx| | ||
| 822 | shndx | ||
| 823 | else if (elf_file.got_section_index) |shndx| | ||
| 824 | shndx | ||
| 825 | else | ||
| 826 | null; | ||
| 827 | break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0; | ||
| 828 | }; | ||
| 829 | // Address of the .zig.got table entry if any. | ||
| 830 | const ZIG_GOT = @as(i64, @intCast(target.zigGotAddress(elf_file))); | ||
| 831 | // Relative offset to the start of the global offset table. | ||
| 832 | const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT; | ||
| 833 | // // Address of the thread pointer. | ||
| 834 | const TP = @as(i64, @intCast(elf_file.tpAddress())); | ||
| 835 | // Address of the dynamic thread pointer. | ||
| 836 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); | ||
| 837 | |||
| 838 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{ | ||
| 839 | fmtRelocType(r_type), | ||
| 840 | r_offset, | ||
| 841 | P, | ||
| 842 | S + A, | ||
| 843 | G + GOT + A, | ||
| 844 | ZIG_GOT + A, | ||
| 845 | target.name(elf_file), | ||
| 846 | }); | ||
| 847 | |||
| 848 | try stream.seekTo(r_offset); | ||
| 849 | |||
| 850 | switch (rel.r_type()) { | ||
| 851 | elf.R_X86_64_NONE => unreachable, | ||
| 852 | |||
| 853 | elf.R_X86_64_64 => { | ||
| 854 | try self.resolveDynAbsReloc( | ||
| 855 | target, | ||
| 856 | rel, | ||
| 857 | dynAbsRelocAction(target, elf_file), | ||
| 858 | elf_file, | ||
| 859 | cwriter, | ||
| 860 | ); | ||
| 861 | }, | ||
| 862 | |||
| 863 | elf.R_X86_64_PLT32, | ||
| 864 | elf.R_X86_64_PC32, | ||
| 865 | => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), | ||
| 866 | |||
| 867 | elf.R_X86_64_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little), | ||
| 868 | elf.R_X86_64_GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), | ||
| 869 | elf.R_X86_64_GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little), | ||
| 870 | |||
| 871 | elf.R_X86_64_GOTPCRELX => { | ||
| 872 | if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { | ||
| 873 | x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk; | ||
| 874 | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); | ||
| 875 | continue; | ||
| 876 | } | ||
| 877 | try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); | ||
| 878 | }, | ||
| 879 | |||
| 880 | elf.R_X86_64_REX_GOTPCRELX => { | ||
| 881 | if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { | ||
| 882 | x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk; | ||
| 883 | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); | ||
| 884 | continue; | ||
| 885 | } | ||
| 886 | try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); | ||
| 887 | }, | ||
| 888 | |||
| 889 | elf.R_X86_64_32 => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little), | ||
| 890 | elf.R_X86_64_32S => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little), | ||
| 891 | |||
| 892 | elf.R_X86_64_TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little), | ||
| 893 | elf.R_X86_64_TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little), | ||
| 894 | |||
| 895 | elf.R_X86_64_DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little), | ||
| 896 | elf.R_X86_64_DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), | ||
| 897 | |||
| 898 | elf.R_X86_64_TLSGD => { | ||
| 899 | if (target.flags.has_tlsgd) { | ||
| 900 | const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file))); | ||
| 901 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | ||
| 902 | } else if (target.flags.has_gottp) { | ||
| 903 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); | ||
| 904 | try x86_64.relaxTlsGdToIe(self, rels[i .. i + 2], @intCast(S_ - P), elf_file, &stream); | ||
| 905 | i += 1; | ||
| 906 | } else { | ||
| 907 | try x86_64.relaxTlsGdToLe( | ||
| 908 | self, | ||
| 909 | rels[i .. i + 2], | ||
| 910 | @as(i32, @intCast(S - TP)), | ||
| 911 | elf_file, | ||
| 912 | &stream, | ||
| 913 | ); | ||
| 914 | i += 1; | ||
| 915 | } | ||
| 916 | }, | ||
| 917 | |||
| 918 | elf.R_X86_64_TLSLD => { | ||
| 919 | if (elf_file.got.tlsld_index) |entry_index| { | ||
| 920 | const tlsld_entry = elf_file.got.entries.items[entry_index]; | ||
| 921 | const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file))); | ||
| 922 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | ||
| 923 | } else { | ||
| 924 | try x86_64.relaxTlsLdToLe( | ||
| 925 | self, | ||
| 926 | rels[i .. i + 2], | ||
| 927 | @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))), | ||
| 928 | elf_file, | ||
| 929 | &stream, | ||
| 930 | ); | ||
| 931 | i += 1; | ||
| 932 | } | ||
| 933 | }, | ||
| 934 | |||
| 935 | elf.R_X86_64_GOTPC32_TLSDESC => { | ||
| 936 | if (target.flags.has_tlsdesc) { | ||
| 937 | const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file))); | ||
| 938 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | ||
| 939 | } else { | ||
| 940 | try x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]); | ||
| 941 | try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); | ||
| 942 | } | ||
| 943 | }, | ||
| 944 | |||
| 945 | elf.R_X86_64_TLSDESC_CALL => if (!target.flags.has_tlsdesc) { | ||
| 946 | // call -> nop | ||
| 947 | try cwriter.writeAll(&.{ 0x66, 0x90 }); | ||
| 948 | }, | ||
| 949 | |||
| 950 | elf.R_X86_64_GOTTPOFF => { | ||
| 951 | if (target.flags.has_gottp) { | ||
| 952 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); | ||
| 953 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | ||
| 954 | } else { | ||
| 955 | x86_64.relaxGotTpOff(code[r_offset - 3 ..]) catch unreachable; | ||
| 956 | try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); | ||
| 957 | } | ||
| 958 | }, | ||
| 959 | |||
| 960 | elf.R_X86_64_GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little), | ||
| 961 | |||
| 962 | // Zig custom relocations | ||
| 963 | Elf.R_X86_64_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little), | ||
| 964 | Elf.R_X86_64_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little), | ||
| 965 | |||
| 966 | else => {}, | ||
| 967 | } | ||
| 968 | } | 656 | } |
| 969 | } | 657 | } |
| 970 | 658 | ||
| ... | @@ -978,6 +666,7 @@ fn resolveDynAbsReloc( | ... | @@ -978,6 +666,7 @@ fn resolveDynAbsReloc( |
| 978 | ) !void { | 666 | ) !void { |
| 979 | const comp = elf_file.base.comp; | 667 | const comp = elf_file.base.comp; |
| 980 | const gpa = comp.gpa; | 668 | const gpa = comp.gpa; |
| 669 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 981 | const P = self.address(elf_file) + rel.r_offset; | 670 | const P = self.address(elf_file) + rel.r_offset; |
| 982 | const A = rel.r_addend; | 671 | const A = rel.r_addend; |
| 983 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | 672 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); |
| ... | @@ -1005,7 +694,7 @@ fn resolveDynAbsReloc( | ... | @@ -1005,7 +694,7 @@ fn resolveDynAbsReloc( |
| 1005 | elf_file.addRelaDynAssumeCapacity(.{ | 694 | elf_file.addRelaDynAssumeCapacity(.{ |
| 1006 | .offset = P, | 695 | .offset = P, |
| 1007 | .sym = target.extra(elf_file).?.dynamic, | 696 | .sym = target.extra(elf_file).?.dynamic, |
| 1008 | .type = elf.R_X86_64_64, | 697 | .type = relocation.encode(.abs, cpu_arch), |
| 1009 | .addend = A, | 698 | .addend = A, |
| 1010 | }); | 699 | }); |
| 1011 | try applyDynamicReloc(A, elf_file, writer); | 700 | try applyDynamicReloc(A, elf_file, writer); |
| ... | @@ -1019,7 +708,7 @@ fn resolveDynAbsReloc( | ... | @@ -1019,7 +708,7 @@ fn resolveDynAbsReloc( |
| 1019 | elf_file.addRelaDynAssumeCapacity(.{ | 708 | elf_file.addRelaDynAssumeCapacity(.{ |
| 1020 | .offset = P, | 709 | .offset = P, |
| 1021 | .sym = target.extra(elf_file).?.dynamic, | 710 | .sym = target.extra(elf_file).?.dynamic, |
| 1022 | .type = elf.R_X86_64_64, | 711 | .type = relocation.encode(.abs, cpu_arch), |
| 1023 | .addend = A, | 712 | .addend = A, |
| 1024 | }); | 713 | }); |
| 1025 | try applyDynamicReloc(A, elf_file, writer); | 714 | try applyDynamicReloc(A, elf_file, writer); |
| ... | @@ -1032,7 +721,7 @@ fn resolveDynAbsReloc( | ... | @@ -1032,7 +721,7 @@ fn resolveDynAbsReloc( |
| 1032 | elf_file.addRelaDynAssumeCapacity(.{ | 721 | elf_file.addRelaDynAssumeCapacity(.{ |
| 1033 | .offset = P, | 722 | .offset = P, |
| 1034 | .sym = target.extra(elf_file).?.dynamic, | 723 | .sym = target.extra(elf_file).?.dynamic, |
| 1035 | .type = elf.R_X86_64_64, | 724 | .type = relocation.encode(.abs, cpu_arch), |
| 1036 | .addend = A, | 725 | .addend = A, |
| 1037 | }); | 726 | }); |
| 1038 | try applyDynamicReloc(A, elf_file, writer); | 727 | try applyDynamicReloc(A, elf_file, writer); |
| ... | @@ -1041,7 +730,7 @@ fn resolveDynAbsReloc( | ... | @@ -1041,7 +730,7 @@ fn resolveDynAbsReloc( |
| 1041 | .baserel => { | 730 | .baserel => { |
| 1042 | elf_file.addRelaDynAssumeCapacity(.{ | 731 | elf_file.addRelaDynAssumeCapacity(.{ |
| 1043 | .offset = P, | 732 | .offset = P, |
| 1044 | .type = elf.R_X86_64_RELATIVE, | 733 | .type = relocation.encode(.rel, cpu_arch), |
| 1045 | .addend = S + A, | 734 | .addend = S + A, |
| 1046 | }); | 735 | }); |
| 1047 | try applyDynamicReloc(S + A, elf_file, writer); | 736 | try applyDynamicReloc(S + A, elf_file, writer); |
| ... | @@ -1051,7 +740,7 @@ fn resolveDynAbsReloc( | ... | @@ -1051,7 +740,7 @@ fn resolveDynAbsReloc( |
| 1051 | const S_ = @as(i64, @intCast(target.address(.{ .plt = false }, elf_file))); | 740 | const S_ = @as(i64, @intCast(target.address(.{ .plt = false }, elf_file))); |
| 1052 | elf_file.addRelaDynAssumeCapacity(.{ | 741 | elf_file.addRelaDynAssumeCapacity(.{ |
| 1053 | .offset = P, | 742 | .offset = P, |
| 1054 | .type = elf.R_X86_64_IRELATIVE, | 743 | .type = relocation.encode(.irel, cpu_arch), |
| 1055 | .addend = S_ + A, | 744 | .addend = S_ + A, |
| 1056 | }); | 745 | }); |
| 1057 | try applyDynamicReloc(S_ + A, elf_file, writer); | 746 | try applyDynamicReloc(S_ + A, elf_file, writer); |
| ... | @@ -1069,158 +758,12 @@ fn applyDynamicReloc(value: i64, elf_file: *Elf, writer: anytype) !void { | ... | @@ -1069,158 +758,12 @@ fn applyDynamicReloc(value: i64, elf_file: *Elf, writer: anytype) !void { |
| 1069 | pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void { | 758 | pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void { |
| 1070 | relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) }); | 759 | relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) }); |
| 1071 | 760 | ||
| 1072 | const file_ptr = self.file(elf_file).?; | 761 | switch (elf_file.getTarget().cpu.arch) { |
| 1073 | var stream = std.io.fixedBufferStream(code); | 762 | .x86_64 => try x86_64.resolveRelocsNonAlloc(self, elf_file, code, undefs), |
| 1074 | const cwriter = stream.writer(); | 763 | else => return error.UnsupportedCpuArch, |
| 1075 | |||
| 1076 | const rels = self.relocs(elf_file); | ||
| 1077 | var i: usize = 0; | ||
| 1078 | while (i < rels.len) : (i += 1) { | ||
| 1079 | const rel = rels[i]; | ||
| 1080 | const r_type = rel.r_type(); | ||
| 1081 | if (r_type == elf.R_X86_64_NONE) continue; | ||
| 1082 | |||
| 1083 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; | ||
| 1084 | |||
| 1085 | const target_index = switch (file_ptr) { | ||
| 1086 | .zig_object => |x| x.symbol(rel.r_sym()), | ||
| 1087 | .object => |x| x.symbols.items[rel.r_sym()], | ||
| 1088 | else => unreachable, | ||
| 1089 | }; | ||
| 1090 | const target = elf_file.symbol(target_index); | ||
| 1091 | |||
| 1092 | // Check for violation of One Definition Rule for COMDATs. | ||
| 1093 | if (target.file(elf_file) == null) { | ||
| 1094 | // TODO convert into an error | ||
| 1095 | log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ | ||
| 1096 | file_ptr.fmtPath(), | ||
| 1097 | self.name(elf_file), | ||
| 1098 | target.name(elf_file), | ||
| 1099 | }); | ||
| 1100 | continue; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | // Report an undefined symbol. | ||
| 1104 | try self.reportUndefined(elf_file, target, target_index, rel, undefs); | ||
| 1105 | |||
| 1106 | // We will use equation format to resolve relocations: | ||
| 1107 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ | ||
| 1108 | // | ||
| 1109 | const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset)); | ||
| 1110 | // Addend from the relocation. | ||
| 1111 | const A = rel.r_addend; | ||
| 1112 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. | ||
| 1113 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | ||
| 1114 | // Address of the global offset table. | ||
| 1115 | const GOT = blk: { | ||
| 1116 | const shndx = if (elf_file.got_plt_section_index) |shndx| | ||
| 1117 | shndx | ||
| 1118 | else if (elf_file.got_section_index) |shndx| | ||
| 1119 | shndx | ||
| 1120 | else | ||
| 1121 | null; | ||
| 1122 | break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0; | ||
| 1123 | }; | ||
| 1124 | // Address of the dynamic thread pointer. | ||
| 1125 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); | ||
| 1126 | |||
| 1127 | relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{ | ||
| 1128 | fmtRelocType(r_type), | ||
| 1129 | rel.r_offset, | ||
| 1130 | P, | ||
| 1131 | S + A, | ||
| 1132 | target.name(elf_file), | ||
| 1133 | }); | ||
| 1134 | |||
| 1135 | try stream.seekTo(r_offset); | ||
| 1136 | |||
| 1137 | switch (r_type) { | ||
| 1138 | elf.R_X86_64_NONE => unreachable, | ||
| 1139 | elf.R_X86_64_8 => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little), | ||
| 1140 | elf.R_X86_64_16 => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), | ||
| 1141 | elf.R_X86_64_32 => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), | ||
| 1142 | elf.R_X86_64_32S => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), | ||
| 1143 | elf.R_X86_64_64 => try cwriter.writeInt(i64, S + A, .little), | ||
| 1144 | elf.R_X86_64_DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), | ||
| 1145 | elf.R_X86_64_DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), | ||
| 1146 | elf.R_X86_64_GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little), | ||
| 1147 | elf.R_X86_64_GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), | ||
| 1148 | elf.R_X86_64_SIZE32 => { | ||
| 1149 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); | ||
| 1150 | try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A)))), .little); | ||
| 1151 | }, | ||
| 1152 | elf.R_X86_64_SIZE64 => { | ||
| 1153 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); | ||
| 1154 | try cwriter.writeInt(i64, @as(i64, @intCast(size + A)), .little); | ||
| 1155 | }, | ||
| 1156 | else => try self.reportUnhandledRelocError(rel, elf_file), | ||
| 1157 | } | ||
| 1158 | } | 764 | } |
| 1159 | } | 765 | } |
| 1160 | 766 | ||
| 1161 | pub fn fmtRelocType(r_type: u32) std.fmt.Formatter(formatRelocType) { | ||
| 1162 | return .{ .data = r_type }; | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | fn formatRelocType( | ||
| 1166 | r_type: u32, | ||
| 1167 | comptime unused_fmt_string: []const u8, | ||
| 1168 | options: std.fmt.FormatOptions, | ||
| 1169 | writer: anytype, | ||
| 1170 | ) !void { | ||
| 1171 | _ = unused_fmt_string; | ||
| 1172 | _ = options; | ||
| 1173 | const str = switch (r_type) { | ||
| 1174 | elf.R_X86_64_NONE => "R_X86_64_NONE", | ||
| 1175 | elf.R_X86_64_64 => "R_X86_64_64", | ||
| 1176 | elf.R_X86_64_PC32 => "R_X86_64_PC32", | ||
| 1177 | elf.R_X86_64_GOT32 => "R_X86_64_GOT32", | ||
| 1178 | elf.R_X86_64_PLT32 => "R_X86_64_PLT32", | ||
| 1179 | elf.R_X86_64_COPY => "R_X86_64_COPY", | ||
| 1180 | elf.R_X86_64_GLOB_DAT => "R_X86_64_GLOB_DAT", | ||
| 1181 | elf.R_X86_64_JUMP_SLOT => "R_X86_64_JUMP_SLOT", | ||
| 1182 | elf.R_X86_64_RELATIVE => "R_X86_64_RELATIVE", | ||
| 1183 | elf.R_X86_64_GOTPCREL => "R_X86_64_GOTPCREL", | ||
| 1184 | elf.R_X86_64_32 => "R_X86_64_32", | ||
| 1185 | elf.R_X86_64_32S => "R_X86_64_32S", | ||
| 1186 | elf.R_X86_64_16 => "R_X86_64_16", | ||
| 1187 | elf.R_X86_64_PC16 => "R_X86_64_PC16", | ||
| 1188 | elf.R_X86_64_8 => "R_X86_64_8", | ||
| 1189 | elf.R_X86_64_PC8 => "R_X86_64_PC8", | ||
| 1190 | elf.R_X86_64_DTPMOD64 => "R_X86_64_DTPMOD64", | ||
| 1191 | elf.R_X86_64_DTPOFF64 => "R_X86_64_DTPOFF64", | ||
| 1192 | elf.R_X86_64_TPOFF64 => "R_X86_64_TPOFF64", | ||
| 1193 | elf.R_X86_64_TLSGD => "R_X86_64_TLSGD", | ||
| 1194 | elf.R_X86_64_TLSLD => "R_X86_64_TLSLD", | ||
| 1195 | elf.R_X86_64_DTPOFF32 => "R_X86_64_DTPOFF32", | ||
| 1196 | elf.R_X86_64_GOTTPOFF => "R_X86_64_GOTTPOFF", | ||
| 1197 | elf.R_X86_64_TPOFF32 => "R_X86_64_TPOFF32", | ||
| 1198 | elf.R_X86_64_PC64 => "R_X86_64_PC64", | ||
| 1199 | elf.R_X86_64_GOTOFF64 => "R_X86_64_GOTOFF64", | ||
| 1200 | elf.R_X86_64_GOTPC32 => "R_X86_64_GOTPC32", | ||
| 1201 | elf.R_X86_64_GOT64 => "R_X86_64_GOT64", | ||
| 1202 | elf.R_X86_64_GOTPCREL64 => "R_X86_64_GOTPCREL64", | ||
| 1203 | elf.R_X86_64_GOTPC64 => "R_X86_64_GOTPC64", | ||
| 1204 | elf.R_X86_64_GOTPLT64 => "R_X86_64_GOTPLT64", | ||
| 1205 | elf.R_X86_64_PLTOFF64 => "R_X86_64_PLTOFF64", | ||
| 1206 | elf.R_X86_64_SIZE32 => "R_X86_64_SIZE32", | ||
| 1207 | elf.R_X86_64_SIZE64 => "R_X86_64_SIZE64", | ||
| 1208 | elf.R_X86_64_GOTPC32_TLSDESC => "R_X86_64_GOTPC32_TLSDESC", | ||
| 1209 | elf.R_X86_64_TLSDESC_CALL => "R_X86_64_TLSDESC_CALL", | ||
| 1210 | elf.R_X86_64_TLSDESC => "R_X86_64_TLSDESC", | ||
| 1211 | elf.R_X86_64_IRELATIVE => "R_X86_64_IRELATIVE", | ||
| 1212 | elf.R_X86_64_RELATIVE64 => "R_X86_64_RELATIVE64", | ||
| 1213 | elf.R_X86_64_GOTPCRELX => "R_X86_64_GOTPCRELX", | ||
| 1214 | elf.R_X86_64_REX_GOTPCRELX => "R_X86_64_REX_GOTPCRELX", | ||
| 1215 | elf.R_X86_64_NUM => "R_X86_64_NUM", | ||
| 1216 | // Zig custom relocations | ||
| 1217 | Elf.R_X86_64_ZIG_GOT32 => "R_X86_64_ZIG_GOT32", | ||
| 1218 | Elf.R_X86_64_ZIG_GOTPCREL => "R_X86_64_ZIG_GOTPCREL", | ||
| 1219 | else => "R_X86_64_UNKNOWN", | ||
| 1220 | }; | ||
| 1221 | try writer.print("{s}", .{str}); | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | pub fn format( | 767 | pub fn format( |
| 1225 | atom: Atom, | 768 | atom: Atom, |
| 1226 | comptime unused_fmt_string: []const u8, | 769 | comptime unused_fmt_string: []const u8, |
| ... | @@ -1285,7 +828,423 @@ pub const Flags = packed struct { | ... | @@ -1285,7 +828,423 @@ pub const Flags = packed struct { |
| 1285 | }; | 828 | }; |
| 1286 | 829 | ||
| 1287 | const x86_64 = struct { | 830 | const x86_64 = struct { |
| 1288 | pub fn relaxGotpcrelx(code: []u8) !void { | 831 | fn scanRelocs(atom: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void { |
| 832 | const is_static = elf_file.base.isStatic(); | ||
| 833 | const is_dyn_lib = elf_file.base.isDynLib(); | ||
| 834 | const file_ptr = atom.file(elf_file).?; | ||
| 835 | const rels = atom.relocs(elf_file); | ||
| 836 | var i: usize = 0; | ||
| 837 | while (i < rels.len) : (i += 1) { | ||
| 838 | const rel = rels[i]; | ||
| 839 | |||
| 840 | if (rel.r_type() == elf.R_X86_64_NONE) continue; | ||
| 841 | |||
| 842 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; | ||
| 843 | |||
| 844 | const symbol_index = switch (file_ptr) { | ||
| 845 | .zig_object => |x| x.symbol(rel.r_sym()), | ||
| 846 | .object => |x| x.symbols.items[rel.r_sym()], | ||
| 847 | else => unreachable, | ||
| 848 | }; | ||
| 849 | const symbol = elf_file.symbol(symbol_index); | ||
| 850 | |||
| 851 | // Check for violation of One Definition Rule for COMDATs. | ||
| 852 | if (symbol.file(elf_file) == null) { | ||
| 853 | // TODO convert into an error | ||
| 854 | log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ | ||
| 855 | file_ptr.fmtPath(), | ||
| 856 | atom.name(elf_file), | ||
| 857 | symbol.name(elf_file), | ||
| 858 | }); | ||
| 859 | continue; | ||
| 860 | } | ||
| 861 | |||
| 862 | // Report an undefined symbol. | ||
| 863 | try atom.reportUndefined(elf_file, symbol, symbol_index, rel, undefs); | ||
| 864 | |||
| 865 | if (symbol.isIFunc(elf_file)) { | ||
| 866 | symbol.flags.needs_got = true; | ||
| 867 | symbol.flags.needs_plt = true; | ||
| 868 | } | ||
| 869 | |||
| 870 | // While traversing relocations, mark symbols that require special handling such as | ||
| 871 | // pointer indirection via GOT, or a stub trampoline via PLT. | ||
| 872 | switch (rel.r_type()) { | ||
| 873 | elf.R_X86_64_64 => { | ||
| 874 | try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); | ||
| 875 | }, | ||
| 876 | |||
| 877 | elf.R_X86_64_32, | ||
| 878 | elf.R_X86_64_32S, | ||
| 879 | => { | ||
| 880 | try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); | ||
| 881 | }, | ||
| 882 | |||
| 883 | elf.R_X86_64_GOT32, | ||
| 884 | elf.R_X86_64_GOTPC32, | ||
| 885 | elf.R_X86_64_GOTPC64, | ||
| 886 | elf.R_X86_64_GOTPCREL, | ||
| 887 | elf.R_X86_64_GOTPCREL64, | ||
| 888 | elf.R_X86_64_GOTPCRELX, | ||
| 889 | elf.R_X86_64_REX_GOTPCRELX, | ||
| 890 | => { | ||
| 891 | symbol.flags.needs_got = true; | ||
| 892 | }, | ||
| 893 | |||
| 894 | elf.R_X86_64_PLT32, | ||
| 895 | elf.R_X86_64_PLTOFF64, | ||
| 896 | => { | ||
| 897 | if (symbol.flags.import) { | ||
| 898 | symbol.flags.needs_plt = true; | ||
| 899 | } | ||
| 900 | }, | ||
| 901 | |||
| 902 | elf.R_X86_64_PC32 => { | ||
| 903 | try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file); | ||
| 904 | }, | ||
| 905 | |||
| 906 | elf.R_X86_64_TLSGD => { | ||
| 907 | // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr | ||
| 908 | |||
| 909 | if (is_static or (!symbol.flags.import and !is_dyn_lib)) { | ||
| 910 | // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a | ||
| 911 | // We skip the next relocation. | ||
| 912 | i += 1; | ||
| 913 | } else if (!symbol.flags.import and is_dyn_lib) { | ||
| 914 | symbol.flags.needs_gottp = true; | ||
| 915 | i += 1; | ||
| 916 | } else { | ||
| 917 | symbol.flags.needs_tlsgd = true; | ||
| 918 | } | ||
| 919 | }, | ||
| 920 | |||
| 921 | elf.R_X86_64_TLSLD => { | ||
| 922 | // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr | ||
| 923 | |||
| 924 | if (is_static or !is_dyn_lib) { | ||
| 925 | // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a | ||
| 926 | // We skip the next relocation. | ||
| 927 | i += 1; | ||
| 928 | } else { | ||
| 929 | elf_file.got.flags.needs_tlsld = true; | ||
| 930 | } | ||
| 931 | }, | ||
| 932 | |||
| 933 | elf.R_X86_64_GOTTPOFF => { | ||
| 934 | const should_relax = blk: { | ||
| 935 | if (is_dyn_lib or symbol.flags.import) break :blk false; | ||
| 936 | if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..])) break :blk false; | ||
| 937 | break :blk true; | ||
| 938 | }; | ||
| 939 | if (!should_relax) { | ||
| 940 | symbol.flags.needs_gottp = true; | ||
| 941 | } | ||
| 942 | }, | ||
| 943 | |||
| 944 | elf.R_X86_64_GOTPC32_TLSDESC => { | ||
| 945 | const should_relax = is_static or (!is_dyn_lib and !symbol.flags.import); | ||
| 946 | if (!should_relax) { | ||
| 947 | symbol.flags.needs_tlsdesc = true; | ||
| 948 | } | ||
| 949 | }, | ||
| 950 | |||
| 951 | elf.R_X86_64_TPOFF32, | ||
| 952 | elf.R_X86_64_TPOFF64, | ||
| 953 | => { | ||
| 954 | if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file); | ||
| 955 | }, | ||
| 956 | |||
| 957 | elf.R_X86_64_GOTOFF64, | ||
| 958 | elf.R_X86_64_DTPOFF32, | ||
| 959 | elf.R_X86_64_DTPOFF64, | ||
| 960 | elf.R_X86_64_SIZE32, | ||
| 961 | elf.R_X86_64_SIZE64, | ||
| 962 | elf.R_X86_64_TLSDESC_CALL, | ||
| 963 | => {}, | ||
| 964 | |||
| 965 | // Zig custom relocations | ||
| 966 | Elf.R_X86_64_ZIG_GOT32, | ||
| 967 | Elf.R_X86_64_ZIG_GOTPCREL, | ||
| 968 | => { | ||
| 969 | assert(symbol.flags.has_zig_got); | ||
| 970 | }, | ||
| 971 | |||
| 972 | else => try atom.reportUnhandledRelocError(rel, elf_file), | ||
| 973 | } | ||
| 974 | } | ||
| 975 | } | ||
| 976 | |||
| 977 | fn resolveRelocsAlloc(atom: Atom, elf_file: *Elf, code: []u8) !void { | ||
| 978 | const file_ptr = atom.file(elf_file).?; | ||
| 979 | var stream = std.io.fixedBufferStream(code); | ||
| 980 | const cwriter = stream.writer(); | ||
| 981 | |||
| 982 | const rels = atom.relocs(elf_file); | ||
| 983 | var i: usize = 0; | ||
| 984 | while (i < rels.len) : (i += 1) { | ||
| 985 | const rel = rels[i]; | ||
| 986 | const r_type = rel.r_type(); | ||
| 987 | if (r_type == elf.R_X86_64_NONE) continue; | ||
| 988 | |||
| 989 | const target = switch (file_ptr) { | ||
| 990 | .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())), | ||
| 991 | .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]), | ||
| 992 | else => unreachable, | ||
| 993 | }; | ||
| 994 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; | ||
| 995 | |||
| 996 | // We will use equation format to resolve relocations: | ||
| 997 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ | ||
| 998 | // | ||
| 999 | // Address of the source atom. | ||
| 1000 | const P = @as(i64, @intCast(atom.address(elf_file) + rel.r_offset)); | ||
| 1001 | // Addend from the relocation. | ||
| 1002 | const A = rel.r_addend; | ||
| 1003 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. | ||
| 1004 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | ||
| 1005 | // Address of the global offset table. | ||
| 1006 | const GOT = blk: { | ||
| 1007 | const shndx = if (elf_file.got_plt_section_index) |shndx| | ||
| 1008 | shndx | ||
| 1009 | else if (elf_file.got_section_index) |shndx| | ||
| 1010 | shndx | ||
| 1011 | else | ||
| 1012 | null; | ||
| 1013 | break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0; | ||
| 1014 | }; | ||
| 1015 | // Address of the .zig.got table entry if any. | ||
| 1016 | const ZIG_GOT = @as(i64, @intCast(target.zigGotAddress(elf_file))); | ||
| 1017 | // Relative offset to the start of the global offset table. | ||
| 1018 | const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT; | ||
| 1019 | // // Address of the thread pointer. | ||
| 1020 | const TP = @as(i64, @intCast(elf_file.tpAddress())); | ||
| 1021 | // Address of the dynamic thread pointer. | ||
| 1022 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); | ||
| 1023 | |||
| 1024 | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{ | ||
| 1025 | relocation.fmtRelocType(r_type, .x86_64), | ||
| 1026 | r_offset, | ||
| 1027 | P, | ||
| 1028 | S + A, | ||
| 1029 | G + GOT + A, | ||
| 1030 | ZIG_GOT + A, | ||
| 1031 | target.name(elf_file), | ||
| 1032 | }); | ||
| 1033 | |||
| 1034 | try stream.seekTo(r_offset); | ||
| 1035 | |||
| 1036 | switch (rel.r_type()) { | ||
| 1037 | elf.R_X86_64_NONE => unreachable, | ||
| 1038 | |||
| 1039 | elf.R_X86_64_64 => { | ||
| 1040 | try atom.resolveDynAbsReloc( | ||
| 1041 | target, | ||
| 1042 | rel, | ||
| 1043 | dynAbsRelocAction(target, elf_file), | ||
| 1044 | elf_file, | ||
| 1045 | cwriter, | ||
| 1046 | ); | ||
| 1047 | }, | ||
| 1048 | |||
| 1049 | elf.R_X86_64_PLT32, | ||
| 1050 | elf.R_X86_64_PC32, | ||
| 1051 | => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), | ||
| 1052 | |||
| 1053 | elf.R_X86_64_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little), | ||
| 1054 | elf.R_X86_64_GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), | ||
| 1055 | elf.R_X86_64_GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little), | ||
| 1056 | |||
| 1057 | elf.R_X86_64_GOTPCRELX => { | ||
| 1058 | if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { | ||
| 1059 | x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk; | ||
| 1060 | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); | ||
| 1061 | continue; | ||
| 1062 | } | ||
| 1063 | try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); | ||
| 1064 | }, | ||
| 1065 | |||
| 1066 | elf.R_X86_64_REX_GOTPCRELX => { | ||
| 1067 | if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { | ||
| 1068 | x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk; | ||
| 1069 | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); | ||
| 1070 | continue; | ||
| 1071 | } | ||
| 1072 | try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); | ||
| 1073 | }, | ||
| 1074 | |||
| 1075 | elf.R_X86_64_32 => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little), | ||
| 1076 | elf.R_X86_64_32S => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little), | ||
| 1077 | |||
| 1078 | elf.R_X86_64_TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little), | ||
| 1079 | elf.R_X86_64_TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little), | ||
| 1080 | |||
| 1081 | elf.R_X86_64_DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little), | ||
| 1082 | elf.R_X86_64_DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), | ||
| 1083 | |||
| 1084 | elf.R_X86_64_TLSGD => { | ||
| 1085 | if (target.flags.has_tlsgd) { | ||
| 1086 | const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file))); | ||
| 1087 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | ||
| 1088 | } else if (target.flags.has_gottp) { | ||
| 1089 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); | ||
| 1090 | try x86_64.relaxTlsGdToIe(atom, rels[i .. i + 2], @intCast(S_ - P), elf_file, &stream); | ||
| 1091 | i += 1; | ||
| 1092 | } else { | ||
| 1093 | try x86_64.relaxTlsGdToLe( | ||
| 1094 | atom, | ||
| 1095 | rels[i .. i + 2], | ||
| 1096 | @as(i32, @intCast(S - TP)), | ||
| 1097 | elf_file, | ||
| 1098 | &stream, | ||
| 1099 | ); | ||
| 1100 | i += 1; | ||
| 1101 | } | ||
| 1102 | }, | ||
| 1103 | |||
| 1104 | elf.R_X86_64_TLSLD => { | ||
| 1105 | if (elf_file.got.tlsld_index) |entry_index| { | ||
| 1106 | const tlsld_entry = elf_file.got.entries.items[entry_index]; | ||
| 1107 | const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file))); | ||
| 1108 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | ||
| 1109 | } else { | ||
| 1110 | try x86_64.relaxTlsLdToLe( | ||
| 1111 | atom, | ||
| 1112 | rels[i .. i + 2], | ||
| 1113 | @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))), | ||
| 1114 | elf_file, | ||
| 1115 | &stream, | ||
| 1116 | ); | ||
| 1117 | i += 1; | ||
| 1118 | } | ||
| 1119 | }, | ||
| 1120 | |||
| 1121 | elf.R_X86_64_GOTPC32_TLSDESC => { | ||
| 1122 | if (target.flags.has_tlsdesc) { | ||
| 1123 | const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file))); | ||
| 1124 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | ||
| 1125 | } else { | ||
| 1126 | try x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]); | ||
| 1127 | try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); | ||
| 1128 | } | ||
| 1129 | }, | ||
| 1130 | |||
| 1131 | elf.R_X86_64_TLSDESC_CALL => if (!target.flags.has_tlsdesc) { | ||
| 1132 | // call -> nop | ||
| 1133 | try cwriter.writeAll(&.{ 0x66, 0x90 }); | ||
| 1134 | }, | ||
| 1135 | |||
| 1136 | elf.R_X86_64_GOTTPOFF => { | ||
| 1137 | if (target.flags.has_gottp) { | ||
| 1138 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); | ||
| 1139 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); | ||
| 1140 | } else { | ||
| 1141 | x86_64.relaxGotTpOff(code[r_offset - 3 ..]) catch unreachable; | ||
| 1142 | try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); | ||
| 1143 | } | ||
| 1144 | }, | ||
| 1145 | |||
| 1146 | elf.R_X86_64_GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little), | ||
| 1147 | |||
| 1148 | // Zig custom relocations | ||
| 1149 | Elf.R_X86_64_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little), | ||
| 1150 | Elf.R_X86_64_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little), | ||
| 1151 | |||
| 1152 | else => {}, | ||
| 1153 | } | ||
| 1154 | } | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | fn resolveRelocsNonAlloc(atom: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void { | ||
| 1158 | const file_ptr = atom.file(elf_file).?; | ||
| 1159 | var stream = std.io.fixedBufferStream(code); | ||
| 1160 | const cwriter = stream.writer(); | ||
| 1161 | |||
| 1162 | const rels = atom.relocs(elf_file); | ||
| 1163 | var i: usize = 0; | ||
| 1164 | while (i < rels.len) : (i += 1) { | ||
| 1165 | const rel = rels[i]; | ||
| 1166 | const r_type = rel.r_type(); | ||
| 1167 | if (r_type == elf.R_X86_64_NONE) continue; | ||
| 1168 | |||
| 1169 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; | ||
| 1170 | |||
| 1171 | const target_index = switch (file_ptr) { | ||
| 1172 | .zig_object => |x| x.symbol(rel.r_sym()), | ||
| 1173 | .object => |x| x.symbols.items[rel.r_sym()], | ||
| 1174 | else => unreachable, | ||
| 1175 | }; | ||
| 1176 | const target = elf_file.symbol(target_index); | ||
| 1177 | |||
| 1178 | // Check for violation of One Definition Rule for COMDATs. | ||
| 1179 | if (target.file(elf_file) == null) { | ||
| 1180 | // TODO convert into an error | ||
| 1181 | log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ | ||
| 1182 | file_ptr.fmtPath(), | ||
| 1183 | atom.name(elf_file), | ||
| 1184 | target.name(elf_file), | ||
| 1185 | }); | ||
| 1186 | continue; | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | // Report an undefined symbol. | ||
| 1190 | try atom.reportUndefined(elf_file, target, target_index, rel, undefs); | ||
| 1191 | |||
| 1192 | // We will use equation format to resolve relocations: | ||
| 1193 | // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ | ||
| 1194 | // | ||
| 1195 | const P = @as(i64, @intCast(atom.address(elf_file) + rel.r_offset)); | ||
| 1196 | // Addend from the relocation. | ||
| 1197 | const A = rel.r_addend; | ||
| 1198 | // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub. | ||
| 1199 | const S = @as(i64, @intCast(target.address(.{}, elf_file))); | ||
| 1200 | // Address of the global offset table. | ||
| 1201 | const GOT = blk: { | ||
| 1202 | const shndx = if (elf_file.got_plt_section_index) |shndx| | ||
| 1203 | shndx | ||
| 1204 | else if (elf_file.got_section_index) |shndx| | ||
| 1205 | shndx | ||
| 1206 | else | ||
| 1207 | null; | ||
| 1208 | break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0; | ||
| 1209 | }; | ||
| 1210 | // Address of the dynamic thread pointer. | ||
| 1211 | const DTP = @as(i64, @intCast(elf_file.dtpAddress())); | ||
| 1212 | |||
| 1213 | relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{ | ||
| 1214 | relocation.fmtRelocType(r_type, .x86_64), | ||
| 1215 | rel.r_offset, | ||
| 1216 | P, | ||
| 1217 | S + A, | ||
| 1218 | target.name(elf_file), | ||
| 1219 | }); | ||
| 1220 | |||
| 1221 | try stream.seekTo(r_offset); | ||
| 1222 | |||
| 1223 | switch (r_type) { | ||
| 1224 | elf.R_X86_64_NONE => unreachable, | ||
| 1225 | elf.R_X86_64_8 => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little), | ||
| 1226 | elf.R_X86_64_16 => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), | ||
| 1227 | elf.R_X86_64_32 => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), | ||
| 1228 | elf.R_X86_64_32S => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), | ||
| 1229 | elf.R_X86_64_64 => try cwriter.writeInt(i64, S + A, .little), | ||
| 1230 | elf.R_X86_64_DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), | ||
| 1231 | elf.R_X86_64_DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), | ||
| 1232 | elf.R_X86_64_GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little), | ||
| 1233 | elf.R_X86_64_GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), | ||
| 1234 | elf.R_X86_64_SIZE32 => { | ||
| 1235 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); | ||
| 1236 | try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A)))), .little); | ||
| 1237 | }, | ||
| 1238 | elf.R_X86_64_SIZE64 => { | ||
| 1239 | const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); | ||
| 1240 | try cwriter.writeInt(i64, @as(i64, @intCast(size + A)), .little); | ||
| 1241 | }, | ||
| 1242 | else => try atom.reportUnhandledRelocError(rel, elf_file), | ||
| 1243 | } | ||
| 1244 | } | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | fn relaxGotpcrelx(code: []u8) !void { | ||
| 1289 | const old_inst = disassemble(code) orelse return error.RelaxFail; | 1248 | const old_inst = disassemble(code) orelse return error.RelaxFail; |
| 1290 | const inst = switch (old_inst.encoding.mnemonic) { | 1249 | const inst = switch (old_inst.encoding.mnemonic) { |
| 1291 | .call => try Instruction.new(old_inst.prefix, .call, &.{ | 1250 | .call => try Instruction.new(old_inst.prefix, .call, &.{ |
| ... | @@ -1303,7 +1262,7 @@ const x86_64 = struct { | ... | @@ -1303,7 +1262,7 @@ const x86_64 = struct { |
| 1303 | encode(&.{ nop, inst }, code) catch return error.RelaxFail; | 1262 | encode(&.{ nop, inst }, code) catch return error.RelaxFail; |
| 1304 | } | 1263 | } |
| 1305 | 1264 | ||
| 1306 | pub fn relaxRexGotpcrelx(code: []u8) !void { | 1265 | fn relaxRexGotpcrelx(code: []u8) !void { |
| 1307 | const old_inst = disassemble(code) orelse return error.RelaxFail; | 1266 | const old_inst = disassemble(code) orelse return error.RelaxFail; |
| 1308 | switch (old_inst.encoding.mnemonic) { | 1267 | switch (old_inst.encoding.mnemonic) { |
| 1309 | .mov => { | 1268 | .mov => { |
| ... | @@ -1315,7 +1274,7 @@ const x86_64 = struct { | ... | @@ -1315,7 +1274,7 @@ const x86_64 = struct { |
| 1315 | } | 1274 | } |
| 1316 | } | 1275 | } |
| 1317 | 1276 | ||
| 1318 | pub fn relaxTlsGdToIe( | 1277 | fn relaxTlsGdToIe( |
| 1319 | self: Atom, | 1278 | self: Atom, |
| 1320 | rels: []align(1) const elf.Elf64_Rela, | 1279 | rels: []align(1) const elf.Elf64_Rela, |
| 1321 | value: i32, | 1280 | value: i32, |
| ... | @@ -1340,8 +1299,8 @@ const x86_64 = struct { | ... | @@ -1340,8 +1299,8 @@ const x86_64 = struct { |
| 1340 | else => { | 1299 | else => { |
| 1341 | var err = try elf_file.addErrorWithNotes(1); | 1300 | var err = try elf_file.addErrorWithNotes(1); |
| 1342 | try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{ | 1301 | try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{ |
| 1343 | fmtRelocType(rels[0].r_type()), | 1302 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1344 | fmtRelocType(rels[1].r_type()), | 1303 | relocation.fmtRelocType(rels[1].r_type(), .x86_64), |
| 1345 | }); | 1304 | }); |
| 1346 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ | 1305 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ |
| 1347 | self.file(elf_file).?.fmtPath(), | 1306 | self.file(elf_file).?.fmtPath(), |
| ... | @@ -1352,7 +1311,7 @@ const x86_64 = struct { | ... | @@ -1352,7 +1311,7 @@ const x86_64 = struct { |
| 1352 | } | 1311 | } |
| 1353 | } | 1312 | } |
| 1354 | 1313 | ||
| 1355 | pub fn relaxTlsLdToLe( | 1314 | fn relaxTlsLdToLe( |
| 1356 | self: Atom, | 1315 | self: Atom, |
| 1357 | rels: []align(1) const elf.Elf64_Rela, | 1316 | rels: []align(1) const elf.Elf64_Rela, |
| 1358 | value: i32, | 1317 | value: i32, |
| ... | @@ -1392,8 +1351,8 @@ const x86_64 = struct { | ... | @@ -1392,8 +1351,8 @@ const x86_64 = struct { |
| 1392 | else => { | 1351 | else => { |
| 1393 | var err = try elf_file.addErrorWithNotes(1); | 1352 | var err = try elf_file.addErrorWithNotes(1); |
| 1394 | try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{ | 1353 | try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{ |
| 1395 | fmtRelocType(rels[0].r_type()), | 1354 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1396 | fmtRelocType(rels[1].r_type()), | 1355 | relocation.fmtRelocType(rels[1].r_type(), .x86_64), |
| 1397 | }); | 1356 | }); |
| 1398 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ | 1357 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ |
| 1399 | self.file(elf_file).?.fmtPath(), | 1358 | self.file(elf_file).?.fmtPath(), |
| ... | @@ -1404,7 +1363,7 @@ const x86_64 = struct { | ... | @@ -1404,7 +1363,7 @@ const x86_64 = struct { |
| 1404 | } | 1363 | } |
| 1405 | } | 1364 | } |
| 1406 | 1365 | ||
| 1407 | pub fn canRelaxGotTpOff(code: []const u8) bool { | 1366 | fn canRelaxGotTpOff(code: []const u8) bool { |
| 1408 | const old_inst = disassemble(code) orelse return false; | 1367 | const old_inst = disassemble(code) orelse return false; |
| 1409 | switch (old_inst.encoding.mnemonic) { | 1368 | switch (old_inst.encoding.mnemonic) { |
| 1410 | .mov => if (Instruction.new(old_inst.prefix, .mov, &.{ | 1369 | .mov => if (Instruction.new(old_inst.prefix, .mov, &.{ |
| ... | @@ -1419,7 +1378,7 @@ const x86_64 = struct { | ... | @@ -1419,7 +1378,7 @@ const x86_64 = struct { |
| 1419 | } | 1378 | } |
| 1420 | } | 1379 | } |
| 1421 | 1380 | ||
| 1422 | pub fn relaxGotTpOff(code: []u8) !void { | 1381 | fn relaxGotTpOff(code: []u8) !void { |
| 1423 | const old_inst = disassemble(code) orelse return error.RelaxFail; | 1382 | const old_inst = disassemble(code) orelse return error.RelaxFail; |
| 1424 | switch (old_inst.encoding.mnemonic) { | 1383 | switch (old_inst.encoding.mnemonic) { |
| 1425 | .mov => { | 1384 | .mov => { |
| ... | @@ -1435,7 +1394,7 @@ const x86_64 = struct { | ... | @@ -1435,7 +1394,7 @@ const x86_64 = struct { |
| 1435 | } | 1394 | } |
| 1436 | } | 1395 | } |
| 1437 | 1396 | ||
| 1438 | pub fn relaxGotPcTlsDesc(code: []u8) !void { | 1397 | fn relaxGotPcTlsDesc(code: []u8) !void { |
| 1439 | const old_inst = disassemble(code) orelse return error.RelaxFail; | 1398 | const old_inst = disassemble(code) orelse return error.RelaxFail; |
| 1440 | switch (old_inst.encoding.mnemonic) { | 1399 | switch (old_inst.encoding.mnemonic) { |
| 1441 | .lea => { | 1400 | .lea => { |
| ... | @@ -1451,7 +1410,7 @@ const x86_64 = struct { | ... | @@ -1451,7 +1410,7 @@ const x86_64 = struct { |
| 1451 | } | 1410 | } |
| 1452 | } | 1411 | } |
| 1453 | 1412 | ||
| 1454 | pub fn relaxTlsGdToLe( | 1413 | fn relaxTlsGdToLe( |
| 1455 | self: Atom, | 1414 | self: Atom, |
| 1456 | rels: []align(1) const elf.Elf64_Rela, | 1415 | rels: []align(1) const elf.Elf64_Rela, |
| 1457 | value: i32, | 1416 | value: i32, |
| ... | @@ -1474,16 +1433,16 @@ const x86_64 = struct { | ... | @@ -1474,16 +1433,16 @@ const x86_64 = struct { |
| 1474 | try stream.seekBy(-4); | 1433 | try stream.seekBy(-4); |
| 1475 | try writer.writeAll(&insts); | 1434 | try writer.writeAll(&insts); |
| 1476 | relocs_log.debug(" relaxing {} and {}", .{ | 1435 | relocs_log.debug(" relaxing {} and {}", .{ |
| 1477 | fmtRelocType(rels[0].r_type()), | 1436 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1478 | fmtRelocType(rels[1].r_type()), | 1437 | relocation.fmtRelocType(rels[1].r_type(), .x86_64), |
| 1479 | }); | 1438 | }); |
| 1480 | }, | 1439 | }, |
| 1481 | 1440 | ||
| 1482 | else => { | 1441 | else => { |
| 1483 | var err = try elf_file.addErrorWithNotes(1); | 1442 | var err = try elf_file.addErrorWithNotes(1); |
| 1484 | try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{ | 1443 | try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{ |
| 1485 | fmtRelocType(rels[0].r_type()), | 1444 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1486 | fmtRelocType(rels[1].r_type()), | 1445 | relocation.fmtRelocType(rels[1].r_type(), .x86_64), |
| 1487 | }); | 1446 | }); |
| 1488 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ | 1447 | try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ |
| 1489 | self.file(elf_file).?.fmtPath(), | 1448 | self.file(elf_file).?.fmtPath(), |
| ... | @@ -1521,6 +1480,7 @@ const elf = std.elf; | ... | @@ -1521,6 +1480,7 @@ const elf = std.elf; |
| 1521 | const eh_frame = @import("eh_frame.zig"); | 1480 | const eh_frame = @import("eh_frame.zig"); |
| 1522 | const log = std.log.scoped(.link); | 1481 | const log = std.log.scoped(.link); |
| 1523 | const relocs_log = std.log.scoped(.link_relocs); | 1482 | const relocs_log = std.log.scoped(.link_relocs); |
| 1483 | const relocation = @import("relocation.zig"); | ||
| 1524 | 1484 | ||
| 1525 | const Allocator = std.mem.Allocator; | 1485 | const Allocator = std.mem.Allocator; |
| 1526 | const Atom = @This(); | 1486 | const Atom = @This(); |
src/link/Elf/Object.zig+23-13| ... | @@ -55,6 +55,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { | ... | @@ -55,6 +55,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 55 | 55 | ||
| 56 | pub fn parse(self: *Object, elf_file: *Elf) !void { | 56 | pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 57 | const gpa = elf_file.base.comp.gpa; | 57 | const gpa = elf_file.base.comp.gpa; |
| 58 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 58 | const handle = elf_file.fileHandle(self.file_handle); | 59 | const handle = elf_file.fileHandle(self.file_handle); |
| 59 | 60 | ||
| 60 | try self.parseCommon(gpa, handle, elf_file); | 61 | try self.parseCommon(gpa, handle, elf_file); |
| ... | @@ -64,8 +65,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { | ... | @@ -64,8 +65,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 64 | for (self.shdrs.items, 0..) |shdr, i| { | 65 | for (self.shdrs.items, 0..) |shdr, i| { |
| 65 | const atom = elf_file.atom(self.atoms.items[i]) orelse continue; | 66 | const atom = elf_file.atom(self.atoms.items[i]) orelse continue; |
| 66 | if (!atom.flags.alive) continue; | 67 | if (!atom.flags.alive) continue; |
| 67 | if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame")) | 68 | if ((cpu_arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or |
| 69 | mem.eql(u8, atom.name(elf_file), ".eh_frame")) | ||
| 70 | { | ||
| 68 | try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file); | 71 | try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file); |
| 72 | } | ||
| 69 | } | 73 | } |
| 70 | } | 74 | } |
| 71 | 75 | ||
| ... | @@ -286,17 +290,22 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O | ... | @@ -286,17 +290,22 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O |
| 286 | } | 290 | } |
| 287 | break :blk name; | 291 | break :blk name; |
| 288 | }; | 292 | }; |
| 289 | const @"type" = switch (shdr.sh_type) { | 293 | const @"type" = tt: { |
| 290 | elf.SHT_NULL => unreachable, | 294 | if (elf_file.getTarget().cpu.arch == .x86_64 and |
| 291 | elf.SHT_PROGBITS => blk: { | 295 | shdr.sh_type == elf.SHT_X86_64_UNWIND) break :tt elf.SHT_PROGBITS; |
| 292 | if (std.mem.eql(u8, name, ".init_array") or std.mem.startsWith(u8, name, ".init_array.")) | 296 | |
| 293 | break :blk elf.SHT_INIT_ARRAY; | 297 | const @"type" = switch (shdr.sh_type) { |
| 294 | if (std.mem.eql(u8, name, ".fini_array") or std.mem.startsWith(u8, name, ".fini_array.")) | 298 | elf.SHT_NULL => unreachable, |
| 295 | break :blk elf.SHT_FINI_ARRAY; | 299 | elf.SHT_PROGBITS => blk: { |
| 296 | break :blk shdr.sh_type; | 300 | if (std.mem.eql(u8, name, ".init_array") or std.mem.startsWith(u8, name, ".init_array.")) |
| 297 | }, | 301 | break :blk elf.SHT_INIT_ARRAY; |
| 298 | elf.SHT_X86_64_UNWIND => elf.SHT_PROGBITS, | 302 | if (std.mem.eql(u8, name, ".fini_array") or std.mem.startsWith(u8, name, ".fini_array.")) |
| 299 | else => shdr.sh_type, | 303 | break :blk elf.SHT_FINI_ARRAY; |
| 304 | break :blk shdr.sh_type; | ||
| 305 | }, | ||
| 306 | else => shdr.sh_type, | ||
| 307 | }; | ||
| 308 | break :tt @"type"; | ||
| 300 | }; | 309 | }; |
| 301 | const flags = blk: { | 310 | const flags = blk: { |
| 302 | var flags = shdr.sh_flags; | 311 | var flags = shdr.sh_flags; |
| ... | @@ -596,9 +605,10 @@ pub fn markLive(self: *Object, elf_file: *Elf) void { | ... | @@ -596,9 +605,10 @@ pub fn markLive(self: *Object, elf_file: *Elf) void { |
| 596 | } | 605 | } |
| 597 | 606 | ||
| 598 | pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void { | 607 | pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void { |
| 608 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 599 | for (self.atoms.items) |atom_index| { | 609 | for (self.atoms.items) |atom_index| { |
| 600 | const atom = elf_file.atom(atom_index) orelse continue; | 610 | const atom = elf_file.atom(atom_index) orelse continue; |
| 601 | const is_eh_frame = atom.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND or | 611 | const is_eh_frame = (cpu_arch == .x86_64 and atom.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or |
| 602 | mem.eql(u8, atom.name(elf_file), ".eh_frame"); | 612 | mem.eql(u8, atom.name(elf_file), ".eh_frame"); |
| 603 | if (atom.flags.alive and is_eh_frame) atom.flags.alive = false; | 613 | if (atom.flags.alive and is_eh_frame) atom.flags.alive = false; |
| 604 | } | 614 | } |
src/link/Elf/ZigObject.zig+5-2| ... | @@ -653,9 +653,10 @@ pub fn getDeclVAddr( | ... | @@ -653,9 +653,10 @@ pub fn getDeclVAddr( |
| 653 | const this_sym = elf_file.symbol(this_sym_index); | 653 | const this_sym = elf_file.symbol(this_sym_index); |
| 654 | const vaddr = this_sym.address(.{}, elf_file); | 654 | const vaddr = this_sym.address(.{}, elf_file); |
| 655 | const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?; | 655 | const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?; |
| 656 | const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); | ||
| 656 | try parent_atom.addReloc(elf_file, .{ | 657 | try parent_atom.addReloc(elf_file, .{ |
| 657 | .r_offset = reloc_info.offset, | 658 | .r_offset = reloc_info.offset, |
| 658 | .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64, | 659 | .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type, |
| 659 | .r_addend = reloc_info.addend, | 660 | .r_addend = reloc_info.addend, |
| 660 | }); | 661 | }); |
| 661 | return vaddr; | 662 | return vaddr; |
| ... | @@ -671,9 +672,10 @@ pub fn getAnonDeclVAddr( | ... | @@ -671,9 +672,10 @@ pub fn getAnonDeclVAddr( |
| 671 | const sym = elf_file.symbol(sym_index); | 672 | const sym = elf_file.symbol(sym_index); |
| 672 | const vaddr = sym.address(.{}, elf_file); | 673 | const vaddr = sym.address(.{}, elf_file); |
| 673 | const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?; | 674 | const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?; |
| 675 | const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); | ||
| 674 | try parent_atom.addReloc(elf_file, .{ | 676 | try parent_atom.addReloc(elf_file, .{ |
| 675 | .r_offset = reloc_info.offset, | 677 | .r_offset = reloc_info.offset, |
| 676 | .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | elf.R_X86_64_64, | 678 | .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type, |
| 677 | .r_addend = reloc_info.addend, | 679 | .r_addend = reloc_info.addend, |
| 678 | }); | 680 | }); |
| 679 | return vaddr; | 681 | return vaddr; |
| ... | @@ -1636,6 +1638,7 @@ const elf = std.elf; | ... | @@ -1636,6 +1638,7 @@ const elf = std.elf; |
| 1636 | const link = @import("../../link.zig"); | 1638 | const link = @import("../../link.zig"); |
| 1637 | const log = std.log.scoped(.link); | 1639 | const log = std.log.scoped(.link); |
| 1638 | const mem = std.mem; | 1640 | const mem = std.mem; |
| 1641 | const relocation = @import("relocation.zig"); | ||
| 1639 | const trace = @import("../../tracy.zig").trace; | 1642 | const trace = @import("../../tracy.zig").trace; |
| 1640 | const std = @import("std"); | 1643 | const std = @import("std"); |
| 1641 | 1644 |
src/link/Elf/eh_frame.zig+23-11| ... | @@ -302,26 +302,23 @@ pub fn calcEhFrameRelocs(elf_file: *Elf) usize { | ... | @@ -302,26 +302,23 @@ pub fn calcEhFrameRelocs(elf_file: *Elf) usize { |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void { | 304 | fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void { |
| 305 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 305 | const offset = std.math.cast(usize, rel.r_offset - rec.offset) orelse return error.Overflow; | 306 | const offset = std.math.cast(usize, rel.r_offset - rec.offset) orelse return error.Overflow; |
| 306 | const P = @as(i64, @intCast(rec.address(elf_file) + offset)); | 307 | const P = math.cast(i64, rec.address(elf_file) + offset) orelse return error.Overflow; |
| 307 | const S = @as(i64, @intCast(sym.address(.{}, elf_file))); | 308 | const S = math.cast(i64, sym.address(.{}, elf_file)) orelse return error.Overflow; |
| 308 | const A = rel.r_addend; | 309 | const A = rel.r_addend; |
| 309 | 310 | ||
| 310 | relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{ | 311 | relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{ |
| 311 | Atom.fmtRelocType(rel.r_type()), | 312 | relocation.fmtRelocType(rel.r_type(), cpu_arch), |
| 312 | offset, | 313 | offset, |
| 313 | P, | 314 | P, |
| 314 | S + A, | 315 | S + A, |
| 315 | sym.name(elf_file), | 316 | sym.name(elf_file), |
| 316 | }); | 317 | }); |
| 317 | 318 | ||
| 318 | var where = contents[offset..]; | 319 | switch (cpu_arch) { |
| 319 | switch (rel.r_type()) { | 320 | .x86_64 => x86_64.resolveReloc(rel, P, S + A, contents[offset..]), |
| 320 | elf.R_X86_64_32 => std.mem.writeInt(i32, where[0..4], @as(i32, @truncate(S + A)), .little), | 321 | else => return error.UnsupportedCpuArch, |
| 321 | elf.R_X86_64_64 => std.mem.writeInt(i64, where[0..8], S + A, .little), | ||
| 322 | elf.R_X86_64_PC32 => std.mem.writeInt(i32, where[0..4], @as(i32, @intCast(S - P + A)), .little), | ||
| 323 | elf.R_X86_64_PC64 => std.mem.writeInt(i64, where[0..8], S - P + A, .little), | ||
| 324 | else => unreachable, | ||
| 325 | } | 322 | } |
| 326 | } | 323 | } |
| 327 | 324 | ||
| ... | @@ -403,6 +400,7 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { | ... | @@ -403,6 +400,7 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { |
| 403 | } | 400 | } |
| 404 | 401 | ||
| 405 | fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { | 402 | fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { |
| 403 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 406 | const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset; | 404 | const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset; |
| 407 | const r_type = rel.r_type(); | 405 | const r_type = rel.r_type(); |
| 408 | var r_addend = rel.r_addend; | 406 | var r_addend = rel.r_addend; |
| ... | @@ -418,7 +416,7 @@ fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Re | ... | @@ -418,7 +416,7 @@ fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Re |
| 418 | } | 416 | } |
| 419 | 417 | ||
| 420 | relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ | 418 | relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ |
| 421 | Atom.fmtRelocType(r_type), | 419 | relocation.fmtRelocType(r_type, cpu_arch), |
| 422 | r_offset, | 420 | r_offset, |
| 423 | r_sym, | 421 | r_sym, |
| 424 | sym.name(elf_file), | 422 | sym.name(elf_file), |
| ... | @@ -541,10 +539,24 @@ const EH_PE = struct { | ... | @@ -541,10 +539,24 @@ const EH_PE = struct { |
| 541 | pub const omit = 0xFF; | 539 | pub const omit = 0xFF; |
| 542 | }; | 540 | }; |
| 543 | 541 | ||
| 542 | const x86_64 = struct { | ||
| 543 | fn resolveReloc(rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) void { | ||
| 544 | switch (rel.r_type()) { | ||
| 545 | elf.R_X86_64_32 => std.mem.writeInt(i32, data[0..4], @as(i32, @truncate(target)), .little), | ||
| 546 | elf.R_X86_64_64 => std.mem.writeInt(i64, data[0..8], target, .little), | ||
| 547 | elf.R_X86_64_PC32 => std.mem.writeInt(i32, data[0..4], @as(i32, @intCast(target - source)), .little), | ||
| 548 | elf.R_X86_64_PC64 => std.mem.writeInt(i64, data[0..8], target - source, .little), | ||
| 549 | else => unreachable, | ||
| 550 | } | ||
| 551 | } | ||
| 552 | }; | ||
| 553 | |||
| 544 | const std = @import("std"); | 554 | const std = @import("std"); |
| 545 | const assert = std.debug.assert; | 555 | const assert = std.debug.assert; |
| 546 | const elf = std.elf; | 556 | const elf = std.elf; |
| 557 | const math = std.math; | ||
| 547 | const relocs_log = std.log.scoped(.link_relocs); | 558 | const relocs_log = std.log.scoped(.link_relocs); |
| 559 | const relocation = @import("relocation.zig"); | ||
| 548 | 560 | ||
| 549 | const Allocator = std.mem.Allocator; | 561 | const Allocator = std.mem.Allocator; |
| 550 | const Atom = @import("Atom.zig"); | 562 | const Atom = @import("Atom.zig"); |
src/link/Elf/file.zig+7| ... | @@ -91,6 +91,13 @@ pub const File = union(enum) { | ... | @@ -91,6 +91,13 @@ pub const File = union(enum) { |
| 91 | } | 91 | } |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | pub fn scanRelocs(file: File, elf_file: *Elf, undefs: anytype) !void { | ||
| 95 | switch (file) { | ||
| 96 | .linker_defined, .shared_object => unreachable, | ||
| 97 | inline else => |x| try x.scanRelocs(elf_file, undefs), | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 94 | pub fn atoms(file: File) []const Atom.Index { | 101 | pub fn atoms(file: File) []const Atom.Index { |
| 95 | return switch (file) { | 102 | return switch (file) { |
| 96 | .linker_defined, .shared_object => &[0]Atom.Index{}, | 103 | .linker_defined, .shared_object => &[0]Atom.Index{}, |
src/link/Elf/relocation.zig created+264| ... | @@ -0,0 +1,264 @@ | ||
| 1 | pub const Kind = enum { | ||
| 2 | abs, | ||
| 3 | copy, | ||
| 4 | rel, | ||
| 5 | irel, | ||
| 6 | glob_dat, | ||
| 7 | jump_slot, | ||
| 8 | dtpmod, | ||
| 9 | dtpoff, | ||
| 10 | tpoff, | ||
| 11 | tlsdesc, | ||
| 12 | }; | ||
| 13 | |||
| 14 | const x86_64_relocs = [_]struct { Kind, u32 }{ | ||
| 15 | .{ .abs, elf.R_X86_64_64 }, | ||
| 16 | .{ .copy, elf.R_X86_64_COPY }, | ||
| 17 | .{ .rel, elf.R_X86_64_RELATIVE }, | ||
| 18 | .{ .irel, elf.R_X86_64_IRELATIVE }, | ||
| 19 | .{ .glob_dat, elf.R_X86_64_GLOB_DAT }, | ||
| 20 | .{ .jump_slot, elf.R_X86_64_JUMP_SLOT }, | ||
| 21 | .{ .dtpmod, elf.R_X86_64_DTPMOD64 }, | ||
| 22 | .{ .dtpoff, elf.R_X86_64_DTPOFF64 }, | ||
| 23 | .{ .tpoff, elf.R_X86_64_TPOFF64 }, | ||
| 24 | .{ .tlsdesc, elf.R_X86_64_TLSDESC }, | ||
| 25 | }; | ||
| 26 | |||
| 27 | const aarch64_relocs = [_]struct { Kind, u32 }{ | ||
| 28 | .{ .abs, elf.R_AARCH64_ABS64 }, | ||
| 29 | .{ .copy, elf.R_AARCH64_COPY }, | ||
| 30 | .{ .rel, elf.R_AARCH64_RELATIVE }, | ||
| 31 | .{ .irel, elf.R_AARCH64_IRELATIVE }, | ||
| 32 | .{ .glob_dat, elf.R_AARCH64_GLOB_DAT }, | ||
| 33 | .{ .jump_slot, elf.R_AARCH64_JUMP_SLOT }, | ||
| 34 | .{ .dtpmod, elf.R_AARCH64_TLS_DTPMOD }, | ||
| 35 | .{ .dtpoff, elf.R_AARCH64_TLS_DTPREL }, | ||
| 36 | .{ .tpoff, elf.R_AARCH64_TLS_TPREL }, | ||
| 37 | .{ .tlsdesc, elf.R_AARCH64_TLSDESC }, | ||
| 38 | }; | ||
| 39 | |||
| 40 | pub fn decode(r_type: u32, cpu_arch: std.Target.Cpu.Arch) ?Kind { | ||
| 41 | const relocs = switch (cpu_arch) { | ||
| 42 | .x86_64 => &x86_64_relocs, | ||
| 43 | .aarch64 => &aarch64_relocs, | ||
| 44 | else => @panic("TODO unhandled cpu arch"), | ||
| 45 | }; | ||
| 46 | inline for (relocs) |entry| { | ||
| 47 | if (entry[1] == r_type) return entry[0]; | ||
| 48 | } | ||
| 49 | return null; | ||
| 50 | } | ||
| 51 | |||
| 52 | pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 { | ||
| 53 | const relocs = switch (cpu_arch) { | ||
| 54 | .x86_64 => &x86_64_relocs, | ||
| 55 | .aarch64 => &aarch64_relocs, | ||
| 56 | else => @panic("TODO unhandled cpu arch"), | ||
| 57 | }; | ||
| 58 | inline for (relocs) |entry| { | ||
| 59 | if (entry[0] == kind) return entry[1]; | ||
| 60 | } | ||
| 61 | unreachable; | ||
| 62 | } | ||
| 63 | |||
| 64 | const FormatRelocTypeCtx = struct { | ||
| 65 | r_type: u32, | ||
| 66 | cpu_arch: std.Target.Cpu.Arch, | ||
| 67 | }; | ||
| 68 | |||
| 69 | pub fn fmtRelocType(r_type: u32, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatRelocType) { | ||
| 70 | return .{ .data = .{ | ||
| 71 | .r_type = r_type, | ||
| 72 | .cpu_arch = cpu_arch, | ||
| 73 | } }; | ||
| 74 | } | ||
| 75 | |||
| 76 | fn formatRelocType( | ||
| 77 | ctx: FormatRelocTypeCtx, | ||
| 78 | comptime unused_fmt_string: []const u8, | ||
| 79 | options: std.fmt.FormatOptions, | ||
| 80 | writer: anytype, | ||
| 81 | ) !void { | ||
| 82 | _ = unused_fmt_string; | ||
| 83 | _ = options; | ||
| 84 | const r_type = ctx.r_type; | ||
| 85 | const str = switch (ctx.cpu_arch) { | ||
| 86 | .x86_64 => switch (r_type) { | ||
| 87 | elf.R_X86_64_NONE => "R_X86_64_NONE", | ||
| 88 | elf.R_X86_64_64 => "R_X86_64_64", | ||
| 89 | elf.R_X86_64_PC32 => "R_X86_64_PC32", | ||
| 90 | elf.R_X86_64_GOT32 => "R_X86_64_GOT32", | ||
| 91 | elf.R_X86_64_PLT32 => "R_X86_64_PLT32", | ||
| 92 | elf.R_X86_64_COPY => "R_X86_64_COPY", | ||
| 93 | elf.R_X86_64_GLOB_DAT => "R_X86_64_GLOB_DAT", | ||
| 94 | elf.R_X86_64_JUMP_SLOT => "R_X86_64_JUMP_SLOT", | ||
| 95 | elf.R_X86_64_RELATIVE => "R_X86_64_RELATIVE", | ||
| 96 | elf.R_X86_64_GOTPCREL => "R_X86_64_GOTPCREL", | ||
| 97 | elf.R_X86_64_32 => "R_X86_64_32", | ||
| 98 | elf.R_X86_64_32S => "R_X86_64_32S", | ||
| 99 | elf.R_X86_64_16 => "R_X86_64_16", | ||
| 100 | elf.R_X86_64_PC16 => "R_X86_64_PC16", | ||
| 101 | elf.R_X86_64_8 => "R_X86_64_8", | ||
| 102 | elf.R_X86_64_PC8 => "R_X86_64_PC8", | ||
| 103 | elf.R_X86_64_DTPMOD64 => "R_X86_64_DTPMOD64", | ||
| 104 | elf.R_X86_64_DTPOFF64 => "R_X86_64_DTPOFF64", | ||
| 105 | elf.R_X86_64_TPOFF64 => "R_X86_64_TPOFF64", | ||
| 106 | elf.R_X86_64_TLSGD => "R_X86_64_TLSGD", | ||
| 107 | elf.R_X86_64_TLSLD => "R_X86_64_TLSLD", | ||
| 108 | elf.R_X86_64_DTPOFF32 => "R_X86_64_DTPOFF32", | ||
| 109 | elf.R_X86_64_GOTTPOFF => "R_X86_64_GOTTPOFF", | ||
| 110 | elf.R_X86_64_TPOFF32 => "R_X86_64_TPOFF32", | ||
| 111 | elf.R_X86_64_PC64 => "R_X86_64_PC64", | ||
| 112 | elf.R_X86_64_GOTOFF64 => "R_X86_64_GOTOFF64", | ||
| 113 | elf.R_X86_64_GOTPC32 => "R_X86_64_GOTPC32", | ||
| 114 | elf.R_X86_64_GOT64 => "R_X86_64_GOT64", | ||
| 115 | elf.R_X86_64_GOTPCREL64 => "R_X86_64_GOTPCREL64", | ||
| 116 | elf.R_X86_64_GOTPC64 => "R_X86_64_GOTPC64", | ||
| 117 | elf.R_X86_64_GOTPLT64 => "R_X86_64_GOTPLT64", | ||
| 118 | elf.R_X86_64_PLTOFF64 => "R_X86_64_PLTOFF64", | ||
| 119 | elf.R_X86_64_SIZE32 => "R_X86_64_SIZE32", | ||
| 120 | elf.R_X86_64_SIZE64 => "R_X86_64_SIZE64", | ||
| 121 | elf.R_X86_64_GOTPC32_TLSDESC => "R_X86_64_GOTPC32_TLSDESC", | ||
| 122 | elf.R_X86_64_TLSDESC_CALL => "R_X86_64_TLSDESC_CALL", | ||
| 123 | elf.R_X86_64_TLSDESC => "R_X86_64_TLSDESC", | ||
| 124 | elf.R_X86_64_IRELATIVE => "R_X86_64_IRELATIVE", | ||
| 125 | elf.R_X86_64_RELATIVE64 => "R_X86_64_RELATIVE64", | ||
| 126 | elf.R_X86_64_GOTPCRELX => "R_X86_64_GOTPCRELX", | ||
| 127 | elf.R_X86_64_REX_GOTPCRELX => "R_X86_64_REX_GOTPCRELX", | ||
| 128 | elf.R_X86_64_NUM => "R_X86_64_NUM", | ||
| 129 | else => "R_X86_64_UNKNOWN", | ||
| 130 | }, | ||
| 131 | .aarch64 => switch (r_type) { | ||
| 132 | elf.R_AARCH64_NONE => "R_AARCH64_NONE", | ||
| 133 | elf.R_AARCH64_ABS64 => "R_AARCH64_ABS64", | ||
| 134 | elf.R_AARCH64_ABS32 => "R_AARCH64_ABS32", | ||
| 135 | elf.R_AARCH64_ABS16 => "R_AARCH64_ABS16", | ||
| 136 | elf.R_AARCH64_PREL64 => "R_AARCH64_PREL64", | ||
| 137 | elf.R_AARCH64_PREL32 => "R_AARCH64_PREL32", | ||
| 138 | elf.R_AARCH64_PREL16 => "R_AARCH64_PREL16", | ||
| 139 | elf.R_AARCH64_MOVW_UABS_G0 => "R_AARCH64_MOVW_UABS_G0", | ||
| 140 | elf.R_AARCH64_MOVW_UABS_G0_NC => "R_AARCH64_MOVW_UABS_G0_NC", | ||
| 141 | elf.R_AARCH64_MOVW_UABS_G1 => "R_AARCH64_MOVW_UABS_G1", | ||
| 142 | elf.R_AARCH64_MOVW_UABS_G1_NC => "R_AARCH64_MOVW_UABS_G1_NC", | ||
| 143 | elf.R_AARCH64_MOVW_UABS_G2 => "R_AARCH64_MOVW_UABS_G2", | ||
| 144 | elf.R_AARCH64_MOVW_UABS_G2_NC => "R_AARCH64_MOVW_UABS_G2_NC", | ||
| 145 | elf.R_AARCH64_MOVW_UABS_G3 => "R_AARCH64_MOVW_UABS_G3", | ||
| 146 | elf.R_AARCH64_MOVW_SABS_G0 => "R_AARCH64_MOVW_SABS_G0", | ||
| 147 | elf.R_AARCH64_MOVW_SABS_G1 => "R_AARCH64_MOVW_SABS_G1", | ||
| 148 | elf.R_AARCH64_MOVW_SABS_G2 => "R_AARCH64_MOVW_SABS_G2", | ||
| 149 | elf.R_AARCH64_LD_PREL_LO19 => "R_AARCH64_LD_PREL_LO19", | ||
| 150 | elf.R_AARCH64_ADR_PREL_LO21 => "R_AARCH64_ADR_PREL_LO21", | ||
| 151 | elf.R_AARCH64_ADR_PREL_PG_HI21 => "R_AARCH64_ADR_PREL_PG_HI21", | ||
| 152 | elf.R_AARCH64_ADR_PREL_PG_HI21_NC => "R_AARCH64_ADR_PREL_PG_HI21_NC", | ||
| 153 | elf.R_AARCH64_ADD_ABS_LO12_NC => "R_AARCH64_ADD_ABS_LO12_NC", | ||
| 154 | elf.R_AARCH64_LDST8_ABS_LO12_NC => "R_AARCH64_LDST8_ABS_LO12_NC", | ||
| 155 | elf.R_AARCH64_TSTBR14 => "R_AARCH64_TSTBR14", | ||
| 156 | elf.R_AARCH64_CONDBR19 => "R_AARCH64_CONDBR19", | ||
| 157 | elf.R_AARCH64_JUMP26 => "R_AARCH64_JUMP26", | ||
| 158 | elf.R_AARCH64_CALL26 => "R_AARCH64_CALL26", | ||
| 159 | elf.R_AARCH64_LDST16_ABS_LO12_NC => "R_AARCH64_LDST16_ABS_LO12_NC", | ||
| 160 | elf.R_AARCH64_LDST32_ABS_LO12_NC => "R_AARCH64_LDST32_ABS_LO12_NC", | ||
| 161 | elf.R_AARCH64_LDST64_ABS_LO12_NC => "R_AARCH64_LDST64_ABS_LO12_NC", | ||
| 162 | elf.R_AARCH64_MOVW_PREL_G0 => "R_AARCH64_MOVW_PREL_G0", | ||
| 163 | elf.R_AARCH64_MOVW_PREL_G0_NC => "R_AARCH64_MOVW_PREL_G0_NC", | ||
| 164 | elf.R_AARCH64_MOVW_PREL_G1 => "R_AARCH64_MOVW_PREL_G1", | ||
| 165 | elf.R_AARCH64_MOVW_PREL_G1_NC => "R_AARCH64_MOVW_PREL_G1_NC", | ||
| 166 | elf.R_AARCH64_MOVW_PREL_G2 => "R_AARCH64_MOVW_PREL_G2", | ||
| 167 | elf.R_AARCH64_MOVW_PREL_G2_NC => "R_AARCH64_MOVW_PREL_G2_NC", | ||
| 168 | elf.R_AARCH64_MOVW_PREL_G3 => "R_AARCH64_MOVW_PREL_G3", | ||
| 169 | elf.R_AARCH64_LDST128_ABS_LO12_NC => "R_AARCH64_LDST128_ABS_LO12_NC", | ||
| 170 | elf.R_AARCH64_MOVW_GOTOFF_G0 => "R_AARCH64_MOVW_GOTOFF_G0", | ||
| 171 | elf.R_AARCH64_MOVW_GOTOFF_G0_NC => "R_AARCH64_MOVW_GOTOFF_G0_NC", | ||
| 172 | elf.R_AARCH64_MOVW_GOTOFF_G1 => "R_AARCH64_MOVW_GOTOFF_G1", | ||
| 173 | elf.R_AARCH64_MOVW_GOTOFF_G1_NC => "R_AARCH64_MOVW_GOTOFF_G1_NC", | ||
| 174 | elf.R_AARCH64_MOVW_GOTOFF_G2 => "R_AARCH64_MOVW_GOTOFF_G2", | ||
| 175 | elf.R_AARCH64_MOVW_GOTOFF_G2_NC => "R_AARCH64_MOVW_GOTOFF_G2_NC", | ||
| 176 | elf.R_AARCH64_MOVW_GOTOFF_G3 => "R_AARCH64_MOVW_GOTOFF_G3", | ||
| 177 | elf.R_AARCH64_GOTREL64 => "R_AARCH64_GOTREL64", | ||
| 178 | elf.R_AARCH64_GOTREL32 => "R_AARCH64_GOTREL32", | ||
| 179 | elf.R_AARCH64_GOT_LD_PREL19 => "R_AARCH64_GOT_LD_PREL19", | ||
| 180 | elf.R_AARCH64_LD64_GOTOFF_LO15 => "R_AARCH64_LD64_GOTOFF_LO15", | ||
| 181 | elf.R_AARCH64_ADR_GOT_PAGE => "R_AARCH64_ADR_GOT_PAGE", | ||
| 182 | elf.R_AARCH64_LD64_GOT_LO12_NC => "R_AARCH64_LD64_GOT_LO12_NC", | ||
| 183 | elf.R_AARCH64_LD64_GOTPAGE_LO15 => "R_AARCH64_LD64_GOTPAGE_LO15", | ||
| 184 | elf.R_AARCH64_TLSGD_ADR_PREL21 => "R_AARCH64_TLSGD_ADR_PREL21", | ||
| 185 | elf.R_AARCH64_TLSGD_ADR_PAGE21 => "R_AARCH64_TLSGD_ADR_PAGE21", | ||
| 186 | elf.R_AARCH64_TLSGD_ADD_LO12_NC => "R_AARCH64_TLSGD_ADD_LO12_NC", | ||
| 187 | elf.R_AARCH64_TLSGD_MOVW_G1 => "R_AARCH64_TLSGD_MOVW_G1", | ||
| 188 | elf.R_AARCH64_TLSGD_MOVW_G0_NC => "R_AARCH64_TLSGD_MOVW_G0_NC", | ||
| 189 | elf.R_AARCH64_TLSLD_ADR_PREL21 => "R_AARCH64_TLSLD_ADR_PREL21", | ||
| 190 | elf.R_AARCH64_TLSLD_ADR_PAGE21 => "R_AARCH64_TLSLD_ADR_PAGE21", | ||
| 191 | elf.R_AARCH64_TLSLD_ADD_LO12_NC => "R_AARCH64_TLSLD_ADD_LO12_NC", | ||
| 192 | elf.R_AARCH64_TLSLD_MOVW_G1 => "R_AARCH64_TLSLD_MOVW_G1", | ||
| 193 | elf.R_AARCH64_TLSLD_MOVW_G0_NC => "R_AARCH64_TLSLD_MOVW_G0_NC", | ||
| 194 | elf.R_AARCH64_TLSLD_LD_PREL19 => "R_AARCH64_TLSLD_LD_PREL19", | ||
| 195 | elf.R_AARCH64_TLSLD_MOVW_DTPREL_G2 => "R_AARCH64_TLSLD_MOVW_DTPREL_G2", | ||
| 196 | elf.R_AARCH64_TLSLD_MOVW_DTPREL_G1 => "R_AARCH64_TLSLD_MOVW_DTPREL_G1", | ||
| 197 | elf.R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC => "R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC", | ||
| 198 | elf.R_AARCH64_TLSLD_MOVW_DTPREL_G0 => "R_AARCH64_TLSLD_MOVW_DTPREL_G0", | ||
| 199 | elf.R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC => "R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC", | ||
| 200 | elf.R_AARCH64_TLSLD_ADD_DTPREL_HI12 => "R_AARCH64_TLSLD_ADD_DTPREL_HI12", | ||
| 201 | elf.R_AARCH64_TLSLD_ADD_DTPREL_LO12 => "R_AARCH64_TLSLD_ADD_DTPREL_LO12", | ||
| 202 | elf.R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC => "R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC", | ||
| 203 | elf.R_AARCH64_TLSLD_LDST8_DTPREL_LO12 => "R_AARCH64_TLSLD_LDST8_DTPREL_LO12", | ||
| 204 | elf.R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC => "R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC", | ||
| 205 | elf.R_AARCH64_TLSLD_LDST16_DTPREL_LO12 => "R_AARCH64_TLSLD_LDST16_DTPREL_LO12", | ||
| 206 | elf.R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC => "R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC", | ||
| 207 | elf.R_AARCH64_TLSLD_LDST32_DTPREL_LO12 => "R_AARCH64_TLSLD_LDST32_DTPREL_LO12", | ||
| 208 | elf.R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC => "R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC", | ||
| 209 | elf.R_AARCH64_TLSLD_LDST64_DTPREL_LO12 => "R_AARCH64_TLSLD_LDST64_DTPREL_LO12", | ||
| 210 | elf.R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC => "R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC", | ||
| 211 | elf.R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 => "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1", | ||
| 212 | elf.R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC => "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC", | ||
| 213 | elf.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 => "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21", | ||
| 214 | elf.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC => "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", | ||
| 215 | elf.R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 => "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19", | ||
| 216 | elf.R_AARCH64_TLSLE_MOVW_TPREL_G2 => "R_AARCH64_TLSLE_MOVW_TPREL_G2", | ||
| 217 | elf.R_AARCH64_TLSLE_MOVW_TPREL_G1 => "R_AARCH64_TLSLE_MOVW_TPREL_G1", | ||
| 218 | elf.R_AARCH64_TLSLE_MOVW_TPREL_G1_NC => "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC", | ||
| 219 | elf.R_AARCH64_TLSLE_MOVW_TPREL_G0 => "R_AARCH64_TLSLE_MOVW_TPREL_G0", | ||
| 220 | elf.R_AARCH64_TLSLE_MOVW_TPREL_G0_NC => "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC", | ||
| 221 | elf.R_AARCH64_TLSLE_ADD_TPREL_HI12 => "R_AARCH64_TLSLE_ADD_TPREL_HI12", | ||
| 222 | elf.R_AARCH64_TLSLE_ADD_TPREL_LO12 => "R_AARCH64_TLSLE_ADD_TPREL_LO12", | ||
| 223 | elf.R_AARCH64_TLSLE_ADD_TPREL_LO12_NC => "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC", | ||
| 224 | elf.R_AARCH64_TLSLE_LDST8_TPREL_LO12 => "R_AARCH64_TLSLE_LDST8_TPREL_LO12", | ||
| 225 | elf.R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC => "R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC", | ||
| 226 | elf.R_AARCH64_TLSLE_LDST16_TPREL_LO12 => "R_AARCH64_TLSLE_LDST16_TPREL_LO12", | ||
| 227 | elf.R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC => "R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC", | ||
| 228 | elf.R_AARCH64_TLSLE_LDST32_TPREL_LO12 => "R_AARCH64_TLSLE_LDST32_TPREL_LO12", | ||
| 229 | elf.R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC => "R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC", | ||
| 230 | elf.R_AARCH64_TLSLE_LDST64_TPREL_LO12 => "R_AARCH64_TLSLE_LDST64_TPREL_LO12", | ||
| 231 | elf.R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC => "R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC", | ||
| 232 | elf.R_AARCH64_TLSDESC_LD_PREL19 => "R_AARCH64_TLSDESC_LD_PREL19", | ||
| 233 | elf.R_AARCH64_TLSDESC_ADR_PREL21 => "R_AARCH64_TLSDESC_ADR_PREL21", | ||
| 234 | elf.R_AARCH64_TLSDESC_ADR_PAGE21 => "R_AARCH64_TLSDESC_ADR_PAGE21", | ||
| 235 | elf.R_AARCH64_TLSDESC_LD64_LO12 => "R_AARCH64_TLSDESC_LD64_LO12", | ||
| 236 | elf.R_AARCH64_TLSDESC_ADD_LO12 => "R_AARCH64_TLSDESC_ADD_LO12", | ||
| 237 | elf.R_AARCH64_TLSDESC_OFF_G1 => "R_AARCH64_TLSDESC_OFF_G1", | ||
| 238 | elf.R_AARCH64_TLSDESC_OFF_G0_NC => "R_AARCH64_TLSDESC_OFF_G0_NC", | ||
| 239 | elf.R_AARCH64_TLSDESC_LDR => "R_AARCH64_TLSDESC_LDR", | ||
| 240 | elf.R_AARCH64_TLSDESC_ADD => "R_AARCH64_TLSDESC_ADD", | ||
| 241 | elf.R_AARCH64_TLSDESC_CALL => "R_AARCH64_TLSDESC_CALL", | ||
| 242 | elf.R_AARCH64_TLSLE_LDST128_TPREL_LO12 => "R_AARCH64_TLSLE_LDST128_TPREL_LO12", | ||
| 243 | elf.R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC => "R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC", | ||
| 244 | elf.R_AARCH64_TLSLD_LDST128_DTPREL_LO12 => "R_AARCH64_TLSLD_LDST128_DTPREL_LO12", | ||
| 245 | elf.R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC => "R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC", | ||
| 246 | elf.R_AARCH64_COPY => "R_AARCH64_COPY", | ||
| 247 | elf.R_AARCH64_GLOB_DAT => "R_AARCH64_GLOB_DAT", | ||
| 248 | elf.R_AARCH64_JUMP_SLOT => "R_AARCH64_JUMP_SLOT", | ||
| 249 | elf.R_AARCH64_RELATIVE => "R_AARCH64_RELATIVE", | ||
| 250 | elf.R_AARCH64_TLS_DTPMOD => "R_AARCH64_TLS_DTPMOD", | ||
| 251 | elf.R_AARCH64_TLS_DTPREL => "R_AARCH64_TLS_DTPREL", | ||
| 252 | elf.R_AARCH64_TLS_TPREL => "R_AARCH64_TLS_TPREL", | ||
| 253 | elf.R_AARCH64_TLSDESC => "R_AARCH64_TLSDESC", | ||
| 254 | elf.R_AARCH64_IRELATIVE => "R_AARCH64_IRELATIVE", | ||
| 255 | else => "R_AARCH64_UNKNOWN", | ||
| 256 | }, | ||
| 257 | else => unreachable, | ||
| 258 | }; | ||
| 259 | try writer.print("{s}", .{str}); | ||
| 260 | } | ||
| 261 | |||
| 262 | const assert = std.debug.assert; | ||
| 263 | const elf = std.elf; | ||
| 264 | const std = @import("std"); | ||
src/link/Elf/synthetic_sections.zig+20-15| ... | @@ -292,7 +292,7 @@ pub const ZigGotSection = struct { | ... | @@ -292,7 +292,7 @@ pub const ZigGotSection = struct { |
| 292 | zig_got.flags.dirty = false; | 292 | zig_got.flags.dirty = false; |
| 293 | } | 293 | } |
| 294 | const entry_size: u16 = elf_file.archPtrWidthBytes(); | 294 | const entry_size: u16 = elf_file.archPtrWidthBytes(); |
| 295 | const target = elf_file.base.comp.root_mod.resolved_target.result; | 295 | const target = elf_file.getTarget(); |
| 296 | const endian = target.cpu.arch.endian(); | 296 | const endian = target.cpu.arch.endian(); |
| 297 | const off = zig_got.entryOffset(index, elf_file); | 297 | const off = zig_got.entryOffset(index, elf_file); |
| 298 | const vaddr = zig_got.entryAddress(index, elf_file); | 298 | const vaddr = zig_got.entryAddress(index, elf_file); |
| ... | @@ -354,13 +354,14 @@ pub const ZigGotSection = struct { | ... | @@ -354,13 +354,14 @@ pub const ZigGotSection = struct { |
| 354 | pub fn addRela(zig_got: ZigGotSection, elf_file: *Elf) !void { | 354 | pub fn addRela(zig_got: ZigGotSection, elf_file: *Elf) !void { |
| 355 | const comp = elf_file.base.comp; | 355 | const comp = elf_file.base.comp; |
| 356 | const gpa = comp.gpa; | 356 | const gpa = comp.gpa; |
| 357 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 357 | try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela()); | 358 | try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela()); |
| 358 | for (zig_got.entries.items) |entry| { | 359 | for (zig_got.entries.items) |entry| { |
| 359 | const symbol = elf_file.symbol(entry); | 360 | const symbol = elf_file.symbol(entry); |
| 360 | const offset = symbol.zigGotAddress(elf_file); | 361 | const offset = symbol.zigGotAddress(elf_file); |
| 361 | elf_file.addRelaDynAssumeCapacity(.{ | 362 | elf_file.addRelaDynAssumeCapacity(.{ |
| 362 | .offset = offset, | 363 | .offset = offset, |
| 363 | .type = elf.R_X86_64_RELATIVE, | 364 | .type = relocation.encode(.rel, cpu_arch), |
| 364 | .addend = @intCast(symbol.address(.{ .plt = false }, elf_file)), | 365 | .addend = @intCast(symbol.address(.{ .plt = false }, elf_file)), |
| 365 | }); | 366 | }); |
| 366 | } | 367 | } |
| ... | @@ -644,6 +645,7 @@ pub const GotSection = struct { | ... | @@ -644,6 +645,7 @@ pub const GotSection = struct { |
| 644 | const comp = elf_file.base.comp; | 645 | const comp = elf_file.base.comp; |
| 645 | const gpa = comp.gpa; | 646 | const gpa = comp.gpa; |
| 646 | const is_dyn_lib = elf_file.base.isDynLib(); | 647 | const is_dyn_lib = elf_file.base.isDynLib(); |
| 648 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 647 | try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file)); | 649 | try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file)); |
| 648 | 650 | ||
| 649 | for (got.entries.items) |entry| { | 651 | for (got.entries.items) |entry| { |
| ... | @@ -660,14 +662,14 @@ pub const GotSection = struct { | ... | @@ -660,14 +662,14 @@ pub const GotSection = struct { |
| 660 | elf_file.addRelaDynAssumeCapacity(.{ | 662 | elf_file.addRelaDynAssumeCapacity(.{ |
| 661 | .offset = offset, | 663 | .offset = offset, |
| 662 | .sym = extra.?.dynamic, | 664 | .sym = extra.?.dynamic, |
| 663 | .type = elf.R_X86_64_GLOB_DAT, | 665 | .type = relocation.encode(.glob_dat, cpu_arch), |
| 664 | }); | 666 | }); |
| 665 | continue; | 667 | continue; |
| 666 | } | 668 | } |
| 667 | if (symbol.?.isIFunc(elf_file)) { | 669 | if (symbol.?.isIFunc(elf_file)) { |
| 668 | elf_file.addRelaDynAssumeCapacity(.{ | 670 | elf_file.addRelaDynAssumeCapacity(.{ |
| 669 | .offset = offset, | 671 | .offset = offset, |
| 670 | .type = elf.R_X86_64_IRELATIVE, | 672 | .type = relocation.encode(.irel, cpu_arch), |
| 671 | .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)), | 673 | .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)), |
| 672 | }); | 674 | }); |
| 673 | continue; | 675 | continue; |
| ... | @@ -677,7 +679,7 @@ pub const GotSection = struct { | ... | @@ -677,7 +679,7 @@ pub const GotSection = struct { |
| 677 | { | 679 | { |
| 678 | elf_file.addRelaDynAssumeCapacity(.{ | 680 | elf_file.addRelaDynAssumeCapacity(.{ |
| 679 | .offset = offset, | 681 | .offset = offset, |
| 680 | .type = elf.R_X86_64_RELATIVE, | 682 | .type = relocation.encode(.rel, cpu_arch), |
| 681 | .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)), | 683 | .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)), |
| 682 | }); | 684 | }); |
| 683 | } | 685 | } |
| ... | @@ -688,7 +690,7 @@ pub const GotSection = struct { | ... | @@ -688,7 +690,7 @@ pub const GotSection = struct { |
| 688 | const offset = entry.address(elf_file); | 690 | const offset = entry.address(elf_file); |
| 689 | elf_file.addRelaDynAssumeCapacity(.{ | 691 | elf_file.addRelaDynAssumeCapacity(.{ |
| 690 | .offset = offset, | 692 | .offset = offset, |
| 691 | .type = elf.R_X86_64_DTPMOD64, | 693 | .type = relocation.encode(.dtpmod, cpu_arch), |
| 692 | }); | 694 | }); |
| 693 | } | 695 | } |
| 694 | }, | 696 | }, |
| ... | @@ -699,18 +701,18 @@ pub const GotSection = struct { | ... | @@ -699,18 +701,18 @@ pub const GotSection = struct { |
| 699 | elf_file.addRelaDynAssumeCapacity(.{ | 701 | elf_file.addRelaDynAssumeCapacity(.{ |
| 700 | .offset = offset, | 702 | .offset = offset, |
| 701 | .sym = extra.?.dynamic, | 703 | .sym = extra.?.dynamic, |
| 702 | .type = elf.R_X86_64_DTPMOD64, | 704 | .type = relocation.encode(.dtpmod, cpu_arch), |
| 703 | }); | 705 | }); |
| 704 | elf_file.addRelaDynAssumeCapacity(.{ | 706 | elf_file.addRelaDynAssumeCapacity(.{ |
| 705 | .offset = offset + 8, | 707 | .offset = offset + 8, |
| 706 | .sym = extra.?.dynamic, | 708 | .sym = extra.?.dynamic, |
| 707 | .type = elf.R_X86_64_DTPOFF64, | 709 | .type = relocation.encode(.dtpoff, cpu_arch), |
| 708 | }); | 710 | }); |
| 709 | } else if (is_dyn_lib) { | 711 | } else if (is_dyn_lib) { |
| 710 | elf_file.addRelaDynAssumeCapacity(.{ | 712 | elf_file.addRelaDynAssumeCapacity(.{ |
| 711 | .offset = offset, | 713 | .offset = offset, |
| 712 | .sym = extra.?.dynamic, | 714 | .sym = extra.?.dynamic, |
| 713 | .type = elf.R_X86_64_DTPMOD64, | 715 | .type = relocation.encode(.dtpmod, cpu_arch), |
| 714 | }); | 716 | }); |
| 715 | } | 717 | } |
| 716 | }, | 718 | }, |
| ... | @@ -721,12 +723,12 @@ pub const GotSection = struct { | ... | @@ -721,12 +723,12 @@ pub const GotSection = struct { |
| 721 | elf_file.addRelaDynAssumeCapacity(.{ | 723 | elf_file.addRelaDynAssumeCapacity(.{ |
| 722 | .offset = offset, | 724 | .offset = offset, |
| 723 | .sym = extra.?.dynamic, | 725 | .sym = extra.?.dynamic, |
| 724 | .type = elf.R_X86_64_TPOFF64, | 726 | .type = relocation.encode(.tpoff, cpu_arch), |
| 725 | }); | 727 | }); |
| 726 | } else if (is_dyn_lib) { | 728 | } else if (is_dyn_lib) { |
| 727 | elf_file.addRelaDynAssumeCapacity(.{ | 729 | elf_file.addRelaDynAssumeCapacity(.{ |
| 728 | .offset = offset, | 730 | .offset = offset, |
| 729 | .type = elf.R_X86_64_TPOFF64, | 731 | .type = relocation.encode(.tpoff, cpu_arch), |
| 730 | .addend = @intCast(symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()), | 732 | .addend = @intCast(symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()), |
| 731 | }); | 733 | }); |
| 732 | } | 734 | } |
| ... | @@ -737,7 +739,7 @@ pub const GotSection = struct { | ... | @@ -737,7 +739,7 @@ pub const GotSection = struct { |
| 737 | elf_file.addRelaDynAssumeCapacity(.{ | 739 | elf_file.addRelaDynAssumeCapacity(.{ |
| 738 | .offset = offset, | 740 | .offset = offset, |
| 739 | .sym = extra.?.dynamic, | 741 | .sym = extra.?.dynamic, |
| 740 | .type = elf.R_X86_64_TLSDESC, | 742 | .type = relocation.encode(.tlsdesc, cpu_arch), |
| 741 | }); | 743 | }); |
| 742 | }, | 744 | }, |
| 743 | } | 745 | } |
| ... | @@ -914,6 +916,7 @@ pub const PltSection = struct { | ... | @@ -914,6 +916,7 @@ pub const PltSection = struct { |
| 914 | pub fn addRela(plt: PltSection, elf_file: *Elf) !void { | 916 | pub fn addRela(plt: PltSection, elf_file: *Elf) !void { |
| 915 | const comp = elf_file.base.comp; | 917 | const comp = elf_file.base.comp; |
| 916 | const gpa = comp.gpa; | 918 | const gpa = comp.gpa; |
| 919 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 917 | try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela()); | 920 | try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela()); |
| 918 | for (plt.symbols.items) |sym_index| { | 921 | for (plt.symbols.items) |sym_index| { |
| 919 | const sym = elf_file.symbol(sym_index); | 922 | const sym = elf_file.symbol(sym_index); |
| ... | @@ -921,7 +924,7 @@ pub const PltSection = struct { | ... | @@ -921,7 +924,7 @@ pub const PltSection = struct { |
| 921 | const extra = sym.extra(elf_file).?; | 924 | const extra = sym.extra(elf_file).?; |
| 922 | const r_offset = sym.gotPltAddress(elf_file); | 925 | const r_offset = sym.gotPltAddress(elf_file); |
| 923 | const r_sym: u64 = extra.dynamic; | 926 | const r_sym: u64 = extra.dynamic; |
| 924 | const r_type: u32 = elf.R_X86_64_JUMP_SLOT; | 927 | const r_type = relocation.encode(.jump_slot, cpu_arch); |
| 925 | elf_file.rela_plt.appendAssumeCapacity(.{ | 928 | elf_file.rela_plt.appendAssumeCapacity(.{ |
| 926 | .r_offset = r_offset, | 929 | .r_offset = r_offset, |
| 927 | .r_info = (r_sym << 32) | r_type, | 930 | .r_info = (r_sym << 32) | r_type, |
| ... | @@ -1154,6 +1157,7 @@ pub const CopyRelSection = struct { | ... | @@ -1154,6 +1157,7 @@ pub const CopyRelSection = struct { |
| 1154 | pub fn addRela(copy_rel: CopyRelSection, elf_file: *Elf) !void { | 1157 | pub fn addRela(copy_rel: CopyRelSection, elf_file: *Elf) !void { |
| 1155 | const comp = elf_file.base.comp; | 1158 | const comp = elf_file.base.comp; |
| 1156 | const gpa = comp.gpa; | 1159 | const gpa = comp.gpa; |
| 1160 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 1157 | try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela()); | 1161 | try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela()); |
| 1158 | for (copy_rel.symbols.items) |sym_index| { | 1162 | for (copy_rel.symbols.items) |sym_index| { |
| 1159 | const sym = elf_file.symbol(sym_index); | 1163 | const sym = elf_file.symbol(sym_index); |
| ... | @@ -1162,7 +1166,7 @@ pub const CopyRelSection = struct { | ... | @@ -1162,7 +1166,7 @@ pub const CopyRelSection = struct { |
| 1162 | elf_file.addRelaDynAssumeCapacity(.{ | 1166 | elf_file.addRelaDynAssumeCapacity(.{ |
| 1163 | .offset = sym.address(.{}, elf_file), | 1167 | .offset = sym.address(.{}, elf_file), |
| 1164 | .sym = extra.dynamic, | 1168 | .sym = extra.dynamic, |
| 1165 | .type = elf.R_X86_64_COPY, | 1169 | .type = relocation.encode(.copy, cpu_arch), |
| 1166 | }); | 1170 | }); |
| 1167 | } | 1171 | } |
| 1168 | } | 1172 | } |
| ... | @@ -1612,7 +1616,7 @@ pub const ComdatGroupSection = struct { | ... | @@ -1612,7 +1616,7 @@ pub const ComdatGroupSection = struct { |
| 1612 | 1616 | ||
| 1613 | fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void { | 1617 | fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void { |
| 1614 | const entry_size = elf_file.archPtrWidthBytes(); | 1618 | const entry_size = elf_file.archPtrWidthBytes(); |
| 1615 | const target = elf_file.base.comp.root_mod.resolved_target.result; | 1619 | const target = elf_file.getTarget(); |
| 1616 | const endian = target.cpu.arch.endian(); | 1620 | const endian = target.cpu.arch.endian(); |
| 1617 | switch (entry_size) { | 1621 | switch (entry_size) { |
| 1618 | 2 => try writer.writeInt(u16, @intCast(value), endian), | 1622 | 2 => try writer.writeInt(u16, @intCast(value), endian), |
| ... | @@ -1627,6 +1631,7 @@ const builtin = @import("builtin"); | ... | @@ -1627,6 +1631,7 @@ const builtin = @import("builtin"); |
| 1627 | const elf = std.elf; | 1631 | const elf = std.elf; |
| 1628 | const mem = std.mem; | 1632 | const mem = std.mem; |
| 1629 | const log = std.log.scoped(.link); | 1633 | const log = std.log.scoped(.link); |
| 1634 | const relocation = @import("relocation.zig"); | ||
| 1630 | const std = @import("std"); | 1635 | const std = @import("std"); |
| 1631 | 1636 | ||
| 1632 | const Allocator = std.mem.Allocator; | 1637 | const Allocator = std.mem.Allocator; |