| ... | ... | @@ -700,13 +700,82 @@ fn reportUndefined( |
| 700 | 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 | 704 | relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) }); |
| 705 | 705 | |
| 706 | | switch (elf_file.getTarget().cpu.arch) { |
| 707 | | .x86_64 => try x86_64.resolveRelocsAlloc(self, elf_file, code), |
| 708 | | else => return error.UnsupportedCpuArch, |
| 706 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 707 | const file_ptr = self.file(elf_file).?; |
| 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 | 781 | fn resolveDynAbsReloc( |
| ... | ... | @@ -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 { |
| 1005 | | const file_ptr = atom.file(elf_file).?; |
| 1006 | | var stream = std.io.fixedBufferStream(code); |
| 1007 | | const cwriter = stream.writer(); |
| 1008 | | |
| 1009 | | const rels = atom.relocs(elf_file); |
| 1010 | | var i: usize = 0; |
| 1011 | | while (i < rels.len) : (i += 1) { |
| 1012 | | const rel = rels[i]; |
| 1013 | | const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); |
| 1014 | | if (r_type == .NONE) continue; |
| 1015 | | |
| 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())); |
| 1073 | fn resolveRelocAlloc( |
| 1074 | atom: Atom, |
| 1075 | elf_file: *Elf, |
| 1076 | rel: elf.Elf64_Rela, |
| 1077 | target: *const Symbol, |
| 1078 | args: ResolveArgs, |
| 1079 | it: *RelocsIterator, |
| 1080 | code: []u8, |
| 1081 | stream: anytype, |
| 1082 | ) (error{ InvalidInstruction, CannotEncode } || RelocError)!void { |
| 1083 | const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); |
| 1084 | const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; |
| 1050 | 1085 | |
| 1051 | | relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{ |
| 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 | | }); |
| 1086 | const cwriter = stream.writer(); |
| 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) { |
| 1064 | | .NONE => unreachable, |
| 1090 | switch (r_type) { |
| 1091 | .NONE => unreachable, |
| 1065 | 1092 | |
| 1066 | | .@"64" => { |
| 1067 | | try atom.resolveDynAbsReloc( |
| 1068 | | target, |
| 1069 | | rel, |
| 1070 | | dynAbsRelocAction(target, elf_file), |
| 1071 | | elf_file, |
| 1072 | | cwriter, |
| 1073 | | ); |
| 1074 | | }, |
| 1093 | .@"64" => { |
| 1094 | try atom.resolveDynAbsReloc( |
| 1095 | target, |
| 1096 | rel, |
| 1097 | dynAbsRelocAction(target, elf_file), |
| 1098 | elf_file, |
| 1099 | cwriter, |
| 1100 | ); |
| 1101 | }, |
| 1075 | 1102 | |
| 1076 | | .PLT32, |
| 1077 | | .PC32, |
| 1078 | | => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little), |
| 1103 | .PLT32, |
| 1104 | .PC32, |
| 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), |
| 1081 | | .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), |
| 1082 | | .GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little), |
| 1107 | .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little), |
| 1108 | .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little), |
| 1109 | .GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little), |
| 1083 | 1110 | |
| 1084 | | .GOTPCRELX => { |
| 1085 | | 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; |
| 1087 | | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); |
| 1088 | | continue; |
| 1089 | | } |
| 1090 | | try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); |
| 1091 | | }, |
| 1111 | .GOTPCRELX => { |
| 1112 | if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { |
| 1113 | x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk; |
| 1114 | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); |
| 1115 | return; |
| 1116 | } |
| 1117 | try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); |
| 1118 | }, |
| 1092 | 1119 | |
| 1093 | | .REX_GOTPCRELX => { |
| 1094 | | 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; |
| 1096 | | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); |
| 1097 | | continue; |
| 1098 | | } |
| 1099 | | try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); |
| 1100 | | }, |
| 1120 | .REX_GOTPCRELX => { |
| 1121 | if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: { |
| 1122 | x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk; |
| 1123 | try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little); |
| 1124 | return; |
| 1125 | } |
| 1126 | try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little); |
| 1127 | }, |
| 1101 | 1128 | |
| 1102 | | .@"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), |
| 1129 | .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(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), |
| 1106 | | .TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little), |
| 1132 | .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(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), |
| 1109 | | .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), |
| 1135 | .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little), |
| 1136 | .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), |
| 1110 | 1137 | |
| 1111 | | .TLSGD => { |
| 1112 | | if (target.flags.has_tlsgd) { |
| 1113 | | const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file))); |
| 1114 | | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1115 | | } else if (target.flags.has_gottp) { |
| 1116 | | 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); |
| 1118 | | i += 1; |
| 1119 | | } else { |
| 1120 | | try x86_64.relaxTlsGdToLe( |
| 1121 | | atom, |
| 1122 | | rels[i .. i + 2], |
| 1123 | | @as(i32, @intCast(S - TP)), |
| 1124 | | elf_file, |
| 1125 | | &stream, |
| 1126 | | ); |
| 1127 | | i += 1; |
| 1128 | | } |
| 1129 | | }, |
| 1138 | .TLSGD => { |
| 1139 | if (target.flags.has_tlsgd) { |
| 1140 | const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file))); |
| 1141 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1142 | } else if (target.flags.has_gottp) { |
| 1143 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); |
| 1144 | try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream); |
| 1145 | } else { |
| 1146 | try x86_64.relaxTlsGdToLe( |
| 1147 | atom, |
| 1148 | &.{ rel, it.next().? }, |
| 1149 | @as(i32, @intCast(S - TP)), |
| 1150 | elf_file, |
| 1151 | stream, |
| 1152 | ); |
| 1153 | } |
| 1154 | }, |
| 1130 | 1155 | |
| 1131 | | .TLSLD => { |
| 1132 | | if (elf_file.got.tlsld_index) |entry_index| { |
| 1133 | | const tlsld_entry = elf_file.got.entries.items[entry_index]; |
| 1134 | | const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file))); |
| 1135 | | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1136 | | } else { |
| 1137 | | try x86_64.relaxTlsLdToLe( |
| 1138 | | atom, |
| 1139 | | rels[i .. i + 2], |
| 1140 | | @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))), |
| 1141 | | elf_file, |
| 1142 | | &stream, |
| 1143 | | ); |
| 1144 | | i += 1; |
| 1145 | | } |
| 1146 | | }, |
| 1156 | .TLSLD => { |
| 1157 | if (elf_file.got.tlsld_index) |entry_index| { |
| 1158 | const tlsld_entry = elf_file.got.entries.items[entry_index]; |
| 1159 | const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file))); |
| 1160 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1161 | } else { |
| 1162 | try x86_64.relaxTlsLdToLe( |
| 1163 | atom, |
| 1164 | &.{ rel, it.next().? }, |
| 1165 | @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))), |
| 1166 | elf_file, |
| 1167 | stream, |
| 1168 | ); |
| 1169 | } |
| 1170 | }, |
| 1147 | 1171 | |
| 1148 | | .GOTPC32_TLSDESC => { |
| 1149 | | if (target.flags.has_tlsdesc) { |
| 1150 | | const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file))); |
| 1151 | | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1152 | | } else { |
| 1153 | | try x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]); |
| 1154 | | try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); |
| 1155 | | } |
| 1156 | | }, |
| 1172 | .GOTPC32_TLSDESC => { |
| 1173 | if (target.flags.has_tlsdesc) { |
| 1174 | const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file))); |
| 1175 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1176 | } else { |
| 1177 | x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch { |
| 1178 | var err = try elf_file.addErrorWithNotes(1); |
| 1179 | try err.addMsg(elf_file, "could not relax {s}", .{@tagName(r_type)}); |
| 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) { |
| 1159 | | // call -> nop |
| 1160 | | try cwriter.writeAll(&.{ 0x66, 0x90 }); |
| 1161 | | }, |
| 1191 | .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { |
| 1192 | // call -> nop |
| 1193 | try cwriter.writeAll(&.{ 0x66, 0x90 }); |
| 1194 | }, |
| 1162 | 1195 | |
| 1163 | | .GOTTPOFF => { |
| 1164 | | if (target.flags.has_gottp) { |
| 1165 | | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); |
| 1166 | | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1167 | | } else { |
| 1168 | | x86_64.relaxGotTpOff(code[r_offset - 3 ..]) catch unreachable; |
| 1169 | | try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); |
| 1170 | | } |
| 1171 | | }, |
| 1196 | .GOTTPOFF => { |
| 1197 | if (target.flags.has_gottp) { |
| 1198 | const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file))); |
| 1199 | try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little); |
| 1200 | } else { |
| 1201 | x86_64.relaxGotTpOff(code[r_offset - 3 ..]); |
| 1202 | try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little); |
| 1203 | } |
| 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)) { |
| 1176 | | // Zig custom relocations |
| 1177 | | 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), |
| 1208 | else => |x| switch (@intFromEnum(x)) { |
| 1209 | // Zig custom relocations |
| 1210 | Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little), |
| 1211 | Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little), |
| 1179 | 1212 | |
| 1180 | | else => {}, |
| 1181 | | }, |
| 1182 | | } |
| 1213 | else => {}, |
| 1214 | }, |
| 1183 | 1215 | } |
| 1184 | 1216 | } |
| 1185 | 1217 | |
| ... | ... | @@ -1274,7 +1306,7 @@ const x86_64 = struct { |
| 1274 | 1306 | } |
| 1275 | 1307 | |
| 1276 | 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 | 1310 | const inst = switch (old_inst.encoding.mnemonic) { |
| 1279 | 1311 | .call => try Instruction.new(old_inst.prefix, .call, &.{ |
| 1280 | 1312 | // TODO: hack to force imm32s in the assembler |
| ... | ... | @@ -1284,28 +1316,28 @@ const x86_64 = struct { |
| 1284 | 1316 | // TODO: hack to force imm32s in the assembler |
| 1285 | 1317 | .{ .imm = Immediate.s(-129) }, |
| 1286 | 1318 | }), |
| 1287 | | else => return error.RelaxFail, |
| 1319 | else => return error.RelaxFailure, |
| 1288 | 1320 | }; |
| 1289 | 1321 | relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding }); |
| 1290 | 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 | 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 | 1328 | switch (old_inst.encoding.mnemonic) { |
| 1297 | 1329 | .mov => { |
| 1298 | 1330 | const inst = try Instruction.new(old_inst.prefix, .lea, &old_inst.ops); |
| 1299 | 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 | 1338 | fn relaxTlsGdToIe( |
| 1307 | 1339 | self: Atom, |
| 1308 | | rels: []align(1) const elf.Elf64_Rela, |
| 1340 | rels: []const elf.Elf64_Rela, |
| 1309 | 1341 | value: i32, |
| 1310 | 1342 | elf_file: *Elf, |
| 1311 | 1343 | stream: anytype, |
| ... | ... | @@ -1328,7 +1360,7 @@ const x86_64 = struct { |
| 1328 | 1360 | |
| 1329 | 1361 | else => { |
| 1330 | 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 | 1364 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1333 | 1365 | relocation.fmtRelocType(rels[1].r_type(), .x86_64), |
| 1334 | 1366 | }); |
| ... | ... | @@ -1337,13 +1369,14 @@ const x86_64 = struct { |
| 1337 | 1369 | self.name(elf_file), |
| 1338 | 1370 | rels[0].r_offset, |
| 1339 | 1371 | }); |
| 1372 | return error.RelaxFailure; |
| 1340 | 1373 | }, |
| 1341 | 1374 | } |
| 1342 | 1375 | } |
| 1343 | 1376 | |
| 1344 | 1377 | fn relaxTlsLdToLe( |
| 1345 | 1378 | self: Atom, |
| 1346 | | rels: []align(1) const elf.Elf64_Rela, |
| 1379 | rels: []const elf.Elf64_Rela, |
| 1347 | 1380 | value: i32, |
| 1348 | 1381 | elf_file: *Elf, |
| 1349 | 1382 | stream: anytype, |
| ... | ... | @@ -1381,7 +1414,7 @@ const x86_64 = struct { |
| 1381 | 1414 | |
| 1382 | 1415 | else => { |
| 1383 | 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 | 1418 | relocation.fmtRelocType(rels[0].r_type(), .x86_64), |
| 1386 | 1419 | relocation.fmtRelocType(rels[1].r_type(), .x86_64), |
| 1387 | 1420 | }); |
| ... | ... | @@ -1390,6 +1423,7 @@ const x86_64 = struct { |
| 1390 | 1423 | self.name(elf_file), |
| 1391 | 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 | 1443 | } |
| 1410 | 1444 | } |
| 1411 | 1445 | |
| 1412 | | fn relaxGotTpOff(code: []u8) !void { |
| 1413 | | const old_inst = disassemble(code) orelse return error.RelaxFail; |
| 1446 | fn relaxGotTpOff(code: []u8) void { |
| 1447 | const old_inst = disassemble(code) orelse unreachable; |
| 1414 | 1448 | switch (old_inst.encoding.mnemonic) { |
| 1415 | 1449 | .mov => { |
| 1416 | | const inst = try Instruction.new(old_inst.prefix, .mov, &.{ |
| 1450 | const inst = Instruction.new(old_inst.prefix, .mov, &.{ |
| 1417 | 1451 | old_inst.ops[0], |
| 1418 | 1452 | // TODO: hack to force imm32s in the assembler |
| 1419 | 1453 | .{ .imm = Immediate.s(-129) }, |
| 1420 | | }); |
| 1454 | }) catch unreachable; |
| 1421 | 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 | 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 | 1464 | switch (old_inst.encoding.mnemonic) { |
| 1431 | 1465 | .lea => { |
| 1432 | 1466 | const inst = try Instruction.new(old_inst.prefix, .mov, &.{ |
| ... | ... | @@ -1435,15 +1469,15 @@ const x86_64 = struct { |
| 1435 | 1469 | .{ .imm = Immediate.s(-129) }, |
| 1436 | 1470 | }); |
| 1437 | 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 | 1478 | fn relaxTlsGdToLe( |
| 1445 | 1479 | self: Atom, |
| 1446 | | rels: []align(1) const elf.Elf64_Rela, |
| 1480 | rels: []const elf.Elf64_Rela, |
| 1447 | 1481 | value: i32, |
| 1448 | 1482 | elf_file: *Elf, |
| 1449 | 1483 | stream: anytype, |
| ... | ... | @@ -1481,6 +1515,7 @@ const x86_64 = struct { |
| 1481 | 1515 | self.name(elf_file), |
| 1482 | 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 | 1541 | const Instruction = encoder.Instruction; |
| 1507 | 1542 | }; |
| 1508 | 1543 | |
| 1544 | const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 }; |
| 1545 | |
| 1509 | 1546 | const RelocError = error{ |
| 1510 | 1547 | Overflow, |
| 1511 | 1548 | OutOfMemory, |
| 1549 | NoSpaceLeft, |
| 1512 | 1550 | RelocFailure, |
| 1551 | RelaxFailure, |
| 1513 | 1552 | UnsupportedCpuArch, |
| 1514 | 1553 | }; |
| 1515 | 1554 | |