authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-05 12:19:45+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-11-05 12:19:45+01:00
log28288dcbbf5258fe7461bbe0f6b2feeba0c2de5d
treeb2517ebf4369ffb2c078b4ceced49a3f83e33c4a
parent1d680459197e7ba5e163d99e07fdfe54c2ad9225
parent165ae04a03206af34707b5505dc042338ce4731e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13444 from ziglang/arm64-coff

aarch64,coff: lift-off!

5 files changed, 340 insertions(+), 58 deletions(-)

lib/std/io.zig+3-3
......@@ -36,7 +36,7 @@ pub const default_mode: ModeOverride = if (is_async) Mode.evented else .blocking
3636
3737fn getStdOutHandle() os.fd_t {
3838 if (builtin.os.tag == .windows) {
39 if (builtin.zig_backend == .stage2_x86_64) {
39 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {
4040 // TODO: this is just a temporary workaround until we advance x86 backend further along.
4141 return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
4242 }
......@@ -62,7 +62,7 @@ pub fn getStdOut() File {
6262
6363fn getStdErrHandle() os.fd_t {
6464 if (builtin.os.tag == .windows) {
65 if (builtin.zig_backend == .stage2_x86_64) {
65 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {
6666 // TODO: this is just a temporary workaround until we advance x86 backend further along.
6767 return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
6868 }
......@@ -88,7 +88,7 @@ pub fn getStdErr() File {
8888
8989fn getStdInHandle() os.fd_t {
9090 if (builtin.os.tag == .windows) {
91 if (builtin.zig_backend == .stage2_x86_64) {
91 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {
9292 // TODO: this is just a temporary workaround until we advance x86 backend further along.
9393 return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
9494 }
src/arch/aarch64/CodeGen.zig+86-13
......@@ -142,7 +142,8 @@ const MCValue = union(enum) {
142142 /// The value is in memory but requires a linker relocation fixup:
143143 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
144144 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
145 linker_load: struct { @"type": enum { got, direct }, sym_index: u32 },
145 /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
146 linker_load: struct { @"type": enum { got, direct, import }, sym_index: u32 },
146147 /// The value is one of the stack variables.
147148 ///
148149 /// If the type is a pointer, it means the pointer address is in
......@@ -1117,13 +1118,11 @@ fn truncRegister(
11171118 });
11181119 },
11191120 32, 64 => {
1120 assert(dest_reg.size() == operand_reg.size());
1121
11221121 _ = try self.addInst(.{
11231122 .tag = .mov_register,
11241123 .data = .{ .rr = .{
1125 .rd = dest_reg,
1126 .rn = operand_reg,
1124 .rd = if (int_bits == 32) dest_reg.toW() else dest_reg.toX(),
1125 .rn = if (int_bits == 32) operand_reg.toW() else operand_reg.toX(),
11271126 } },
11281127 });
11291128 },
......@@ -3719,14 +3718,21 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
37193718 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
37203719 .got => .load_memory_ptr_got,
37213720 .direct => .load_memory_ptr_direct,
3721 .import => unreachable,
37223722 };
37233723 const mod = self.bin_file.options.module.?;
3724 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
3725 const atom_index = switch (self.bin_file.tag) {
3726 .macho => owner_decl.link.macho.sym_index,
3727 .coff => owner_decl.link.coff.sym_index,
3728 else => unreachable, // unsupported target format
3729 };
37243730 _ = try self.addInst(.{
37253731 .tag = tag,
37263732 .data = .{
37273733 .payload = try self.addExtra(Mir.LoadMemoryPie{
37283734 .register = @enumToInt(src_reg),
3729 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
3735 .atom_index = atom_index,
37303736 .sym_index = load_struct.sym_index,
37313737 }),
37323738 },
......@@ -4057,6 +4063,45 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
40574063 } else {
40584064 return self.fail("TODO implement calling bitcasted functions", .{});
40594065 }
4066 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4067 if (func_value.castTag(.function)) |func_payload| {
4068 const func = func_payload.data;
4069 const fn_owner_decl = mod.declPtr(func.owner_decl);
4070 try self.genSetReg(Type.initTag(.u64), .x30, .{
4071 .linker_load = .{
4072 .@"type" = .got,
4073 .sym_index = fn_owner_decl.link.coff.sym_index,
4074 },
4075 });
4076 // blr x30
4077 _ = try self.addInst(.{
4078 .tag = .blr,
4079 .data = .{ .reg = .x30 },
4080 });
4081 } else if (func_value.castTag(.extern_fn)) |func_payload| {
4082 const extern_fn = func_payload.data;
4083 const decl_name = mod.declPtr(extern_fn.owner_decl).name;
4084 if (extern_fn.lib_name) |lib_name| {
4085 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
4086 decl_name,
4087 lib_name,
4088 });
4089 }
4090 const sym_index = try coff_file.getGlobalSymbol(mem.sliceTo(decl_name, 0));
4091 try self.genSetReg(Type.initTag(.u64), .x30, .{
4092 .linker_load = .{
4093 .@"type" = .import,
4094 .sym_index = sym_index,
4095 },
4096 });
4097 // blr x30
4098 _ = try self.addInst(.{
4099 .tag = .blr,
4100 .data = .{ .reg = .x30 },
4101 });
4102 } else {
4103 return self.fail("TODO implement calling bitcasted functions", .{});
4104 }
40604105 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
40614106 if (func_value.castTag(.function)) |func_payload| {
40624107 try p9.seeDecl(func_payload.data.owner_decl);
......@@ -4077,8 +4122,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
40774122 } else {
40784123 return self.fail("TODO implement calling bitcasted functions", .{});
40794124 }
4080 } else if (self.bin_file.cast(link.File.Coff)) |_| {
4081 return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch});
40824125 } else unreachable;
40834126 } else {
40844127 assert(ty.zigTypeTag() == .Pointer);
......@@ -5161,14 +5204,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
51615204 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
51625205 .got => .load_memory_ptr_got,
51635206 .direct => .load_memory_ptr_direct,
5207 .import => unreachable,
51645208 };
51655209 const mod = self.bin_file.options.module.?;
5210 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5211 const atom_index = switch (self.bin_file.tag) {
5212 .macho => owner_decl.link.macho.sym_index,
5213 .coff => owner_decl.link.coff.sym_index,
5214 else => unreachable, // unsupported target format
5215 };
51665216 _ = try self.addInst(.{
51675217 .tag = tag,
51685218 .data = .{
51695219 .payload = try self.addExtra(Mir.LoadMemoryPie{
51705220 .register = @enumToInt(src_reg),
5171 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
5221 .atom_index = atom_index,
51725222 .sym_index = load_struct.sym_index,
51735223 }),
51745224 },
......@@ -5268,14 +5318,21 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
52685318 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
52695319 .got => .load_memory_got,
52705320 .direct => .load_memory_direct,
5321 .import => .load_memory_import,
52715322 };
52725323 const mod = self.bin_file.options.module.?;
5324 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5325 const atom_index = switch (self.bin_file.tag) {
5326 .macho => owner_decl.link.macho.sym_index,
5327 .coff => owner_decl.link.coff.sym_index,
5328 else => unreachable, // unsupported target format
5329 };
52735330 _ = try self.addInst(.{
52745331 .tag = tag,
52755332 .data = .{
52765333 .payload = try self.addExtra(Mir.LoadMemoryPie{
52775334 .register = @enumToInt(reg),
5278 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
5335 .atom_index = atom_index,
52795336 .sym_index = load_struct.sym_index,
52805337 }),
52815338 },
......@@ -5455,14 +5512,21 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
54555512 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
54565513 .got => .load_memory_ptr_got,
54575514 .direct => .load_memory_ptr_direct,
5515 .import => unreachable,
54585516 };
54595517 const mod = self.bin_file.options.module.?;
5518 const owner_decl = mod.declPtr(self.mod_fn.owner_decl);
5519 const atom_index = switch (self.bin_file.tag) {
5520 .macho => owner_decl.link.macho.sym_index,
5521 .coff => owner_decl.link.coff.sym_index,
5522 else => unreachable, // unsupported target format
5523 };
54605524 _ = try self.addInst(.{
54615525 .tag = tag,
54625526 .data = .{
54635527 .payload = try self.addExtra(Mir.LoadMemoryPie{
54645528 .register = @enumToInt(src_reg),
5465 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
5529 .atom_index = atom_index,
54665530 .sym_index = load_struct.sym_index,
54675531 }),
54685532 },
......@@ -5775,7 +5839,13 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
57755839 .sym_index = decl.link.macho.sym_index,
57765840 } };
57775841 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5778 return self.fail("TODO codegen COFF const Decl pointer", .{});
5842 // Because COFF is PIE-always-on, we defer memory address resolution until
5843 // the linker has enough info to perform relocations.
5844 assert(decl.link.coff.sym_index != 0);
5845 return MCValue{ .linker_load = .{
5846 .@"type" = .got,
5847 .sym_index = decl.link.coff.sym_index,
5848 } };
57795849 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
57805850 try p9.seeDecl(decl_index);
57815851 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
......@@ -5799,7 +5869,10 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
57995869 .sym_index = local_sym_index,
58005870 } };
58015871 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5802 return self.fail("TODO lower unnamed const in COFF", .{});
5872 return MCValue{ .linker_load = .{
5873 .@"type" = .direct,
5874 .sym_index = local_sym_index,
5875 } };
58035876 } else if (self.bin_file.cast(link.File.Plan9)) |_| {
58045877 return self.fail("TODO lower unnamed const in Plan9", .{});
58055878 } else {
src/arch/aarch64/Emit.zig+59-8
......@@ -145,6 +145,7 @@ pub fn emitMir(
145145
146146 .load_memory_got => try emit.mirLoadMemoryPie(inst),
147147 .load_memory_direct => try emit.mirLoadMemoryPie(inst),
148 .load_memory_import => try emit.mirLoadMemoryPie(inst),
148149 .load_memory_ptr_got => try emit.mirLoadMemoryPie(inst),
149150 .load_memory_ptr_direct => try emit.mirLoadMemoryPie(inst),
150151
......@@ -674,13 +675,14 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
674675 assert(emit.mir.instructions.items(.tag)[inst] == .call_extern);
675676 const relocation = emit.mir.instructions.items(.data)[inst].relocation;
676677
678 const offset = blk: {
679 const offset = @intCast(u32, emit.code.items.len);
680 // bl
681 try emit.writeInstruction(Instruction.bl(0));
682 break :blk offset;
683 };
684
677685 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
678 const offset = blk: {
679 const offset = @intCast(u32, emit.code.items.len);
680 // bl
681 try emit.writeInstruction(Instruction.bl(0));
682 break :blk offset;
683 };
684686 // Add relocation to the decl.
685687 const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
686688 const target = macho_file.getGlobalByIndex(relocation.sym_index);
......@@ -692,8 +694,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
692694 .pcrel = true,
693695 .length = 2,
694696 });
697 } else if (emit.bin_file.cast(link.File.Coff)) |_| {
698 unreachable; // Calling imports is handled via `.load_memory_import`
695699 } else {
696 return emit.fail("Implement call_extern for linking backends != MachO", .{});
700 return emit.fail("Implement call_extern for linking backends != {{ COFF, MachO }}", .{});
697701 }
698702}
699703
......@@ -855,7 +859,9 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
855859 try emit.writeInstruction(Instruction.adrp(reg.toX(), 0));
856860
857861 switch (tag) {
858 .load_memory_got => {
862 .load_memory_got,
863 .load_memory_import,
864 => {
859865 // ldr reg, reg, offset
860866 try emit.writeInstruction(Instruction.ldr(
861867 reg,
......@@ -926,6 +932,51 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
926932 else => unreachable,
927933 },
928934 });
935 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
936 const atom = coff_file.getAtomForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
937 const target = switch (tag) {
938 .load_memory_got,
939 .load_memory_ptr_got,
940 .load_memory_direct,
941 .load_memory_ptr_direct,
942 => link.File.Coff.SymbolWithLoc{ .sym_index = data.sym_index, .file = null },
943 .load_memory_import => coff_file.getGlobalByIndex(data.sym_index),
944 else => unreachable,
945 };
946 try atom.addRelocation(coff_file, .{
947 .target = target,
948 .offset = offset,
949 .addend = 0,
950 .pcrel = true,
951 .length = 2,
952 .@"type" = switch (tag) {
953 .load_memory_got,
954 .load_memory_ptr_got,
955 => .got_page,
956 .load_memory_direct,
957 .load_memory_ptr_direct,
958 => .page,
959 .load_memory_import => .import_page,
960 else => unreachable,
961 },
962 });
963 try atom.addRelocation(coff_file, .{
964 .target = target,
965 .offset = offset + 4,
966 .addend = 0,
967 .pcrel = false,
968 .length = 2,
969 .@"type" = switch (tag) {
970 .load_memory_got,
971 .load_memory_ptr_got,
972 => .got_pageoff,
973 .load_memory_direct,
974 .load_memory_ptr_direct,
975 => .pageoff,
976 .load_memory_import => .import_pageoff,
977 else => unreachable,
978 },
979 });
929980 } else {
930981 return emit.fail("TODO implement load_memory for PIE GOT indirection on this platform", .{});
931982 }
src/arch/aarch64/Mir.zig+4
......@@ -84,6 +84,10 @@ pub const Inst = struct {
8484 ///
8585 /// Payload is `LoadMemoryPie`
8686 load_memory_direct,
87 /// Loads the contents into a register
88 ///
89 /// Payload is `LoadMemoryPie`
90 load_memory_import,
8791 /// Loads the address into a register
8892 ///
8993 /// Payload is `LoadMemoryPie`
src/link/Coff.zig+188-34
......@@ -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");
......@@ -125,9 +127,29 @@ const Entry = struct {
125127
126128pub const Reloc = struct {
127129 @"type": enum {
130 // x86, x86_64
131 /// RIP-relative displacement to a GOT pointer
128132 got,
129 direct,
133 /// RIP-relative displacement to an import pointer
130134 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,
131153 },
132154 target: SymbolWithLoc,
133155 offset: u32,
......@@ -139,9 +161,20 @@ pub const Reloc = struct {
139161 /// Returns an Atom which is the target node of this relocation edge (if any).
140162 fn getTargetAtom(self: Reloc, coff_file: *Coff) ?*Atom {
141163 switch (self.@"type") {
142 .got => return coff_file.getGotAtomForSymbol(self.target),
143 .direct => return coff_file.getAtomForSymbol(self.target),
144 .import => return coff_file.getImportAtomForSymbol(self.target),
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),
145178 }
146179 }
147180};
......@@ -151,8 +184,6 @@ const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanag
151184const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));
152185
153186const default_file_alignment: u16 = 0x200;
154const default_image_base_dll: u64 = 0x10000000;
155const default_image_base_exe: u64 = 0x400000;
156187const default_size_of_stack_reserve: u32 = 0x1000000;
157188const default_size_of_stack_commit: u32 = 0x1000;
158189const default_size_of_heap_reserve: u32 = 0x100000;
......@@ -866,12 +897,14 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
866897 for (relocs.items) |*reloc| {
867898 if (!reloc.dirty) continue;
868899
900 const source_vaddr = source_sym.value + reloc.offset;
869901 const target_atom = reloc.getTargetAtom(self) orelse continue;
870902 const target_vaddr = target_atom.getSymbol(self).value;
871903 const target_vaddr_with_addend = target_vaddr + reloc.addend;
904 const image_base = self.getImageBase();
872905
873906 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{
874 source_sym.value + reloc.offset,
907 source_vaddr,
875908 target_vaddr_with_addend,
876909 self.getSymbolName(reloc.target),
877910 @tagName(reloc.@"type"),
......@@ -880,30 +913,137 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
880913
881914 reloc.dirty = false;
882915
883 if (reloc.pcrel) {
884 const source_vaddr = source_sym.value + reloc.offset;
885 const disp =
886 @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4;
887 try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset);
888 continue;
889 }
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 }
890930
891 switch (self.ptr_width) {
892 .p32 => try self.base.file.?.pwriteAll(
893 mem.asBytes(&@intCast(u32, target_vaddr_with_addend + default_image_base_exe)),
894 file_offset + reloc.offset,
895 ),
896 .p64 => switch (reloc.length) {
897 2 => try self.base.file.?.pwriteAll(
898 mem.asBytes(&@truncate(u32, target_vaddr_with_addend + default_image_base_exe)),
899 file_offset + reloc.offset,
900 ),
901 3 => try self.base.file.?.pwriteAll(
902 mem.asBytes(&(target_vaddr_with_addend + default_image_base_exe)),
903 file_offset + reloc.offset,
904 ),
905 else => unreachable,
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 }
9061005 },
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
9071047 }
9081048 }
9091049}
......@@ -1831,11 +1971,7 @@ fn writeHeader(self: *Coff) !void {
18311971 const subsystem: coff.Subsystem = .WINDOWS_CUI;
18321972 const size_of_image: u32 = self.getSizeOfImage();
18331973 const size_of_headers: u32 = mem.alignForwardGeneric(u32, self.getSizeOfHeaders(), default_file_alignment);
1834 const image_base = self.base.options.image_base_override orelse switch (self.base.options.output_mode) {
1835 .Exe => default_image_base_exe,
1836 .Lib => default_image_base_dll,
1837 else => unreachable,
1838 };
1974 const image_base = self.getImageBase();
18391975
18401976 const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address;
18411977 const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address;
......@@ -2042,6 +2178,19 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
20422178 return self.globals.items[global_index];
20432179}
20442180
2181pub fn getImageBase(self: Coff) u64 {
2182 const image_base: u64 = self.base.options.image_base_override orelse switch (self.base.options.output_mode) {
2183 .Exe => switch (self.base.options.target.cpu.arch) {
2184 .aarch64 => @as(u64, 0x140000000),
2185 .x86_64, .x86 => 0x400000,
2186 else => unreachable, // unsupported target architecture
2187 },
2188 .Lib => 0x10000000,
2189 .Obj => 0,
2190 };
2191 return image_base;
2192}
2193
20452194/// Returns pointer-to-symbol described by `sym_loc` descriptor.
20462195pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol {
20472196 assert(sym_loc.file == null); // TODO linking object files
......@@ -2248,3 +2397,8 @@ fn logSections(self: *Coff) void {
22482397 });
22492398 }
22502399}
2400
2401inline fn isArithmeticOp(inst: *const [4]u8) bool {
2402 const group_decode = @truncate(u5, inst[3]);
2403 return ((group_decode >> 2) == 4);
2404}