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;
99const log = std.log.scoped(.link);
1010const math = std.math;
1111const mem = std.mem;
12const meta = std.meta;
1213
1314const Allocator = std.mem.Allocator;
1415
16const aarch64 = @import("../arch/aarch64/bits.zig");
1517const codegen = @import("../codegen.zig");
1618const link = @import("../link.zig");
1719const lld = @import("Coff/lld.zig");
......@@ -885,12 +887,13 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
885887 for (relocs.items) |*reloc| {
886888 if (!reloc.dirty) continue;
887889
890 const source_vaddr = source_sym.value + reloc.offset;
888891 const target_atom = reloc.getTargetAtom(self) orelse continue;
889892 const target_vaddr = target_atom.getSymbol(self).value;
890893 const target_vaddr_with_addend = target_vaddr + reloc.addend;
891894
892895 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{
893 source_sym.value + reloc.offset,
896 source_vaddr,
894897 target_vaddr_with_addend,
895898 self.getSymbolName(reloc.target),
896899 @tagName(reloc.@"type"),
......@@ -899,25 +902,108 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
899902
900903 reloc.dirty = false;
901904
905 var buffer: [@sizeOf(u32)]u8 = undefined;
902906 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,
908998
909999 .got, .import => {
9101000 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;
9141002 try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset);
9151003 },
9161004 .direct => {
9171005 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;
9211007 try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset);
9221008 } else switch (self.ptr_width) {
9231009 .p32 => try self.base.file.?.pwriteAll(
......@@ -2281,3 +2367,8 @@ fn logSections(self: *Coff) void {
22812367 });
22822368 }
22832369}
2370
2371inline fn isArithmeticOp(inst: *const [4]u8) bool {
2372 const group_decode = @truncate(u5, inst[3]);
2373 return ((group_decode >> 2) == 4);
2374}