authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 20:11:32+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 20:11:32+01:00
log4cde47a169efc3d2dc70f057742e65b088e139a3
tree26901a8c10681769372c72c6a6cd6e2602033920
parent60bc2e7616b0fd42c98ba8b9e0b212439b6ea1a0

elf: simplify logic for resolving alloc relocs on different arches


2 files changed, 229 insertions(+), 193 deletions(-)

src/link/Elf.zig+6-9
...@@ -1344,6 +1344,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)...@@ -1344,6 +1344,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
1344 // Beyond this point, everything has been allocated a virtual address and we can resolve1344 // Beyond this point, everything has been allocated a virtual address and we can resolve
1345 // the relocations, and commit objects to file.1345 // the relocations, and commit objects to file.
1346 if (self.zigObjectPtr()) |zig_object| {1346 if (self.zigObjectPtr()) |zig_object| {
1347 var has_reloc_errors = false;
1347 for (zig_object.atoms.items) |atom_index| {1348 for (zig_object.atoms.items) |atom_index| {
1348 const atom_ptr = self.atom(atom_index) orelse continue;1349 const atom_ptr = self.atom(atom_index) orelse continue;
1349 if (!atom_ptr.flags.alive) continue;1350 if (!atom_ptr.flags.alive) continue;
...@@ -1354,10 +1355,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)...@@ -1354,10 +1355,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
1354 defer gpa.free(code);1355 defer gpa.free(code);
1355 const file_offset = shdr.sh_offset + atom_ptr.value;1356 const file_offset = shdr.sh_offset + atom_ptr.value;
1356 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {1357 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
1357 // TODO1358 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
1358 error.RelaxFail, error.InvalidInstruction, error.CannotEncode => {
1359 log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{});
1360 },
1361 error.UnsupportedCpuArch => {1359 error.UnsupportedCpuArch => {
1362 try self.reportUnsupportedCpuArch();1360 try self.reportUnsupportedCpuArch();
1363 return error.FlushFailure;1361 return error.FlushFailure;
...@@ -1366,6 +1364,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)...@@ -1366,6 +1364,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
1366 };1364 };
1367 try self.base.file.?.pwriteAll(code, file_offset);1365 try self.base.file.?.pwriteAll(code, file_offset);
1368 }1366 }
1367
1368 if (has_reloc_errors) return error.FlushFailure;
1369 }1369 }
13701370
1371 try self.writePhdrTable();1371 try self.writePhdrTable();
...@@ -2052,6 +2052,7 @@ fn scanRelocs(self: *Elf) !void {...@@ -2052,6 +2052,7 @@ fn scanRelocs(self: *Elf) !void {
2052 var has_reloc_errors = false;2052 var has_reloc_errors = false;
2053 for (objects.items) |index| {2053 for (objects.items) |index| {
2054 self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) {2054 self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) {
2055 error.RelaxFailure => unreachable,
2055 error.UnsupportedCpuArch => {2056 error.UnsupportedCpuArch => {
2056 try self.reportUnsupportedCpuArch();2057 try self.reportUnsupportedCpuArch();
2057 return error.FlushFailure;2058 return error.FlushFailure;
...@@ -4517,15 +4518,11 @@ fn writeAtoms(self: *Elf) !void {...@@ -4517,15 +4518,11 @@ fn writeAtoms(self: *Elf) !void {
4517 else4518 else
4518 atom_ptr.resolveRelocsAlloc(self, out_code);4519 atom_ptr.resolveRelocsAlloc(self, out_code);
4519 _ = res catch |err| switch (err) {4520 _ = res catch |err| switch (err) {
4520 // TODO
4521 error.RelaxFail, error.InvalidInstruction, error.CannotEncode => {
4522 log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{});
4523 },
4524 error.UnsupportedCpuArch => {4521 error.UnsupportedCpuArch => {
4525 try self.reportUnsupportedCpuArch();4522 try self.reportUnsupportedCpuArch();
4526 return error.FlushFailure;4523 return error.FlushFailure;
4527 },4524 },
4528 error.RelocFailure => has_reloc_errors = true,4525 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
4529 else => |e| return e,4526 else => |e| return e,
4530 };4527 };
4531 }4528 }
src/link/Elf/Atom.zig+223-184
...@@ -700,13 +700,82 @@ fn reportUndefined(...@@ -700,13 +700,82 @@ fn reportUndefined(
700 return false;700 return false;
701}701}
702702
703pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {703pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!void {
704 relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });704 relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });
705705
706 switch (elf_file.getTarget().cpu.arch) {706 const cpu_arch = elf_file.getTarget().cpu.arch;
707 .x86_64 => try x86_64.resolveRelocsAlloc(self, elf_file, code),707 const file_ptr = self.file(elf_file).?;
708 else => return error.UnsupportedCpuArch,708 var stream = std.io.fixedBufferStream(code);
709
710 const rels = self.relocs(elf_file);
711 var it = RelocsIterator{ .relocs = rels };
712 var has_reloc_errors = false;
713 while (it.next()) |rel| {
714 const r_kind = relocation.decode(rel.r_type(), cpu_arch);
715 if (r_kind == .none) continue;
716
717 const target = switch (file_ptr) {
718 .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),
719 .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
720 else => unreachable,
721 };
722 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
723
724 // We will use equation format to resolve relocations:
725 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
726 //
727 // Address of the source atom.
728 const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset));
729 // Addend from the relocation.
730 const A = rel.r_addend;
731 // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
732 const S = @as(i64, @intCast(target.address(.{}, elf_file)));
733 // Address of the global offset table.
734 const GOT = blk: {
735 const shndx = if (elf_file.got_plt_section_index) |shndx|
736 shndx
737 else if (elf_file.got_section_index) |shndx|
738 shndx
739 else
740 null;
741 break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0;
742 };
743 // Address of the .zig.got table entry if any.
744 const ZIG_GOT = @as(i64, @intCast(target.zigGotAddress(elf_file)));
745 // Relative offset to the start of the global offset table.
746 const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT;
747 // // Address of the thread pointer.
748 const TP = @as(i64, @intCast(elf_file.tpAddress()));
749 // Address of the dynamic thread pointer.
750 const DTP = @as(i64, @intCast(elf_file.dtpAddress()));
751
752 relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{
753 relocation.fmtRelocType(rel.r_type(), cpu_arch),
754 r_offset,
755 P,
756 S + A,
757 G + GOT + A,
758 ZIG_GOT + A,
759 target.name(elf_file),
760 });
761
762 try stream.seekTo(r_offset);
763
764 const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP, ZIG_GOT };
765
766 switch (cpu_arch) {
767 .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
768 error.RelaxFailure,
769 error.InvalidInstruction,
770 error.CannotEncode,
771 => has_reloc_errors = true,
772 else => |e| return e,
773 },
774 else => return error.UnsupportedCpuArch,
775 }
709 }776 }
777
778 if (has_reloc_errors) return error.RelaxFailure;
710}779}
711780
712fn resolveDynAbsReloc(781fn resolveDynAbsReloc(
...@@ -1001,185 +1070,148 @@ const x86_64 = struct {...@@ -1001,185 +1070,148 @@ const x86_64 = struct {
1001 }1070 }
1002 }1071 }
10031072
1004 fn resolveRelocsAlloc(atom: Atom, elf_file: *Elf, code: []u8) !void {1073 fn resolveRelocAlloc(
1005 const file_ptr = atom.file(elf_file).?;1074 atom: Atom,
1006 var stream = std.io.fixedBufferStream(code);1075 elf_file: *Elf,
1007 const cwriter = stream.writer();1076 rel: elf.Elf64_Rela,
10081077 target: *const Symbol,
1009 const rels = atom.relocs(elf_file);1078 args: ResolveArgs,
1010 var i: usize = 0;1079 it: *RelocsIterator,
1011 while (i < rels.len) : (i += 1) {1080 code: []u8,
1012 const rel = rels[i];1081 stream: anytype,
1013 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());1082 ) (error{ InvalidInstruction, CannotEncode } || RelocError)!void {
1014 if (r_type == .NONE) continue;1083 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
10151084 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
1016 const target = switch (file_ptr) {
1017 .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),
1018 .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
1019 else => unreachable,
1020 };
1021 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
1022
1023 // We will use equation format to resolve relocations:
1024 // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
1025 //
1026 // Address of the source atom.
1027 const P = @as(i64, @intCast(atom.address(elf_file) + rel.r_offset));
1028 // Addend from the relocation.
1029 const A = rel.r_addend;
1030 // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
1031 const S = @as(i64, @intCast(target.address(.{}, elf_file)));
1032 // Address of the global offset table.
1033 const GOT = blk: {
1034 const shndx = if (elf_file.got_plt_section_index) |shndx|
1035 shndx
1036 else if (elf_file.got_section_index) |shndx|
1037 shndx
1038 else
1039 null;
1040 break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0;
1041 };
1042 // Address of the .zig.got table entry if any.
1043 const ZIG_GOT = @as(i64, @intCast(target.zigGotAddress(elf_file)));
1044 // Relative offset to the start of the global offset table.
1045 const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT;
1046 // // Address of the thread pointer.
1047 const TP = @as(i64, @intCast(elf_file.tpAddress()));
1048 // Address of the dynamic thread pointer.
1049 const DTP = @as(i64, @intCast(elf_file.dtpAddress()));
10501085
1051 relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{1086 const cwriter = stream.writer();
1052 relocation.fmtRelocType(rel.r_type(), .x86_64),
1053 r_offset,
1054 P,
1055 S + A,
1056 G + GOT + A,
1057 ZIG_GOT + A,
1058 target.name(elf_file),
1059 });
10601087
1061 try stream.seekTo(r_offset);1088 const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;
10621089
1063 switch (r_type) {1090 switch (r_type) {
1064 .NONE => unreachable,1091 .NONE => unreachable,
10651092
1066 .@"64" => {1093 .@"64" => {
1067 try atom.resolveDynAbsReloc(1094 try atom.resolveDynAbsReloc(
1068 target,1095 target,
1069 rel,1096 rel,
1070 dynAbsRelocAction(target, elf_file),1097 dynAbsRelocAction(target, elf_file),
1071 elf_file,1098 elf_file,
1072 cwriter,1099 cwriter,
1073 );1100 );
1074 },1101 },
10751102
1076 .PLT32,1103 .PLT32,
1077 .PC32,1104 .PC32,
1078 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),1105 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
10791106
1080 .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),1107 .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
1081 .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),1108 .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
1082 .GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little),1109 .GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little),
10831110
1084 .GOTPCRELX => {1111 .GOTPCRELX => {
1085 if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {1112 if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
1086 x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk;1113 x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk;
1087 try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);1114 try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
1088 continue;1115 return;
1089 }1116 }
1090 try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);1117 try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
1091 },1118 },
10921119
1093 .REX_GOTPCRELX => {1120 .REX_GOTPCRELX => {
1094 if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {1121 if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
1095 x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk;1122 x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk;
1096 try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);1123 try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
1097 continue;1124 return;
1098 }1125 }
1099 try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);1126 try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
1100 },1127 },
11011128
1102 .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),1129 .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
1103 .@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),1130 .@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),
11041131
1105 .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),1132 .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),
1106 .TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little),1133 .TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little),
11071134
1108 .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little),1135 .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little),
1109 .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),1136 .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),
11101137
1111 .TLSGD => {1138 .TLSGD => {
1112 if (target.flags.has_tlsgd) {1139 if (target.flags.has_tlsgd) {
1113 const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file)));1140 const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file)));
1114 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1141 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1115 } else if (target.flags.has_gottp) {1142 } else if (target.flags.has_gottp) {
1116 const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));1143 const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));
1117 try x86_64.relaxTlsGdToIe(atom, rels[i .. i + 2], @intCast(S_ - P), elf_file, &stream);1144 try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream);
1118 i += 1;1145 } else {
1119 } else {1146 try x86_64.relaxTlsGdToLe(
1120 try x86_64.relaxTlsGdToLe(1147 atom,
1121 atom,1148 &.{ rel, it.next().? },
1122 rels[i .. i + 2],1149 @as(i32, @intCast(S - TP)),
1123 @as(i32, @intCast(S - TP)),1150 elf_file,
1124 elf_file,1151 stream,
1125 &stream,1152 );
1126 );1153 }
1127 i += 1;1154 },
1128 }
1129 },
11301155
1131 .TLSLD => {1156 .TLSLD => {
1132 if (elf_file.got.tlsld_index) |entry_index| {1157 if (elf_file.got.tlsld_index) |entry_index| {
1133 const tlsld_entry = elf_file.got.entries.items[entry_index];1158 const tlsld_entry = elf_file.got.entries.items[entry_index];
1134 const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file)));1159 const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file)));
1135 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1160 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1136 } else {1161 } else {
1137 try x86_64.relaxTlsLdToLe(1162 try x86_64.relaxTlsLdToLe(
1138 atom,1163 atom,
1139 rels[i .. i + 2],1164 &.{ rel, it.next().? },
1140 @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))),1165 @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))),
1141 elf_file,1166 elf_file,
1142 &stream,1167 stream,
1143 );1168 );
1144 i += 1;1169 }
1145 }1170 },
1146 },
11471171
1148 .GOTPC32_TLSDESC => {1172 .GOTPC32_TLSDESC => {
1149 if (target.flags.has_tlsdesc) {1173 if (target.flags.has_tlsdesc) {
1150 const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file)));1174 const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file)));
1151 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1175 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1152 } else {1176 } else {
1153 try x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]);1177 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {
1154 try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);1178 var err = try elf_file.addErrorWithNotes(1);
1155 }1179 try err.addMsg(elf_file, "could not relax {s}", .{@tagName(r_type)});
1156 },1180 try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{
1181 atom.file(elf_file).?.fmtPath(),
1182 atom.name(elf_file),
1183 rel.r_offset,
1184 });
1185 return error.RelaxFailure;
1186 };
1187 try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
1188 }
1189 },
11571190
1158 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {1191 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
1159 // call -> nop1192 // call -> nop
1160 try cwriter.writeAll(&.{ 0x66, 0x90 });1193 try cwriter.writeAll(&.{ 0x66, 0x90 });
1161 },1194 },
11621195
1163 .GOTTPOFF => {1196 .GOTTPOFF => {
1164 if (target.flags.has_gottp) {1197 if (target.flags.has_gottp) {
1165 const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));1198 const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));
1166 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);1199 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1167 } else {1200 } else {
1168 x86_64.relaxGotTpOff(code[r_offset - 3 ..]) catch unreachable;1201 x86_64.relaxGotTpOff(code[r_offset - 3 ..]);
1169 try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);1202 try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
1170 }1203 }
1171 },1204 },
11721205
1173 .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),1206 .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),
11741207
1175 else => |x| switch (@intFromEnum(x)) {1208 else => |x| switch (@intFromEnum(x)) {
1176 // Zig custom relocations1209 // Zig custom relocations
1177 Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little),1210 Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little),
1178 Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little),1211 Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little),
11791212
1180 else => {},1213 else => {},
1181 },1214 },
1182 }
1183 }1215 }
1184 }1216 }
11851217
...@@ -1274,7 +1306,7 @@ const x86_64 = struct {...@@ -1274,7 +1306,7 @@ const x86_64 = struct {
1274 }1306 }
12751307
1276 fn relaxGotpcrelx(code: []u8) !void {1308 fn relaxGotpcrelx(code: []u8) !void {
1277 const old_inst = disassemble(code) orelse return error.RelaxFail;1309 const old_inst = disassemble(code) orelse return error.RelaxFailure;
1278 const inst = switch (old_inst.encoding.mnemonic) {1310 const inst = switch (old_inst.encoding.mnemonic) {
1279 .call => try Instruction.new(old_inst.prefix, .call, &.{1311 .call => try Instruction.new(old_inst.prefix, .call, &.{
1280 // TODO: hack to force imm32s in the assembler1312 // TODO: hack to force imm32s in the assembler
...@@ -1284,28 +1316,28 @@ const x86_64 = struct {...@@ -1284,28 +1316,28 @@ const x86_64 = struct {
1284 // TODO: hack to force imm32s in the assembler1316 // TODO: hack to force imm32s in the assembler
1285 .{ .imm = Immediate.s(-129) },1317 .{ .imm = Immediate.s(-129) },
1286 }),1318 }),
1287 else => return error.RelaxFail,1319 else => return error.RelaxFailure,
1288 };1320 };
1289 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });1321 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
1290 const nop = try Instruction.new(.none, .nop, &.{});1322 const nop = try Instruction.new(.none, .nop, &.{});
1291 encode(&.{ nop, inst }, code) catch return error.RelaxFail;1323 try encode(&.{ nop, inst }, code);
1292 }1324 }
12931325
1294 fn relaxRexGotpcrelx(code: []u8) !void {1326 fn relaxRexGotpcrelx(code: []u8) !void {
1295 const old_inst = disassemble(code) orelse return error.RelaxFail;1327 const old_inst = disassemble(code) orelse return error.RelaxFailure;
1296 switch (old_inst.encoding.mnemonic) {1328 switch (old_inst.encoding.mnemonic) {
1297 .mov => {1329 .mov => {
1298 const inst = try Instruction.new(old_inst.prefix, .lea, &old_inst.ops);1330 const inst = try Instruction.new(old_inst.prefix, .lea, &old_inst.ops);
1299 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });1331 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
1300 encode(&.{inst}, code) catch return error.RelaxFail;1332 try encode(&.{inst}, code);
1301 },1333 },
1302 else => return error.RelaxFail,1334 else => return error.RelaxFailure,
1303 }1335 }
1304 }1336 }
13051337
1306 fn relaxTlsGdToIe(1338 fn relaxTlsGdToIe(
1307 self: Atom,1339 self: Atom,
1308 rels: []align(1) const elf.Elf64_Rela,1340 rels: []const elf.Elf64_Rela,
1309 value: i32,1341 value: i32,
1310 elf_file: *Elf,1342 elf_file: *Elf,
1311 stream: anytype,1343 stream: anytype,
...@@ -1328,7 +1360,7 @@ const x86_64 = struct {...@@ -1328,7 +1360,7 @@ const x86_64 = struct {
13281360
1329 else => {1361 else => {
1330 var err = try elf_file.addErrorWithNotes(1);1362 var err = try elf_file.addErrorWithNotes(1);
1331 try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{1363 try err.addMsg(elf_file, "TODO: rewrite {} when followed by {}", .{
1332 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1364 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1333 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1365 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
1334 });1366 });
...@@ -1337,13 +1369,14 @@ const x86_64 = struct {...@@ -1337,13 +1369,14 @@ const x86_64 = struct {
1337 self.name(elf_file),1369 self.name(elf_file),
1338 rels[0].r_offset,1370 rels[0].r_offset,
1339 });1371 });
1372 return error.RelaxFailure;
1340 },1373 },
1341 }1374 }
1342 }1375 }
13431376
1344 fn relaxTlsLdToLe(1377 fn relaxTlsLdToLe(
1345 self: Atom,1378 self: Atom,
1346 rels: []align(1) const elf.Elf64_Rela,1379 rels: []const elf.Elf64_Rela,
1347 value: i32,1380 value: i32,
1348 elf_file: *Elf,1381 elf_file: *Elf,
1349 stream: anytype,1382 stream: anytype,
...@@ -1381,7 +1414,7 @@ const x86_64 = struct {...@@ -1381,7 +1414,7 @@ const x86_64 = struct {
13811414
1382 else => {1415 else => {
1383 var err = try elf_file.addErrorWithNotes(1);1416 var err = try elf_file.addErrorWithNotes(1);
1384 try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{1417 try err.addMsg(elf_file, "TODO: rewrite {} when followed by {}", .{
1385 relocation.fmtRelocType(rels[0].r_type(), .x86_64),1418 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
1386 relocation.fmtRelocType(rels[1].r_type(), .x86_64),1419 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
1387 });1420 });
...@@ -1390,6 +1423,7 @@ const x86_64 = struct {...@@ -1390,6 +1423,7 @@ const x86_64 = struct {
1390 self.name(elf_file),1423 self.name(elf_file),
1391 rels[0].r_offset,1424 rels[0].r_offset,
1392 });1425 });
1426 return error.RelaxFailure;
1393 },1427 },
1394 }1428 }
1395 }1429 }
...@@ -1409,24 +1443,24 @@ const x86_64 = struct {...@@ -1409,24 +1443,24 @@ const x86_64 = struct {
1409 }1443 }
1410 }1444 }
14111445
1412 fn relaxGotTpOff(code: []u8) !void {1446 fn relaxGotTpOff(code: []u8) void {
1413 const old_inst = disassemble(code) orelse return error.RelaxFail;1447 const old_inst = disassemble(code) orelse unreachable;
1414 switch (old_inst.encoding.mnemonic) {1448 switch (old_inst.encoding.mnemonic) {
1415 .mov => {1449 .mov => {
1416 const inst = try Instruction.new(old_inst.prefix, .mov, &.{1450 const inst = Instruction.new(old_inst.prefix, .mov, &.{
1417 old_inst.ops[0],1451 old_inst.ops[0],
1418 // TODO: hack to force imm32s in the assembler1452 // TODO: hack to force imm32s in the assembler
1419 .{ .imm = Immediate.s(-129) },1453 .{ .imm = Immediate.s(-129) },
1420 });1454 }) catch unreachable;
1421 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });1455 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
1422 encode(&.{inst}, code) catch return error.RelaxFail;1456 encode(&.{inst}, code) catch unreachable;
1423 },1457 },
1424 else => return error.RelaxFail,1458 else => unreachable,
1425 }1459 }
1426 }1460 }
14271461
1428 fn relaxGotPcTlsDesc(code: []u8) !void {1462 fn relaxGotPcTlsDesc(code: []u8) !void {
1429 const old_inst = disassemble(code) orelse return error.RelaxFail;1463 const old_inst = disassemble(code) orelse return error.RelaxFailure;
1430 switch (old_inst.encoding.mnemonic) {1464 switch (old_inst.encoding.mnemonic) {
1431 .lea => {1465 .lea => {
1432 const inst = try Instruction.new(old_inst.prefix, .mov, &.{1466 const inst = try Instruction.new(old_inst.prefix, .mov, &.{
...@@ -1435,15 +1469,15 @@ const x86_64 = struct {...@@ -1435,15 +1469,15 @@ const x86_64 = struct {
1435 .{ .imm = Immediate.s(-129) },1469 .{ .imm = Immediate.s(-129) },
1436 });1470 });
1437 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });1471 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
1438 encode(&.{inst}, code) catch return error.RelaxFail;1472 try encode(&.{inst}, code);
1439 },1473 },
1440 else => return error.RelaxFail,1474 else => return error.RelaxFailure,
1441 }1475 }
1442 }1476 }
14431477
1444 fn relaxTlsGdToLe(1478 fn relaxTlsGdToLe(
1445 self: Atom,1479 self: Atom,
1446 rels: []align(1) const elf.Elf64_Rela,1480 rels: []const elf.Elf64_Rela,
1447 value: i32,1481 value: i32,
1448 elf_file: *Elf,1482 elf_file: *Elf,
1449 stream: anytype,1483 stream: anytype,
...@@ -1481,6 +1515,7 @@ const x86_64 = struct {...@@ -1481,6 +1515,7 @@ const x86_64 = struct {
1481 self.name(elf_file),1515 self.name(elf_file),
1482 rels[0].r_offset,1516 rels[0].r_offset,
1483 });1517 });
1518 return error.RelaxFailure;
1484 },1519 },
1485 }1520 }
1486 }1521 }
...@@ -1506,10 +1541,14 @@ const x86_64 = struct {...@@ -1506,10 +1541,14 @@ const x86_64 = struct {
1506 const Instruction = encoder.Instruction;1541 const Instruction = encoder.Instruction;
1507};1542};
15081543
1544const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 };
1545
1509const RelocError = error{1546const RelocError = error{
1510 Overflow,1547 Overflow,
1511 OutOfMemory,1548 OutOfMemory,
1549 NoSpaceLeft,
1512 RelocFailure,1550 RelocFailure,
1551 RelaxFailure,
1513 UnsupportedCpuArch,1552 UnsupportedCpuArch,
1514};1553};
15151554