| ... | ... | @@ -9,9 +9,11 @@ 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; |
| 12 | 13 | |
| 13 | 14 | const Allocator = std.mem.Allocator; |
| 14 | 15 | |
| 16 | const aarch64 = @import("../arch/aarch64/bits.zig"); |
| 15 | 17 | const codegen = @import("../codegen.zig"); |
| 16 | 18 | const link = @import("../link.zig"); |
| 17 | 19 | const lld = @import("Coff/lld.zig"); |
| ... | ... | @@ -885,12 +887,13 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 885 | 887 | for (relocs.items) |*reloc| { |
| 886 | 888 | if (!reloc.dirty) continue; |
| 887 | 889 | |
| 890 | const source_vaddr = source_sym.value + reloc.offset; |
| 888 | 891 | const target_atom = reloc.getTargetAtom(self) orelse continue; |
| 889 | 892 | const target_vaddr = target_atom.getSymbol(self).value; |
| 890 | 893 | const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| 891 | 894 | |
| 892 | 895 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ |
| 893 | | source_sym.value + reloc.offset, |
| 896 | source_vaddr, |
| 894 | 897 | target_vaddr_with_addend, |
| 895 | 898 | self.getSymbolName(reloc.target), |
| 896 | 899 | @tagName(reloc.@"type"), |
| ... | ... | @@ -899,25 +902,108 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 899 | 902 | |
| 900 | 903 | reloc.dirty = false; |
| 901 | 904 | |
| 905 | var buffer: [@sizeOf(u32)]u8 = undefined; |
| 902 | 906 | switch (reloc.@"type") { |
| 903 | | .branch_26 => @panic("TODO branch26"), |
| 904 | | .got_page => @panic("TODO got_page"), |
| 905 | | .got_pageoff => @panic("TODO got_pageoff"), |
| 906 | | .page => @panic("TODO page"), |
| 907 | | .pageoff => @panic("TODO pageoff"), |
| 907 | .branch_26, |
| 908 | .got_page, |
| 909 | .got_pageoff, |
| 910 | .page, |
| 911 | .pageoff, |
| 912 | => { |
| 913 | const amt = try self.base.file.?.preadAll(&buffer, file_offset + reloc.offset); |
| 914 | if (amt != buffer.len) return error.InputOutput; |
| 915 | |
| 916 | switch (reloc.@"type") { |
| 917 | .branch_26 => { |
| 918 | const displacement = math.cast(i28, @intCast(i64, target_vaddr_with_addend) - @intCast(i64, source_vaddr)) orelse |
| 919 | unreachable; // TODO generate thunks |
| 920 | var inst = aarch64.Instruction{ |
| 921 | .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload( |
| 922 | aarch64.Instruction, |
| 923 | aarch64.Instruction.unconditional_branch_immediate, |
| 924 | ), &buffer), |
| 925 | }; |
| 926 | inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2)); |
| 927 | mem.writeIntLittle(u32, &buffer, inst.toU32()); |
| 928 | }, |
| 929 | .got_page, .page => { |
| 930 | const source_page = @intCast(i32, source_vaddr >> 12); |
| 931 | const target_page = @intCast(i32, target_vaddr_with_addend >> 12); |
| 932 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); |
| 933 | var inst = aarch64.Instruction{ |
| 934 | .pc_relative_address = mem.bytesToValue(meta.TagPayload( |
| 935 | aarch64.Instruction, |
| 936 | aarch64.Instruction.pc_relative_address, |
| 937 | ), &buffer), |
| 938 | }; |
| 939 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); |
| 940 | inst.pc_relative_address.immlo = @truncate(u2, pages); |
| 941 | mem.writeIntLittle(u32, &buffer, inst.toU32()); |
| 942 | }, |
| 943 | .got_pageoff, .pageoff => { |
| 944 | assert(!reloc.pcrel); |
| 945 | |
| 946 | const narrowed = @truncate(u12, @intCast(u64, target_vaddr_with_addend)); |
| 947 | if (isArithmeticOp(&buffer)) { |
| 948 | var inst = aarch64.Instruction{ |
| 949 | .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( |
| 950 | aarch64.Instruction, |
| 951 | aarch64.Instruction.add_subtract_immediate, |
| 952 | ), &buffer), |
| 953 | }; |
| 954 | inst.add_subtract_immediate.imm12 = narrowed; |
| 955 | mem.writeIntLittle(u32, &buffer, inst.toU32()); |
| 956 | } else { |
| 957 | var inst = aarch64.Instruction{ |
| 958 | .load_store_register = mem.bytesToValue(meta.TagPayload( |
| 959 | aarch64.Instruction, |
| 960 | aarch64.Instruction.load_store_register, |
| 961 | ), &buffer), |
| 962 | }; |
| 963 | const offset: u12 = blk: { |
| 964 | if (inst.load_store_register.size == 0) { |
| 965 | if (inst.load_store_register.v == 1) { |
| 966 | // 128-bit SIMD is scaled by 16. |
| 967 | break :blk @divExact(narrowed, 16); |
| 968 | } |
| 969 | // Otherwise, 8-bit SIMD or ldrb. |
| 970 | break :blk narrowed; |
| 971 | } else { |
| 972 | const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable; |
| 973 | break :blk @divExact(narrowed, denom); |
| 974 | } |
| 975 | }; |
| 976 | inst.load_store_register.offset = offset; |
| 977 | mem.writeIntLittle(u32, &buffer, inst.toU32()); |
| 978 | } |
| 979 | }, |
| 980 | |
| 981 | else => unreachable, |
| 982 | } |
| 983 | |
| 984 | try self.base.file.?.pwriteAll(&buffer, file_offset + reloc.offset); |
| 985 | |
| 986 | return; |
| 987 | }, |
| 988 | |
| 989 | else => {}, |
| 990 | } |
| 991 | |
| 992 | switch (reloc.@"type") { |
| 993 | .branch_26 => unreachable, |
| 994 | .got_page => unreachable, |
| 995 | .got_pageoff => unreachable, |
| 996 | .page => unreachable, |
| 997 | .pageoff => unreachable, |
| 908 | 998 | |
| 909 | 999 | .got, .import => { |
| 910 | 1000 | assert(reloc.pcrel); |
| 911 | | const source_vaddr = source_sym.value + reloc.offset; |
| 912 | | const disp = |
| 913 | | @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; |
| 1001 | const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; |
| 914 | 1002 | try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); |
| 915 | 1003 | }, |
| 916 | 1004 | .direct => { |
| 917 | 1005 | if (reloc.pcrel) { |
| 918 | | const source_vaddr = source_sym.value + reloc.offset; |
| 919 | | const disp = |
| 920 | | @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; |
| 1006 | const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; |
| 921 | 1007 | try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); |
| 922 | 1008 | } else switch (self.ptr_width) { |
| 923 | 1009 | .p32 => try self.base.file.?.pwriteAll( |
| ... | ... | @@ -2281,3 +2367,8 @@ fn logSections(self: *Coff) void { |
| 2281 | 2367 | }); |
| 2282 | 2368 | } |
| 2283 | 2369 | } |
| 2370 | |
| 2371 | inline fn isArithmeticOp(inst: *const [4]u8) bool { |
| 2372 | const group_decode = @truncate(u5, inst[3]); |
| 2373 | return ((group_decode >> 2) == 4); |
| 2374 | } |