authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 19:06:10+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 19:06:10+01:00
log60bc2e7616b0fd42c98ba8b9e0b212439b6ea1a0
treea7b067cbb12e047718cc324aa912ca613a22700a
parent1ca004176f8f76b1d54d878e002ebcc4362f9b92

elf: simplify logic for handling scanning relocs on different arches


3 files changed, 209 insertions(+), 144 deletions(-)

src/link/Elf.zig+9
...@@ -2049,18 +2049,22 @@ fn scanRelocs(self: *Elf) !void {...@@ -2049,18 +2049,22 @@ fn scanRelocs(self: *Elf) !void {
2049 if (self.zigObjectPtr()) |zo| objects.appendAssumeCapacity(zo.index);2049 if (self.zigObjectPtr()) |zo| objects.appendAssumeCapacity(zo.index);
2050 objects.appendSliceAssumeCapacity(self.objects.items);2050 objects.appendSliceAssumeCapacity(self.objects.items);
20512051
2052 var has_reloc_errors = false;
2052 for (objects.items) |index| {2053 for (objects.items) |index| {
2053 self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) {2054 self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) {
2054 error.UnsupportedCpuArch => {2055 error.UnsupportedCpuArch => {
2055 try self.reportUnsupportedCpuArch();2056 try self.reportUnsupportedCpuArch();
2056 return error.FlushFailure;2057 return error.FlushFailure;
2057 },2058 },
2059 error.RelocFailure => has_reloc_errors = true,
2058 else => |e| return e,2060 else => |e| return e,
2059 };2061 };
2060 }2062 }
20612063
2062 try self.reportUndefinedSymbols(&undefs);2064 try self.reportUndefinedSymbols(&undefs);
20632065
2066 if (has_reloc_errors) return error.FlushFailure;
2067
2064 for (self.symbols.items, 0..) |*sym, i| {2068 for (self.symbols.items, 0..) |*sym, i| {
2065 const index = @as(u32, @intCast(i));2069 const index = @as(u32, @intCast(i));
2066 if (!sym.isLocal(self) and !sym.flags.has_dynamic) {2070 if (!sym.isLocal(self) and !sym.flags.has_dynamic) {
...@@ -4449,6 +4453,8 @@ fn writeAtoms(self: *Elf) !void {...@@ -4449,6 +4453,8 @@ fn writeAtoms(self: *Elf) !void {
4449 undefs.deinit();4453 undefs.deinit();
4450 }4454 }
44514455
4456 var has_reloc_errors = false;
4457
4452 // TODO iterate over `output_sections` directly4458 // TODO iterate over `output_sections` directly
4453 for (self.shdrs.items, 0..) |shdr, shndx| {4459 for (self.shdrs.items, 0..) |shdr, shndx| {
4454 if (shdr.sh_type == elf.SHT_NULL) continue;4460 if (shdr.sh_type == elf.SHT_NULL) continue;
...@@ -4519,6 +4525,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -4519,6 +4525,7 @@ fn writeAtoms(self: *Elf) !void {
4519 try self.reportUnsupportedCpuArch();4525 try self.reportUnsupportedCpuArch();
4520 return error.FlushFailure;4526 return error.FlushFailure;
4521 },4527 },
4528 error.RelocFailure => has_reloc_errors = true,
4522 else => |e| return e,4529 else => |e| return e,
4523 };4530 };
4524 }4531 }
...@@ -4527,6 +4534,8 @@ fn writeAtoms(self: *Elf) !void {...@@ -4527,6 +4534,8 @@ fn writeAtoms(self: *Elf) !void {
4527 }4534 }
45284535
4529 try self.reportUndefinedSymbols(&undefs);4536 try self.reportUndefinedSymbols(&undefs);
4537
4538 if (has_reloc_errors) return error.FlushFailure;
4530}4539}
45314540
4532pub fn updateSymtabSize(self: *Elf) !void {4541pub fn updateSymtabSize(self: *Elf) !void {
src/link/Elf/Atom.zig+189-138
...@@ -300,7 +300,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -300,7 +300,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
300 self.* = .{};300 self.* = .{};
301}301}
302302
303pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {303pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela {
304 const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};304 const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};
305 return switch (self.file(elf_file).?) {305 return switch (self.file(elf_file).?) {
306 .zig_object => |x| x.relocs.items[shndx].items,306 .zig_object => |x| x.relocs.items[shndx].items,
...@@ -394,11 +394,54 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {...@@ -394,11 +394,54 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {
394 return false;394 return false;
395}395}
396396
397pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void {397pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) RelocError!void {
398 switch (elf_file.getTarget().cpu.arch) {398 const cpu_arch = elf_file.getTarget().cpu.arch;
399 .x86_64 => try x86_64.scanRelocs(self, elf_file, code, undefs),399 const file_ptr = self.file(elf_file).?;
400 else => return error.UnsupportedCpuArch,400 const rels = self.relocs(elf_file);
401
402 var has_reloc_errors = false;
403 var it = RelocsIterator{ .relocs = rels };
404 while (it.next()) |rel| {
405 const r_kind = relocation.decode(rel.r_type(), cpu_arch);
406 if (r_kind == .none) continue;
407
408 const symbol_index = switch (file_ptr) {
409 .zig_object => |x| x.symbol(rel.r_sym()),
410 .object => |x| x.symbols.items[rel.r_sym()],
411 else => unreachable,
412 };
413 const symbol = elf_file.symbol(symbol_index);
414
415 // Check for violation of One Definition Rule for COMDATs.
416 if (symbol.file(elf_file) == null) {
417 // TODO convert into an error
418 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
419 file_ptr.fmtPath(),
420 self.name(elf_file),
421 symbol.name(elf_file),
422 });
423 continue;
424 }
425
426 // Report an undefined symbol.
427 if (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs)) continue;
428
429 if (symbol.isIFunc(elf_file)) {
430 symbol.flags.needs_got = true;
431 symbol.flags.needs_plt = true;
432 }
433
434 // While traversing relocations, mark symbols that require special handling such as
435 // pointer indirection via GOT, or a stub trampoline via PLT.
436 switch (elf_file.getTarget().cpu.arch) {
437 .x86_64 => x86_64.scanReloc(self, elf_file, rel, symbol, code, &it) catch |err| switch (err) {
438 error.RelocFailure => has_reloc_errors = true,
439 else => |e| return e,
440 },
441 else => return error.UnsupportedCpuArch,
442 }
401 }443 }
444 if (has_reloc_errors) return error.RelocFailure;
402}445}
403446
404fn scanReloc(447fn scanReloc(
...@@ -407,7 +450,7 @@ fn scanReloc(...@@ -407,7 +450,7 @@ fn scanReloc(
407 rel: elf.Elf64_Rela,450 rel: elf.Elf64_Rela,
408 action: RelocAction,451 action: RelocAction,
409 elf_file: *Elf,452 elf_file: *Elf,
410) error{OutOfMemory}!void {453) RelocError!void {
411 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;454 const is_writeable = self.inputShdr(elf_file).sh_flags & elf.SHF_WRITE != 0;
412 const num_dynrelocs = switch (self.file(elf_file).?) {455 const num_dynrelocs = switch (self.file(elf_file).?) {
413 .linker_defined => unreachable,456 .linker_defined => unreachable,
...@@ -554,7 +597,7 @@ fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 {...@@ -554,7 +597,7 @@ fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 {
554 return 3;597 return 3;
555}598}
556599
557fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) error{OutOfMemory}!void {600fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) RelocError!void {
558 var err = try elf_file.addErrorWithNotes(1);601 var err = try elf_file.addErrorWithNotes(1);
559 try err.addMsg(elf_file, "fatal linker error: unhandled relocation type {} at offset 0x{x}", .{602 try err.addMsg(elf_file, "fatal linker error: unhandled relocation type {} at offset 0x{x}", .{
560 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),603 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
...@@ -564,6 +607,7 @@ fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) er...@@ -564,6 +607,7 @@ fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) er
564 self.file(elf_file).?.fmtPath(),607 self.file(elf_file).?.fmtPath(),
565 self.name(elf_file),608 self.name(elf_file),
566 });609 });
610 return error.RelocFailure;
567}611}
568612
569fn reportTextRelocError(613fn reportTextRelocError(
...@@ -571,7 +615,7 @@ fn reportTextRelocError(...@@ -571,7 +615,7 @@ fn reportTextRelocError(
571 symbol: *const Symbol,615 symbol: *const Symbol,
572 rel: elf.Elf64_Rela,616 rel: elf.Elf64_Rela,
573 elf_file: *Elf,617 elf_file: *Elf,
574) error{OutOfMemory}!void {618) RelocError!void {
575 var err = try elf_file.addErrorWithNotes(1);619 var err = try elf_file.addErrorWithNotes(1);
576 try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{620 try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{
577 rel.r_offset,621 rel.r_offset,
...@@ -581,6 +625,7 @@ fn reportTextRelocError(...@@ -581,6 +625,7 @@ fn reportTextRelocError(
581 self.file(elf_file).?.fmtPath(),625 self.file(elf_file).?.fmtPath(),
582 self.name(elf_file),626 self.name(elf_file),
583 });627 });
628 return error.RelocFailure;
584}629}
585630
586fn reportPicError(631fn reportPicError(
...@@ -588,7 +633,7 @@ fn reportPicError(...@@ -588,7 +633,7 @@ fn reportPicError(
588 symbol: *const Symbol,633 symbol: *const Symbol,
589 rel: elf.Elf64_Rela,634 rel: elf.Elf64_Rela,
590 elf_file: *Elf,635 elf_file: *Elf,
591) error{OutOfMemory}!void {636) RelocError!void {
592 var err = try elf_file.addErrorWithNotes(2);637 var err = try elf_file.addErrorWithNotes(2);
593 try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{638 try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{
594 rel.r_offset,639 rel.r_offset,
...@@ -599,6 +644,7 @@ fn reportPicError(...@@ -599,6 +644,7 @@ fn reportPicError(
599 self.name(elf_file),644 self.name(elf_file),
600 });645 });
601 try err.addNote(elf_file, "recompile with -fPIC", .{});646 try err.addNote(elf_file, "recompile with -fPIC", .{});
647 return error.RelocFailure;
602}648}
603649
604fn reportNoPicError(650fn reportNoPicError(
...@@ -606,7 +652,7 @@ fn reportNoPicError(...@@ -606,7 +652,7 @@ fn reportNoPicError(
606 symbol: *const Symbol,652 symbol: *const Symbol,
607 rel: elf.Elf64_Rela,653 rel: elf.Elf64_Rela,
608 elf_file: *Elf,654 elf_file: *Elf,
609) error{OutOfMemory}!void {655) RelocError!void {
610 var err = try elf_file.addErrorWithNotes(2);656 var err = try elf_file.addErrorWithNotes(2);
611 try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{657 try err.addMsg(elf_file, "relocation at offset 0x{x} against symbol '{s}' cannot be used", .{
612 rel.r_offset,658 rel.r_offset,
...@@ -617,6 +663,7 @@ fn reportNoPicError(...@@ -617,6 +663,7 @@ fn reportNoPicError(
617 self.name(elf_file),663 self.name(elf_file),
618 });664 });
619 try err.addNote(elf_file, "recompile with -fno-PIC", .{});665 try err.addNote(elf_file, "recompile with -fno-PIC", .{});
666 return error.RelocFailure;
620}667}
621668
622// This function will report any undefined non-weak symbols that are not imports.669// This function will report any undefined non-weak symbols that are not imports.
...@@ -627,7 +674,7 @@ fn reportUndefined(...@@ -627,7 +674,7 @@ fn reportUndefined(
627 sym_index: Symbol.Index,674 sym_index: Symbol.Index,
628 rel: elf.Elf64_Rela,675 rel: elf.Elf64_Rela,
629 undefs: anytype,676 undefs: anytype,
630) !void {677) !bool {
631 const comp = elf_file.base.comp;678 const comp = elf_file.base.comp;
632 const gpa = comp.gpa;679 const gpa = comp.gpa;
633 const rel_esym = switch (self.file(elf_file).?) {680 const rel_esym = switch (self.file(elf_file).?) {
...@@ -647,7 +694,10 @@ fn reportUndefined(...@@ -647,7 +694,10 @@ fn reportUndefined(
647 gop.value_ptr.* = std.ArrayList(Atom.Index).init(gpa);694 gop.value_ptr.* = std.ArrayList(Atom.Index).init(gpa);
648 }695 }
649 try gop.value_ptr.append(self.atom_index);696 try gop.value_ptr.append(self.atom_index);
697 return true;
650 }698 }
699
700 return false;
651}701}
652702
653pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {703pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
...@@ -831,152 +881,123 @@ pub const Flags = packed struct {...@@ -831,152 +881,123 @@ pub const Flags = packed struct {
831};881};
832882
833const x86_64 = struct {883const x86_64 = struct {
834 fn scanRelocs(atom: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void {884 fn scanReloc(
885 atom: Atom,
886 elf_file: *Elf,
887 rel: elf.Elf64_Rela,
888 symbol: *Symbol,
889 code: ?[]const u8,
890 it: *RelocsIterator,
891 ) !void {
835 const is_static = elf_file.base.isStatic();892 const is_static = elf_file.base.isStatic();
836 const is_dyn_lib = elf_file.base.isDynLib();893 const is_dyn_lib = elf_file.base.isDynLib();
837 const file_ptr = atom.file(elf_file).?;
838 const rels = atom.relocs(elf_file);
839 var i: usize = 0;
840 while (i < rels.len) : (i += 1) {
841 const rel = rels[i];
842 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
843
844 if (r_type == .NONE) continue;
845
846 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
847894
848 const symbol_index = switch (file_ptr) {895 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
849 .zig_object => |x| x.symbol(rel.r_sym()),896 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
850 .object => |x| x.symbols.items[rel.r_sym()],
851 else => unreachable,
852 };
853 const symbol = elf_file.symbol(symbol_index);
854897
855 // Check for violation of One Definition Rule for COMDATs.898 switch (r_type) {
856 if (symbol.file(elf_file) == null) {899 .@"64" => {
857 // TODO convert into an error900 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
858 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{901 },
859 file_ptr.fmtPath(),
860 atom.name(elf_file),
861 symbol.name(elf_file),
862 });
863 continue;
864 }
865902
866 // Report an undefined symbol.903 .@"32",
867 try atom.reportUndefined(elf_file, symbol, symbol_index, rel, undefs);904 .@"32S",
905 => {
906 try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file);
907 },
868908
869 if (symbol.isIFunc(elf_file)) {909 .GOT32,
910 .GOTPC32,
911 .GOTPC64,
912 .GOTPCREL,
913 .GOTPCREL64,
914 .GOTPCRELX,
915 .REX_GOTPCRELX,
916 => {
870 symbol.flags.needs_got = true;917 symbol.flags.needs_got = true;
871 symbol.flags.needs_plt = true;918 },
872 }
873
874 // While traversing relocations, mark symbols that require special handling such as
875 // pointer indirection via GOT, or a stub trampoline via PLT.
876 switch (r_type) {
877 .@"64" => {
878 try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
879 },
880
881 .@"32",
882 .@"32S",
883 => {
884 try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file);
885 },
886919
887 .GOT32,920 .PLT32,
888 .GOTPC32,921 .PLTOFF64,
889 .GOTPC64,922 => {
890 .GOTPCREL,923 if (symbol.flags.import) {
891 .GOTPCREL64,924 symbol.flags.needs_plt = true;
892 .GOTPCRELX,925 }
893 .REX_GOTPCRELX,926 },
894 => {
895 symbol.flags.needs_got = true;
896 },
897927
898 .PLT32,928 .PC32 => {
899 .PLTOFF64,929 try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);
900 => {930 },
901 if (symbol.flags.import) {
902 symbol.flags.needs_plt = true;
903 }
904 },
905931
906 .PC32 => {932 .TLSGD => {
907 try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);933 // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr
908 },
909934
910 .TLSGD => {935 if (is_static or (!symbol.flags.import and !is_dyn_lib)) {
911 // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr936 // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a
937 // We skip the next relocation.
938 it.skip(1);
939 } else if (!symbol.flags.import and is_dyn_lib) {
940 symbol.flags.needs_gottp = true;
941 it.skip(1);
942 } else {
943 symbol.flags.needs_tlsgd = true;
944 }
945 },
912946
913 if (is_static or (!symbol.flags.import and !is_dyn_lib)) {947 .TLSLD => {
914 // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a948 // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr
915 // We skip the next relocation.
916 i += 1;
917 } else if (!symbol.flags.import and is_dyn_lib) {
918 symbol.flags.needs_gottp = true;
919 i += 1;
920 } else {
921 symbol.flags.needs_tlsgd = true;
922 }
923 },
924949
925 .TLSLD => {950 if (is_static or !is_dyn_lib) {
926 // TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr951 // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a
952 // We skip the next relocation.
953 it.skip(1);
954 } else {
955 elf_file.got.flags.needs_tlsld = true;
956 }
957 },
927958
928 if (is_static or !is_dyn_lib) {959 .GOTTPOFF => {
929 // Relax if building with -static flag as __tls_get_addr() will not be present in libc.a960 const should_relax = blk: {
930 // We skip the next relocation.961 if (is_dyn_lib or symbol.flags.import) break :blk false;
931 i += 1;962 if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..])) break :blk false;
932 } else {963 break :blk true;
933 elf_file.got.flags.needs_tlsld = true;964 };
934 }965 if (!should_relax) {
935 },966 symbol.flags.needs_gottp = true;
967 }
968 },
936969
937 .GOTTPOFF => {970 .GOTPC32_TLSDESC => {
938 const should_relax = blk: {971 const should_relax = is_static or (!is_dyn_lib and !symbol.flags.import);
939 if (is_dyn_lib or symbol.flags.import) break :blk false;972 if (!should_relax) {
940 if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..])) break :blk false;973 symbol.flags.needs_tlsdesc = true;
941 break :blk true;974 }
942 };975 },
943 if (!should_relax) {
944 symbol.flags.needs_gottp = true;
945 }
946 },
947976
948 .GOTPC32_TLSDESC => {977 .TPOFF32,
949 const should_relax = is_static or (!is_dyn_lib and !symbol.flags.import);978 .TPOFF64,
950 if (!should_relax) {979 => {
951 symbol.flags.needs_tlsdesc = true;980 if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);
952 }981 },
953 },
954982
955 .TPOFF32,983 .GOTOFF64,
956 .TPOFF64,984 .DTPOFF32,
985 .DTPOFF64,
986 .SIZE32,
987 .SIZE64,
988 .TLSDESC_CALL,
989 => {},
990
991 else => |x| switch (@intFromEnum(x)) {
992 // Zig custom relocations
993 Elf.R_ZIG_GOT32,
994 Elf.R_ZIG_GOTPCREL,
957 => {995 => {
958 if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);996 assert(symbol.flags.has_zig_got);
959 },997 },
960998
961 .GOTOFF64,999 else => try atom.reportUnhandledRelocError(rel, elf_file),
962 .DTPOFF32,1000 },
963 .DTPOFF64,
964 .SIZE32,
965 .SIZE64,
966 .TLSDESC_CALL,
967 => {},
968
969 else => |x| switch (@intFromEnum(x)) {
970 // Zig custom relocations
971 Elf.R_ZIG_GOT32,
972 Elf.R_ZIG_GOTPCREL,
973 => {
974 assert(symbol.flags.has_zig_got);
975 },
976
977 else => try atom.reportUnhandledRelocError(rel, elf_file),
978 },
979 }
980 }1001 }
981 }1002 }
9821003
...@@ -1195,7 +1216,7 @@ const x86_64 = struct {...@@ -1195,7 +1216,7 @@ const x86_64 = struct {
1195 }1216 }
11961217
1197 // Report an undefined symbol.1218 // Report an undefined symbol.
1198 try atom.reportUndefined(elf_file, target, target_index, rel, undefs);1219 if (try atom.reportUndefined(elf_file, target, target_index, rel, undefs)) continue;
11991220
1200 // We will use equation format to resolve relocations:1221 // We will use equation format to resolve relocations:
1201 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/1222 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
...@@ -1485,6 +1506,36 @@ const x86_64 = struct {...@@ -1485,6 +1506,36 @@ const x86_64 = struct {
1485 const Instruction = encoder.Instruction;1506 const Instruction = encoder.Instruction;
1486};1507};
14871508
1509const RelocError = error{
1510 Overflow,
1511 OutOfMemory,
1512 RelocFailure,
1513 UnsupportedCpuArch,
1514};
1515
1516const RelocsIterator = struct {
1517 relocs: []const elf.Elf64_Rela,
1518 pos: i64 = -1,
1519
1520 fn next(it: *RelocsIterator) ?elf.Elf64_Rela {
1521 it.pos += 1;
1522 if (it.pos >= it.relocs.len) return null;
1523 return it.relocs[@intCast(it.pos)];
1524 }
1525
1526 fn prev(it: *RelocsIterator) ?elf.Elf64_Rela {
1527 if (it.pos == -1) return null;
1528 const rel = it.relocs[@intCast(it.pos)];
1529 it.pos -= 1;
1530 return rel;
1531 }
1532
1533 fn skip(it: *RelocsIterator, num: usize) void {
1534 assert(num > 0);
1535 it.pos += @intCast(num);
1536 }
1537};
1538
1488const std = @import("std");1539const std = @import("std");
1489const assert = std.debug.assert;1540const assert = std.debug.assert;
1490const elf = std.elf;1541const elf = std.elf;
src/link/Elf/relocation.zig+11-6
...@@ -1,4 +1,6 @@...@@ -1,4 +1,6 @@
1pub const Kind = enum {1pub const Kind = enum {
2 none,
3 other,
2 abs,4 abs,
3 copy,5 copy,
4 rel,6 rel,
...@@ -13,23 +15,24 @@ pub const Kind = enum {...@@ -13,23 +15,24 @@ pub const Kind = enum {
1315
14fn Table(comptime len: comptime_int, comptime RelType: type, comptime mapping: [len]struct { Kind, RelType }) type {16fn Table(comptime len: comptime_int, comptime RelType: type, comptime mapping: [len]struct { Kind, RelType }) type {
15 return struct {17 return struct {
16 fn decode(r_type: u32) ?Kind {18 fn decode(r_type: u32) Kind {
17 inline for (mapping) |entry| {19 inline for (mapping) |entry| {
18 if (@intFromEnum(entry[1]) == r_type) return entry[0];20 if (@intFromEnum(entry[1]) == r_type) return entry[0];
19 }21 }
20 return null;22 return .other;
21 }23 }
2224
23 fn encode(comptime kind: Kind) u32 {25 fn encode(comptime kind: Kind) u32 {
24 inline for (mapping) |entry| {26 inline for (mapping) |entry| {
25 if (entry[0] == kind) return @intFromEnum(entry[1]);27 if (entry[0] == kind) return @intFromEnum(entry[1]);
26 }28 }
27 unreachable;29 @panic("encoding .other is ambiguous");
28 }30 }
29 };31 };
30}32}
3133
32const x86_64_relocs = Table(10, elf.R_X86_64, .{34const x86_64_relocs = Table(11, elf.R_X86_64, .{
35 .{ .none, .NONE },
33 .{ .abs, .@"64" },36 .{ .abs, .@"64" },
34 .{ .copy, .COPY },37 .{ .copy, .COPY },
35 .{ .rel, .RELATIVE },38 .{ .rel, .RELATIVE },
...@@ -42,7 +45,8 @@ const x86_64_relocs = Table(10, elf.R_X86_64, .{...@@ -42,7 +45,8 @@ const x86_64_relocs = Table(10, elf.R_X86_64, .{
42 .{ .tlsdesc, .TLSDESC },45 .{ .tlsdesc, .TLSDESC },
43});46});
4447
45const aarch64_relocs = Table(10, elf.R_AARCH64, .{48const aarch64_relocs = Table(11, elf.R_AARCH64, .{
49 .{ .none, .NONE },
46 .{ .abs, .ABS64 },50 .{ .abs, .ABS64 },
47 .{ .copy, .COPY },51 .{ .copy, .COPY },
48 .{ .rel, .RELATIVE },52 .{ .rel, .RELATIVE },
...@@ -55,7 +59,8 @@ const aarch64_relocs = Table(10, elf.R_AARCH64, .{...@@ -55,7 +59,8 @@ const aarch64_relocs = Table(10, elf.R_AARCH64, .{
55 .{ .tlsdesc, .TLSDESC },59 .{ .tlsdesc, .TLSDESC },
56});60});
5761
58const riscv64_relocs = Table(10, elf.R_RISCV, .{62const riscv64_relocs = Table(11, elf.R_RISCV, .{
63 .{ .none, .NONE },
59 .{ .abs, .@"64" },64 .{ .abs, .@"64" },
60 .{ .copy, .COPY },65 .{ .copy, .COPY },
61 .{ .rel, .RELATIVE },66 .{ .rel, .RELATIVE },