| author | |
| committer | |
| log | 1aeef297337985c5fd8647462cc7c78ea1a4df43 |
| tree | cca12f12bd3eaff958c441c9fad1c9d232d4f0ba |
| parent | 5ef33e7c7ea58f3777b0acac2335bd940b8a1fa6 |
3 files changed, 247 insertions(+), 216 deletions(-)
src/link/Coff.zig+3-214| ... | ... | @@ -9,11 +9,9 @@ const fmt = std.fmt; |
| 9 | 9 | const log = std.log.scoped(.link); |
| 10 | 10 | const math = std.math; |
| 11 | 11 | const mem = std.mem; |
| 12 | const meta = std.meta; | |
| 13 | 12 | |
| 14 | 13 | const Allocator = std.mem.Allocator; |
| 15 | 14 | |
| 16 | const aarch64 = @import("../arch/aarch64/bits.zig"); | |
| 17 | 15 | const codegen = @import("../codegen.zig"); |
| 18 | 16 | const link = @import("../link.zig"); |
| 19 | 17 | const lld = @import("Coff/lld.zig"); |
| ... | ... | @@ -26,6 +24,7 @@ const Liveness = @import("../Liveness.zig"); |
| 26 | 24 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 27 | 25 | const Module = @import("../Module.zig"); |
| 28 | 26 | const Object = @import("Coff/Object.zig"); |
| 27 | const Relocation = @import("Coff/Relocation.zig"); | |
| 29 | 28 | const StringTable = @import("strtab.zig").StringTable; |
| 30 | 29 | const TypedValue = @import("../TypedValue.zig"); |
| 31 | 30 | |
| ... | ... | @@ -125,61 +124,7 @@ const Entry = struct { |
| 125 | 124 | sym_index: u32, |
| 126 | 125 | }; |
| 127 | 126 | |
| 128 | pub const Reloc = struct { | |
| 129 | @"type": enum { | |
| 130 | // x86, x86_64 | |
| 131 | /// RIP-relative displacement to a GOT pointer | |
| 132 | got, | |
| 133 | /// RIP-relative displacement to an import pointer | |
| 134 | import, | |
| 135 | ||
| 136 | // aarch64 | |
| 137 | /// PC-relative distance to target page in GOT section | |
| 138 | got_page, | |
| 139 | /// Offset to a GOT pointer relative to the start of a page in GOT section | |
| 140 | got_pageoff, | |
| 141 | /// PC-relative distance to target page in a section (e.g., .rdata) | |
| 142 | page, | |
| 143 | /// Offset to a pointer relative to the start of a page in a section (e.g., .rdata) | |
| 144 | pageoff, | |
| 145 | /// PC-relative distance to target page in a import section | |
| 146 | import_page, | |
| 147 | /// Offset to a pointer relative to the start of a page in an import section (e.g., .rdata) | |
| 148 | import_pageoff, | |
| 149 | ||
| 150 | // common | |
| 151 | /// Absolute pointer value | |
| 152 | direct, | |
| 153 | }, | |
| 154 | target: SymbolWithLoc, | |
| 155 | offset: u32, | |
| 156 | addend: u32, | |
| 157 | pcrel: bool, | |
| 158 | length: u2, | |
| 159 | dirty: bool = true, | |
| 160 | ||
| 161 | /// Returns an Atom which is the target node of this relocation edge (if any). | |
| 162 | fn getTargetAtom(self: Reloc, coff_file: *Coff) ?*Atom { | |
| 163 | switch (self.@"type") { | |
| 164 | .got, | |
| 165 | .got_page, | |
| 166 | .got_pageoff, | |
| 167 | => return coff_file.getGotAtomForSymbol(self.target), | |
| 168 | ||
| 169 | .direct, | |
| 170 | .page, | |
| 171 | .pageoff, | |
| 172 | => return coff_file.getAtomForSymbol(self.target), | |
| 173 | ||
| 174 | .import, | |
| 175 | .import_page, | |
| 176 | .import_pageoff, | |
| 177 | => return coff_file.getImportAtomForSymbol(self.target), | |
| 178 | } | |
| 179 | } | |
| 180 | }; | |
| 181 | ||
| 182 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); | |
| 127 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation)); | |
| 183 | 128 | const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); |
| 184 | 129 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| 185 | 130 | |
| ... | ... | @@ -888,163 +833,12 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void { |
| 888 | 833 | |
| 889 | 834 | fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 890 | 835 | const relocs = self.relocs.get(atom) orelse return; |
| 891 | const source_sym = atom.getSymbol(self); | |
| 892 | const source_section = self.sections.get(@enumToInt(source_sym.section_number) - 1).header; | |
| 893 | const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address; | |
| 894 | 836 | |
| 895 | 837 | log.debug("relocating '{s}'", .{atom.getName(self)}); |
| 896 | 838 | |
| 897 | 839 | for (relocs.items) |*reloc| { |
| 898 | 840 | if (!reloc.dirty) continue; |
| 899 | ||
| 900 | const source_vaddr = source_sym.value + reloc.offset; | |
| 901 | const target_atom = reloc.getTargetAtom(self) orelse continue; | |
| 902 | const target_vaddr = target_atom.getSymbol(self).value; | |
| 903 | const target_vaddr_with_addend = target_vaddr + reloc.addend; | |
| 904 | const image_base = self.getImageBase(); | |
| 905 | ||
| 906 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ | |
| 907 | source_vaddr, | |
| 908 | target_vaddr_with_addend, | |
| 909 | self.getSymbolName(reloc.target), | |
| 910 | @tagName(reloc.@"type"), | |
| 911 | file_offset + reloc.offset, | |
| 912 | }); | |
| 913 | ||
| 914 | reloc.dirty = false; | |
| 915 | ||
| 916 | switch (self.base.options.target.cpu.arch) { | |
| 917 | .aarch64 => { | |
| 918 | var buffer: [@sizeOf(u64)]u8 = undefined; | |
| 919 | switch (reloc.length) { | |
| 920 | 2 => { | |
| 921 | const amt = try self.base.file.?.preadAll(buffer[0..4], file_offset + reloc.offset); | |
| 922 | if (amt != 4) return error.InputOutput; | |
| 923 | }, | |
| 924 | 3 => { | |
| 925 | const amt = try self.base.file.?.preadAll(&buffer, file_offset + reloc.offset); | |
| 926 | if (amt != 8) return error.InputOutput; | |
| 927 | }, | |
| 928 | else => unreachable, | |
| 929 | } | |
| 930 | ||
| 931 | switch (reloc.@"type") { | |
| 932 | .got_page, .import_page, .page => { | |
| 933 | const source_page = @intCast(i32, source_vaddr >> 12); | |
| 934 | const target_page = @intCast(i32, target_vaddr_with_addend >> 12); | |
| 935 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); | |
| 936 | var inst = aarch64.Instruction{ | |
| 937 | .pc_relative_address = mem.bytesToValue(meta.TagPayload( | |
| 938 | aarch64.Instruction, | |
| 939 | aarch64.Instruction.pc_relative_address, | |
| 940 | ), buffer[0..4]), | |
| 941 | }; | |
| 942 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); | |
| 943 | inst.pc_relative_address.immlo = @truncate(u2, pages); | |
| 944 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); | |
| 945 | }, | |
| 946 | .got_pageoff, .import_pageoff, .pageoff => { | |
| 947 | assert(!reloc.pcrel); | |
| 948 | ||
| 949 | const narrowed = @truncate(u12, @intCast(u64, target_vaddr_with_addend)); | |
| 950 | if (isArithmeticOp(buffer[0..4])) { | |
| 951 | var inst = aarch64.Instruction{ | |
| 952 | .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( | |
| 953 | aarch64.Instruction, | |
| 954 | aarch64.Instruction.add_subtract_immediate, | |
| 955 | ), buffer[0..4]), | |
| 956 | }; | |
| 957 | inst.add_subtract_immediate.imm12 = narrowed; | |
| 958 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); | |
| 959 | } else { | |
| 960 | var inst = aarch64.Instruction{ | |
| 961 | .load_store_register = mem.bytesToValue(meta.TagPayload( | |
| 962 | aarch64.Instruction, | |
| 963 | aarch64.Instruction.load_store_register, | |
| 964 | ), buffer[0..4]), | |
| 965 | }; | |
| 966 | const offset: u12 = blk: { | |
| 967 | if (inst.load_store_register.size == 0) { | |
| 968 | if (inst.load_store_register.v == 1) { | |
| 969 | // 128-bit SIMD is scaled by 16. | |
| 970 | break :blk @divExact(narrowed, 16); | |
| 971 | } | |
| 972 | // Otherwise, 8-bit SIMD or ldrb. | |
| 973 | break :blk narrowed; | |
| 974 | } else { | |
| 975 | const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable; | |
| 976 | break :blk @divExact(narrowed, denom); | |
| 977 | } | |
| 978 | }; | |
| 979 | inst.load_store_register.offset = offset; | |
| 980 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); | |
| 981 | } | |
| 982 | }, | |
| 983 | .direct => { | |
| 984 | assert(!reloc.pcrel); | |
| 985 | switch (reloc.length) { | |
| 986 | 2 => mem.writeIntLittle( | |
| 987 | u32, | |
| 988 | buffer[0..4], | |
| 989 | @truncate(u32, target_vaddr_with_addend + image_base), | |
| 990 | ), | |
| 991 | 3 => mem.writeIntLittle(u64, &buffer, target_vaddr_with_addend + image_base), | |
| 992 | else => unreachable, | |
| 993 | } | |
| 994 | }, | |
| 995 | ||
| 996 | .got => unreachable, | |
| 997 | .import => unreachable, | |
| 998 | } | |
| 999 | ||
| 1000 | switch (reloc.length) { | |
| 1001 | 2 => try self.base.file.?.pwriteAll(buffer[0..4], file_offset + reloc.offset), | |
| 1002 | 3 => try self.base.file.?.pwriteAll(&buffer, file_offset + reloc.offset), | |
| 1003 | else => unreachable, | |
| 1004 | } | |
| 1005 | }, | |
| 1006 | ||
| 1007 | .x86_64, .x86 => { | |
| 1008 | switch (reloc.@"type") { | |
| 1009 | .got_page => unreachable, | |
| 1010 | .got_pageoff => unreachable, | |
| 1011 | .page => unreachable, | |
| 1012 | .pageoff => unreachable, | |
| 1013 | .import_page => unreachable, | |
| 1014 | .import_pageoff => unreachable, | |
| 1015 | ||
| 1016 | .got, .import => { | |
| 1017 | assert(reloc.pcrel); | |
| 1018 | const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; | |
| 1019 | try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); | |
| 1020 | }, | |
| 1021 | .direct => { | |
| 1022 | if (reloc.pcrel) { | |
| 1023 | const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; | |
| 1024 | try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); | |
| 1025 | } else switch (self.ptr_width) { | |
| 1026 | .p32 => try self.base.file.?.pwriteAll( | |
| 1027 | mem.asBytes(&@intCast(u32, target_vaddr_with_addend + image_base)), | |
| 1028 | file_offset + reloc.offset, | |
| 1029 | ), | |
| 1030 | .p64 => switch (reloc.length) { | |
| 1031 | 2 => try self.base.file.?.pwriteAll( | |
| 1032 | mem.asBytes(&@truncate(u32, target_vaddr_with_addend + image_base)), | |
| 1033 | file_offset + reloc.offset, | |
| 1034 | ), | |
| 1035 | 3 => try self.base.file.?.pwriteAll( | |
| 1036 | mem.asBytes(&(target_vaddr_with_addend + image_base)), | |
| 1037 | file_offset + reloc.offset, | |
| 1038 | ), | |
| 1039 | else => unreachable, | |
| 1040 | }, | |
| 1041 | } | |
| 1042 | }, | |
| 1043 | } | |
| 1044 | }, | |
| 1045 | ||
| 1046 | else => unreachable, // unhandled target architecture | |
| 1047 | } | |
| 841 | try reloc.resolve(atom, self); | |
| 1048 | 842 | } |
| 1049 | 843 | } |
| 1050 | 844 | |
| ... | ... | @@ -2397,8 +2191,3 @@ fn logSections(self: *Coff) void { |
| 2397 | 2191 | }); |
| 2398 | 2192 | } |
| 2399 | 2193 | } |
| 2400 | ||
| 2401 | inline fn isArithmeticOp(inst: *const [4]u8) bool { | |
| 2402 | const group_decode = @truncate(u5, inst[3]); | |
| 2403 | return ((group_decode >> 2) == 4); | |
| 2404 | } |
src/link/Coff/Atom.zig+2-2| ... | ... | @@ -5,7 +5,7 @@ const coff = std.coff; |
| 5 | 5 | const log = std.log.scoped(.link); |
| 6 | 6 | |
| 7 | 7 | const Coff = @import("../Coff.zig"); |
| 8 | const Reloc = Coff.Reloc; | |
| 8 | const Relocation = @import("Relocation.zig"); | |
| 9 | 9 | const SymbolWithLoc = Coff.SymbolWithLoc; |
| 10 | 10 | |
| 11 | 11 | /// Each decl always gets a local symbol with the fully qualified name. |
| ... | ... | @@ -92,7 +92,7 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool { |
| 92 | 92 | return surplus >= Coff.min_text_capacity; |
| 93 | 93 | } |
| 94 | 94 | |
| 95 | pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Reloc) !void { | |
| 95 | pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Relocation) !void { | |
| 96 | 96 | const gpa = coff_file.base.allocator; |
| 97 | 97 | log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.@"type"), reloc.target.sym_index }); |
| 98 | 98 | const gop = try coff_file.relocs.getOrPut(gpa, self); |
src/link/Coff/Relocation.zig created+242| ... | ... | @@ -0,0 +1,242 @@ |
| 1 | const Relocation = @This(); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const assert = std.debug.assert; | |
| 5 | const log = std.log.scoped(.link); | |
| 6 | const math = std.math; | |
| 7 | const mem = std.mem; | |
| 8 | const meta = std.meta; | |
| 9 | ||
| 10 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | |
| 11 | ||
| 12 | const Atom = @import("Atom.zig"); | |
| 13 | const Coff = @import("../Coff.zig"); | |
| 14 | const SymbolWithLoc = Coff.SymbolWithLoc; | |
| 15 | ||
| 16 | @"type": enum { | |
| 17 | // x86, x86_64 | |
| 18 | /// RIP-relative displacement to a GOT pointer | |
| 19 | got, | |
| 20 | /// RIP-relative displacement to an import pointer | |
| 21 | import, | |
| 22 | ||
| 23 | // aarch64 | |
| 24 | /// PC-relative distance to target page in GOT section | |
| 25 | got_page, | |
| 26 | /// Offset to a GOT pointer relative to the start of a page in GOT section | |
| 27 | got_pageoff, | |
| 28 | /// PC-relative distance to target page in a section (e.g., .rdata) | |
| 29 | page, | |
| 30 | /// Offset to a pointer relative to the start of a page in a section (e.g., .rdata) | |
| 31 | pageoff, | |
| 32 | /// PC-relative distance to target page in a import section | |
| 33 | import_page, | |
| 34 | /// Offset to a pointer relative to the start of a page in an import section (e.g., .rdata) | |
| 35 | import_pageoff, | |
| 36 | ||
| 37 | // common | |
| 38 | /// Absolute pointer value | |
| 39 | direct, | |
| 40 | }, | |
| 41 | target: SymbolWithLoc, | |
| 42 | offset: u32, | |
| 43 | addend: u32, | |
| 44 | pcrel: bool, | |
| 45 | length: u2, | |
| 46 | dirty: bool = true, | |
| 47 | ||
| 48 | /// Returns an Atom which is the target node of this relocation edge (if any). | |
| 49 | pub fn getTargetAtom(self: Relocation, coff_file: *Coff) ?*Atom { | |
| 50 | switch (self.@"type") { | |
| 51 | .got, | |
| 52 | .got_page, | |
| 53 | .got_pageoff, | |
| 54 | => return coff_file.getGotAtomForSymbol(self.target), | |
| 55 | ||
| 56 | .direct, | |
| 57 | .page, | |
| 58 | .pageoff, | |
| 59 | => return coff_file.getAtomForSymbol(self.target), | |
| 60 | ||
| 61 | .import, | |
| 62 | .import_page, | |
| 63 | .import_pageoff, | |
| 64 | => return coff_file.getImportAtomForSymbol(self.target), | |
| 65 | } | |
| 66 | } | |
| 67 | ||
| 68 | pub fn resolve(self: *Relocation, atom: *Atom, coff_file: *Coff) !void { | |
| 69 | const source_sym = atom.getSymbol(coff_file); | |
| 70 | const source_section = coff_file.sections.get(@enumToInt(source_sym.section_number) - 1).header; | |
| 71 | const source_vaddr = source_sym.value + self.offset; | |
| 72 | ||
| 73 | const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address; | |
| 74 | ||
| 75 | const target_atom = self.getTargetAtom(coff_file) orelse return; | |
| 76 | const target_vaddr = target_atom.getSymbol(coff_file).value; | |
| 77 | const target_vaddr_with_addend = target_vaddr + self.addend; | |
| 78 | ||
| 79 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ | |
| 80 | source_vaddr, | |
| 81 | target_vaddr_with_addend, | |
| 82 | coff_file.getSymbolName(self.target), | |
| 83 | @tagName(self.@"type"), | |
| 84 | file_offset + self.offset, | |
| 85 | }); | |
| 86 | ||
| 87 | const ctx: Context = .{ | |
| 88 | .source_vaddr = source_vaddr, | |
| 89 | .target_vaddr = target_vaddr_with_addend, | |
| 90 | .file_offset = file_offset, | |
| 91 | .image_base = coff_file.getImageBase(), | |
| 92 | }; | |
| 93 | ||
| 94 | switch (coff_file.base.options.target.cpu.arch) { | |
| 95 | .aarch64 => try self.resolveAarch64(ctx, coff_file), | |
| 96 | .x86, .x86_64 => try self.resolveX86(ctx, coff_file), | |
| 97 | else => unreachable, // unhandled target architecture | |
| 98 | } | |
| 99 | ||
| 100 | self.dirty = false; | |
| 101 | } | |
| 102 | ||
| 103 | const Context = struct { | |
| 104 | source_vaddr: u32, | |
| 105 | target_vaddr: u32, | |
| 106 | file_offset: u32, | |
| 107 | image_base: u64, | |
| 108 | }; | |
| 109 | ||
| 110 | fn resolveAarch64(self: *Relocation, ctx: Context, coff_file: *Coff) !void { | |
| 111 | var buffer: [@sizeOf(u64)]u8 = undefined; | |
| 112 | switch (self.length) { | |
| 113 | 2 => { | |
| 114 | const amt = try coff_file.base.file.?.preadAll(buffer[0..4], ctx.file_offset + self.offset); | |
| 115 | if (amt != 4) return error.InputOutput; | |
| 116 | }, | |
| 117 | 3 => { | |
| 118 | const amt = try coff_file.base.file.?.preadAll(&buffer, ctx.file_offset + self.offset); | |
| 119 | if (amt != 8) return error.InputOutput; | |
| 120 | }, | |
| 121 | else => unreachable, | |
| 122 | } | |
| 123 | ||
| 124 | switch (self.@"type") { | |
| 125 | .got_page, .import_page, .page => { | |
| 126 | const source_page = @intCast(i32, ctx.source_vaddr >> 12); | |
| 127 | const target_page = @intCast(i32, ctx.target_vaddr >> 12); | |
| 128 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); | |
| 129 | var inst = aarch64.Instruction{ | |
| 130 | .pc_relative_address = mem.bytesToValue(meta.TagPayload( | |
| 131 | aarch64.Instruction, | |
| 132 | aarch64.Instruction.pc_relative_address, | |
| 133 | ), buffer[0..4]), | |
| 134 | }; | |
| 135 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); | |
| 136 | inst.pc_relative_address.immlo = @truncate(u2, pages); | |
| 137 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); | |
| 138 | }, | |
| 139 | .got_pageoff, .import_pageoff, .pageoff => { | |
| 140 | assert(!self.pcrel); | |
| 141 | ||
| 142 | const narrowed = @truncate(u12, @intCast(u64, ctx.target_vaddr)); | |
| 143 | if (isArithmeticOp(buffer[0..4])) { | |
| 144 | var inst = aarch64.Instruction{ | |
| 145 | .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( | |
| 146 | aarch64.Instruction, | |
| 147 | aarch64.Instruction.add_subtract_immediate, | |
| 148 | ), buffer[0..4]), | |
| 149 | }; | |
| 150 | inst.add_subtract_immediate.imm12 = narrowed; | |
| 151 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); | |
| 152 | } else { | |
| 153 | var inst = aarch64.Instruction{ | |
| 154 | .load_store_register = mem.bytesToValue(meta.TagPayload( | |
| 155 | aarch64.Instruction, | |
| 156 | aarch64.Instruction.load_store_register, | |
| 157 | ), buffer[0..4]), | |
| 158 | }; | |
| 159 | const offset: u12 = blk: { | |
| 160 | if (inst.load_store_register.size == 0) { | |
| 161 | if (inst.load_store_register.v == 1) { | |
| 162 | // 128-bit SIMD is scaled by 16. | |
| 163 | break :blk @divExact(narrowed, 16); | |
| 164 | } | |
| 165 | // Otherwise, 8-bit SIMD or ldrb. | |
| 166 | break :blk narrowed; | |
| 167 | } else { | |
| 168 | const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable; | |
| 169 | break :blk @divExact(narrowed, denom); | |
| 170 | } | |
| 171 | }; | |
| 172 | inst.load_store_register.offset = offset; | |
| 173 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); | |
| 174 | } | |
| 175 | }, | |
| 176 | .direct => { | |
| 177 | assert(!self.pcrel); | |
| 178 | switch (self.length) { | |
| 179 | 2 => mem.writeIntLittle( | |
| 180 | u32, | |
| 181 | buffer[0..4], | |
| 182 | @truncate(u32, ctx.target_vaddr + ctx.image_base), | |
| 183 | ), | |
| 184 | 3 => mem.writeIntLittle(u64, &buffer, ctx.target_vaddr + ctx.image_base), | |
| 185 | else => unreachable, | |
| 186 | } | |
| 187 | }, | |
| 188 | ||
| 189 | .got => unreachable, | |
| 190 | .import => unreachable, | |
| 191 | } | |
| 192 | ||
| 193 | switch (self.length) { | |
| 194 | 2 => try coff_file.base.file.?.pwriteAll(buffer[0..4], ctx.file_offset + self.offset), | |
| 195 | 3 => try coff_file.base.file.?.pwriteAll(&buffer, ctx.file_offset + self.offset), | |
| 196 | else => unreachable, | |
| 197 | } | |
| 198 | } | |
| 199 | ||
| 200 | fn resolveX86(self: *Relocation, ctx: Context, coff_file: *Coff) !void { | |
| 201 | switch (self.@"type") { | |
| 202 | .got_page => unreachable, | |
| 203 | .got_pageoff => unreachable, | |
| 204 | .page => unreachable, | |
| 205 | .pageoff => unreachable, | |
| 206 | .import_page => unreachable, | |
| 207 | .import_pageoff => unreachable, | |
| 208 | ||
| 209 | .got, .import => { | |
| 210 | assert(self.pcrel); | |
| 211 | const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4; | |
| 212 | try coff_file.base.file.?.pwriteAll(mem.asBytes(&disp), ctx.file_offset + self.offset); | |
| 213 | }, | |
| 214 | .direct => { | |
| 215 | if (self.pcrel) { | |
| 216 | const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4; | |
| 217 | try coff_file.base.file.?.pwriteAll(mem.asBytes(&disp), ctx.file_offset + self.offset); | |
| 218 | } else switch (coff_file.ptr_width) { | |
| 219 | .p32 => try coff_file.base.file.?.pwriteAll( | |
| 220 | mem.asBytes(&@intCast(u32, ctx.target_vaddr + ctx.image_base)), | |
| 221 | ctx.file_offset + self.offset, | |
| 222 | ), | |
| 223 | .p64 => switch (self.length) { | |
| 224 | 2 => try coff_file.base.file.?.pwriteAll( | |
| 225 | mem.asBytes(&@truncate(u32, ctx.target_vaddr + ctx.image_base)), | |
| 226 | ctx.file_offset + self.offset, | |
| 227 | ), | |
| 228 | 3 => try coff_file.base.file.?.pwriteAll( | |
| 229 | mem.asBytes(&(ctx.target_vaddr + ctx.image_base)), | |
| 230 | ctx.file_offset + self.offset, | |
| 231 | ), | |
| 232 | else => unreachable, | |
| 233 | }, | |
| 234 | } | |
| 235 | }, | |
| 236 | } | |
| 237 | } | |
| 238 | ||
| 239 | inline fn isArithmeticOp(inst: *const [4]u8) bool { | |
| 240 | const group_decode = @truncate(u5, inst[3]); | |
| 241 | return ((group_decode >> 2) == 4); | |
| 242 | } |