| ... | @@ -700,13 +700,82 @@ fn reportUndefined( | ... | @@ -700,13 +700,82 @@ fn reportUndefined( |
| 700 | return false; | 700 | return false; |
| 701 | } | 701 | } |
| 702 | | 702 | |
| 703 | pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { | 703 | pub 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) }); |
| 705 | | 705 | |
| 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 | } |
| 711 | | 780 | |
| 712 | fn resolveDynAbsReloc( | 781 | fn resolveDynAbsReloc( |
| ... | @@ -1001,185 +1070,148 @@ const x86_64 = struct { | ... | @@ -1001,185 +1070,148 @@ const x86_64 = struct { |
| 1001 | } | 1070 | } |
| 1002 | } | 1071 | } |
| 1003 | | 1072 | |
| 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, |
| 1008 | | 1077 | 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()); |
| 1015 | | 1084 | 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())); | | |
| 1050 | | 1085 | |
| 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 | }); | | |
| 1060 | | 1087 | |
| 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; |
| 1062 | | 1089 | |
| 1063 | switch (r_type) { | 1090 | switch (r_type) { |
| 1064 | .NONE => unreachable, | 1091 | .NONE => unreachable, |
| 1065 | | 1092 | |
| 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 | }, |
| 1075 | | 1102 | |
| 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), |
| 1079 | | 1106 | |
| 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), |
| 1083 | | 1110 | |
| 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 | }, |
| 1092 | | 1119 | |
| 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 | }, |
| 1101 | | 1128 | |
| 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), |
| 1104 | | 1131 | |
| 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), |
| 1107 | | 1134 | |
| 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), |
| 1110 | | 1137 | |
| 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 | }, | | |
| 1130 | | 1155 | |
| 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 | }, | | |
| 1147 | | 1171 | |
| 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 | }, |
| 1157 | | 1190 | |
| 1158 | .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { | 1191 | .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { |
| 1159 | // call -> nop | 1192 | // call -> nop |
| 1160 | try cwriter.writeAll(&.{ 0x66, 0x90 }); | 1193 | try cwriter.writeAll(&.{ 0x66, 0x90 }); |
| 1161 | }, | 1194 | }, |
| 1162 | | 1195 | |
| 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 | }, |
| 1172 | | 1205 | |
| 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), |
| 1174 | | 1207 | |
| 1175 | else => |x| switch (@intFromEnum(x)) { | 1208 | else => |x| switch (@intFromEnum(x)) { |
| 1176 | // Zig custom relocations | 1209 | // 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), |
| 1179 | | 1212 | |
| 1180 | else => {}, | 1213 | else => {}, |
| 1181 | }, | 1214 | }, |
| 1182 | } | | |
| 1183 | } | 1215 | } |
| 1184 | } | 1216 | } |
| 1185 | | 1217 | |
| ... | @@ -1274,7 +1306,7 @@ const x86_64 = struct { | ... | @@ -1274,7 +1306,7 @@ const x86_64 = struct { |
| 1274 | } | 1306 | } |
| 1275 | | 1307 | |
| 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 assembler | 1312 | // 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 assembler | 1316 | // 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 | } |
| 1293 | | 1325 | |
| 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 | } |
| 1305 | | 1337 | |
| 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 { |
| 1328 | | 1360 | |
| 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 | } |
| 1343 | | 1376 | |
| 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 { |
| 1381 | | 1414 | |
| 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 | } |
| 1411 | | 1445 | |
| 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 assembler | 1452 | // 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 | } |
| 1427 | | 1461 | |
| 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 | } |
| 1443 | | 1477 | |
| 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 | }; |
| 1508 | | 1543 | |
| | 1544 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 }; |
| | 1545 | |
| 1509 | const RelocError = error{ | 1546 | const RelocError = error{ |
| 1510 | Overflow, | 1547 | Overflow, |
| 1511 | OutOfMemory, | 1548 | OutOfMemory, |
| | 1549 | NoSpaceLeft, |
| 1512 | RelocFailure, | 1550 | RelocFailure, |
| | 1551 | RelaxFailure, |
| 1513 | UnsupportedCpuArch, | 1552 | UnsupportedCpuArch, |
| 1514 | }; | 1553 | }; |
| 1515 | | 1554 | |