authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-16 12:43:37+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-16 21:54:43+01:00
logfc7dd3e285889cd0f75e7270bb0021ad32f73ca3
treef3417c9239b2a45148564fbbb16eef9c2826dc28
parent88d4b5cb18bdc68099162f1db8103d614025659c

elf: enable adding support for additional cpu archs


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 };
13701381
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 }
20342045
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 }
20422060
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);
44724490
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 // TODO4495 _ = 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 }
44854507
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 {
52715293
5272fn sortRelaDyn(self: *Elf) void {5294fn 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 }
52815306
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}
52935317
5294fn calcNumIRelativeRelocs(self: *Elf) usize {5318fn calcNumIRelativeRelocs(self: *Elf) usize {
...@@ -5667,6 +5691,13 @@ fn reportMissingLibraryError(...@@ -5667,6 +5691,13 @@ fn reportMissingLibraryError(
5667 }5691 }
5668}5692}
56695693
5694pub 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
5670pub fn reportParseError(5701pub 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}
59345965
5966pub 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 error5970/// 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 types5971/// 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");
6059const lldMain = @import("../main.zig").lldMain;6094const lldMain = @import("../main.zig").lldMain;
6060const musl = @import("../musl.zig");6095const musl = @import("../musl.zig");
6061const relocatable = @import("Elf/relocatable.zig");6096const relocatable = @import("Elf/relocatable.zig");
6097const relocation = @import("Elf/relocation.zig");
6062const target_util = @import("../target.zig");6098const target_util = @import("../target.zig");
6063const trace = @import("../tracy.zig").trace;6099const trace = @import("../tracy.zig").trace;
6064const synthetic_sections = @import("Elf/synthetic_sections.zig");6100const 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 {
312pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void {312pub 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) });
314314
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 }
341337
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}
386382
387pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {383pub 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}
393393
394pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void {394pub 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}
539400
...@@ -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 {
693fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) error{OutOfMemory}!void {554fn 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(
789pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {650pub 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) });
791652
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}
970658
...@@ -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 {
1069pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void {758pub 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) });
1071760
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}
1160766
1161pub fn fmtRelocType(r_type: u32) std.fmt.Formatter(formatRelocType) {
1162 return .{ .data = r_type };
1163}
1164
1165fn 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
1224pub fn format(767pub 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};
1286829
1287const x86_64 = struct {830const 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 }
13051264
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 }
13171276
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 }
13541313
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 }
14061365
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 }
14211380
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 }
14371396
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 }
14531412
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 },
14811440
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;
1521const eh_frame = @import("eh_frame.zig");1480const eh_frame = @import("eh_frame.zig");
1522const log = std.log.scoped(.link);1481const log = std.log.scoped(.link);
1523const relocs_log = std.log.scoped(.link_relocs);1482const relocs_log = std.log.scoped(.link_relocs);
1483const relocation = @import("relocation.zig");
15241484
1525const Allocator = std.mem.Allocator;1485const Allocator = std.mem.Allocator;
1526const Atom = @This();1486const 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 {
5555
56pub fn parse(self: *Object, elf_file: *Elf) !void {56pub 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);
5960
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}
7175
...@@ -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}
597606
598pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void {607pub 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 or611 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;
1636const link = @import("../../link.zig");1638const link = @import("../../link.zig");
1637const log = std.log.scoped(.link);1639const log = std.log.scoped(.link);
1638const mem = std.mem;1640const mem = std.mem;
1641const relocation = @import("relocation.zig");
1639const trace = @import("../../tracy.zig").trace;1642const trace = @import("../../tracy.zig").trace;
1640const std = @import("std");1643const std = @import("std");
16411644
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}
303303
304fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void {304fn 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;
309310
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 });
317318
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}
327324
...@@ -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}
404401
405fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela {402fn 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 }
419417
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};
543541
542const 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
544const std = @import("std");554const std = @import("std");
545const assert = std.debug.assert;555const assert = std.debug.assert;
546const elf = std.elf;556const elf = std.elf;
557const math = std.math;
547const relocs_log = std.log.scoped(.link_relocs);558const relocs_log = std.log.scoped(.link_relocs);
559const relocation = @import("relocation.zig");
548560
549const Allocator = std.mem.Allocator;561const Allocator = std.mem.Allocator;
550const Atom = @import("Atom.zig");562const 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 }
9393
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 @@
1pub 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
14const 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
27const 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
40pub 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
52pub 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
64const FormatRelocTypeCtx = struct {
65 r_type: u32,
66 cpu_arch: std.Target.Cpu.Arch,
67};
68
69pub 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
76fn 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
262const assert = std.debug.assert;
263const elf = std.elf;
264const 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));
648650
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 {
16121616
1613fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {1617fn 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");
1627const elf = std.elf;1631const elf = std.elf;
1628const mem = std.mem;1632const mem = std.mem;
1629const log = std.log.scoped(.link);1633const log = std.log.scoped(.link);
1634const relocation = @import("relocation.zig");
1630const std = @import("std");1635const std = @import("std");
16311636
1632const Allocator = std.mem.Allocator;1637const Allocator = std.mem.Allocator;