authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-04 14:19:03+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-05 10:15:00+01:00
log205421c3117dbcd819dc636a7485e3cfeec0be20
tree5c73292f6242e24765bb0c97cca92686f7d03377
parentd80203b55d0550f94824ee2c108af259a666357c

coff: implement handling of arm64-specific relocs


1 files changed, 103 insertions(+), 12 deletions(-)

src/link/Coff.zig+103-12
...@@ -9,9 +9,11 @@ const fmt = std.fmt;...@@ -9,9 +9,11 @@ const fmt = std.fmt;
9const log = std.log.scoped(.link);9const log = std.log.scoped(.link);
10const math = std.math;10const math = std.math;
11const mem = std.mem;11const mem = std.mem;
12const meta = std.meta;
1213
13const Allocator = std.mem.Allocator;14const Allocator = std.mem.Allocator;
1415
16const aarch64 = @import("../arch/aarch64/bits.zig");
15const codegen = @import("../codegen.zig");17const codegen = @import("../codegen.zig");
16const link = @import("../link.zig");18const link = @import("../link.zig");
17const lld = @import("Coff/lld.zig");19const lld = @import("Coff/lld.zig");
...@@ -885,12 +887,13 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {...@@ -885,12 +887,13 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
885 for (relocs.items) |*reloc| {887 for (relocs.items) |*reloc| {
886 if (!reloc.dirty) continue;888 if (!reloc.dirty) continue;
887889
890 const source_vaddr = source_sym.value + reloc.offset;
888 const target_atom = reloc.getTargetAtom(self) orelse continue;891 const target_atom = reloc.getTargetAtom(self) orelse continue;
889 const target_vaddr = target_atom.getSymbol(self).value;892 const target_vaddr = target_atom.getSymbol(self).value;
890 const target_vaddr_with_addend = target_vaddr + reloc.addend;893 const target_vaddr_with_addend = target_vaddr + reloc.addend;
891894
892 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{895 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{
893 source_sym.value + reloc.offset,896 source_vaddr,
894 target_vaddr_with_addend,897 target_vaddr_with_addend,
895 self.getSymbolName(reloc.target),898 self.getSymbolName(reloc.target),
896 @tagName(reloc.@"type"),899 @tagName(reloc.@"type"),
...@@ -899,25 +902,108 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {...@@ -899,25 +902,108 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
899902
900 reloc.dirty = false;903 reloc.dirty = false;
901904
905 var buffer: [@sizeOf(u32)]u8 = undefined;
902 switch (reloc.@"type") {906 switch (reloc.@"type") {
903 .branch_26 => @panic("TODO branch26"),907 .branch_26,
904 .got_page => @panic("TODO got_page"),908 .got_page,
905 .got_pageoff => @panic("TODO got_pageoff"),909 .got_pageoff,
906 .page => @panic("TODO page"),910 .page,
907 .pageoff => @panic("TODO pageoff"),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,
908998
909 .got, .import => {999 .got, .import => {
910 assert(reloc.pcrel);1000 assert(reloc.pcrel);
911 const source_vaddr = source_sym.value + reloc.offset;1001 const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4;
912 const disp =
913 @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4;
914 try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset);1002 try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset);
915 },1003 },
916 .direct => {1004 .direct => {
917 if (reloc.pcrel) {1005 if (reloc.pcrel) {
918 const source_vaddr = source_sym.value + reloc.offset;1006 const disp = @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4;
919 const disp =
920 @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4;
921 try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset);1007 try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset);
922 } else switch (self.ptr_width) {1008 } else switch (self.ptr_width) {
923 .p32 => try self.base.file.?.pwriteAll(1009 .p32 => try self.base.file.?.pwriteAll(
...@@ -2281,3 +2367,8 @@ fn logSections(self: *Coff) void {...@@ -2281,3 +2367,8 @@ fn logSections(self: *Coff) void {
2281 });2367 });
2282 }2368 }
2283}2369}
2370
2371inline fn isArithmeticOp(inst: *const [4]u8) bool {
2372 const group_decode = @truncate(u5, inst[3]);
2373 return ((group_decode >> 2) == 4);
2374}