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...@@ -36,7 +36,7 @@ pub const default_mode: ModeOverride = if (is_async) Mode.evented else .blocking
3636
37fn getStdOutHandle() os.fd_t {37fn getStdOutHandle() os.fd_t {
38 if (builtin.os.tag == .windows) {38 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) {
40 // TODO: this is just a temporary workaround until we advance x86 backend further along.40 // TODO: this is just a temporary workaround until we advance x86 backend further along.
41 return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;41 return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
42 }42 }
...@@ -62,7 +62,7 @@ pub fn getStdOut() File {...@@ -62,7 +62,7 @@ pub fn getStdOut() File {
6262
63fn getStdErrHandle() os.fd_t {63fn getStdErrHandle() os.fd_t {
64 if (builtin.os.tag == .windows) {64 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) {
66 // TODO: this is just a temporary workaround until we advance x86 backend further along.66 // TODO: this is just a temporary workaround until we advance x86 backend further along.
67 return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;67 return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
68 }68 }
...@@ -88,7 +88,7 @@ pub fn getStdErr() File {...@@ -88,7 +88,7 @@ pub fn getStdErr() File {
8888
89fn getStdInHandle() os.fd_t {89fn getStdInHandle() os.fd_t {
90 if (builtin.os.tag == .windows) {90 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) {
92 // TODO: this is just a temporary workaround until we advance x86 backend further along.92 // TODO: this is just a temporary workaround until we advance x86 backend further along.
93 return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;93 return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
94 }94 }
src/arch/aarch64/CodeGen.zig+86-13
...@@ -142,7 +142,8 @@ const MCValue = union(enum) {...@@ -142,7 +142,8 @@ const MCValue = union(enum) {
142 /// The value is in memory but requires a linker relocation fixup:142 /// The value is in memory but requires a linker relocation fixup:
143 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)143 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
144 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)144 /// * 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 },
146 /// The value is one of the stack variables.147 /// The value is one of the stack variables.
147 ///148 ///
148 /// If the type is a pointer, it means the pointer address is in149 /// If the type is a pointer, it means the pointer address is in
...@@ -1117,13 +1118,11 @@ fn truncRegister(...@@ -1117,13 +1118,11 @@ fn truncRegister(
1117 });1118 });
1118 },1119 },
1119 32, 64 => {1120 32, 64 => {
1120 assert(dest_reg.size() == operand_reg.size());
1121
1122 _ = try self.addInst(.{1121 _ = try self.addInst(.{
1123 .tag = .mov_register,1122 .tag = .mov_register,
1124 .data = .{ .rr = .{1123 .data = .{ .rr = .{
1125 .rd = dest_reg,1124 .rd = if (int_bits == 32) dest_reg.toW() else dest_reg.toX(),
1126 .rn = operand_reg,1125 .rn = if (int_bits == 32) operand_reg.toW() else operand_reg.toX(),
1127 } },1126 } },
1128 });1127 });
1129 },1128 },
...@@ -3719,14 +3718,21 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3719,14 +3718,21 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
3719 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {3718 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
3720 .got => .load_memory_ptr_got,3719 .got => .load_memory_ptr_got,
3721 .direct => .load_memory_ptr_direct,3720 .direct => .load_memory_ptr_direct,
3721 .import => unreachable,
3722 };3722 };
3723 const mod = self.bin_file.options.module.?;3723 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 };
3724 _ = try self.addInst(.{3730 _ = try self.addInst(.{
3725 .tag = tag,3731 .tag = tag,
3726 .data = .{3732 .data = .{
3727 .payload = try self.addExtra(Mir.LoadMemoryPie{3733 .payload = try self.addExtra(Mir.LoadMemoryPie{
3728 .register = @enumToInt(src_reg),3734 .register = @enumToInt(src_reg),
3729 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,3735 .atom_index = atom_index,
3730 .sym_index = load_struct.sym_index,3736 .sym_index = load_struct.sym_index,
3731 }),3737 }),
3732 },3738 },
...@@ -4057,6 +4063,45 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4057,6 +4063,45 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4057 } else {4063 } else {
4058 return self.fail("TODO implement calling bitcasted functions", .{});4064 return self.fail("TODO implement calling bitcasted functions", .{});
4059 }4065 }
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 }
4060 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {4105 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4061 if (func_value.castTag(.function)) |func_payload| {4106 if (func_value.castTag(.function)) |func_payload| {
4062 try p9.seeDecl(func_payload.data.owner_decl);4107 try p9.seeDecl(func_payload.data.owner_decl);
...@@ -4077,8 +4122,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -4077,8 +4122,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
4077 } else {4122 } else {
4078 return self.fail("TODO implement calling bitcasted functions", .{});4123 return self.fail("TODO implement calling bitcasted functions", .{});
4079 }4124 }
4080 } else if (self.bin_file.cast(link.File.Coff)) |_| {
4081 return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch});
4082 } else unreachable;4125 } else unreachable;
4083 } else {4126 } else {
4084 assert(ty.zigTypeTag() == .Pointer);4127 assert(ty.zigTypeTag() == .Pointer);
...@@ -5161,14 +5204,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -5161,14 +5204,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
5161 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {5204 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
5162 .got => .load_memory_ptr_got,5205 .got => .load_memory_ptr_got,
5163 .direct => .load_memory_ptr_direct,5206 .direct => .load_memory_ptr_direct,
5207 .import => unreachable,
5164 };5208 };
5165 const mod = self.bin_file.options.module.?;5209 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 };
5166 _ = try self.addInst(.{5216 _ = try self.addInst(.{
5167 .tag = tag,5217 .tag = tag,
5168 .data = .{5218 .data = .{
5169 .payload = try self.addExtra(Mir.LoadMemoryPie{5219 .payload = try self.addExtra(Mir.LoadMemoryPie{
5170 .register = @enumToInt(src_reg),5220 .register = @enumToInt(src_reg),
5171 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,5221 .atom_index = atom_index,
5172 .sym_index = load_struct.sym_index,5222 .sym_index = load_struct.sym_index,
5173 }),5223 }),
5174 },5224 },
...@@ -5268,14 +5318,21 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -5268,14 +5318,21 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
5268 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {5318 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
5269 .got => .load_memory_got,5319 .got => .load_memory_got,
5270 .direct => .load_memory_direct,5320 .direct => .load_memory_direct,
5321 .import => .load_memory_import,
5271 };5322 };
5272 const mod = self.bin_file.options.module.?;5323 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 };
5273 _ = try self.addInst(.{5330 _ = try self.addInst(.{
5274 .tag = tag,5331 .tag = tag,
5275 .data = .{5332 .data = .{
5276 .payload = try self.addExtra(Mir.LoadMemoryPie{5333 .payload = try self.addExtra(Mir.LoadMemoryPie{
5277 .register = @enumToInt(reg),5334 .register = @enumToInt(reg),
5278 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,5335 .atom_index = atom_index,
5279 .sym_index = load_struct.sym_index,5336 .sym_index = load_struct.sym_index,
5280 }),5337 }),
5281 },5338 },
...@@ -5455,14 +5512,21 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -5455,14 +5512,21 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
5455 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {5512 const tag: Mir.Inst.Tag = switch (load_struct.@"type") {
5456 .got => .load_memory_ptr_got,5513 .got => .load_memory_ptr_got,
5457 .direct => .load_memory_ptr_direct,5514 .direct => .load_memory_ptr_direct,
5515 .import => unreachable,
5458 };5516 };
5459 const mod = self.bin_file.options.module.?;5517 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 };
5460 _ = try self.addInst(.{5524 _ = try self.addInst(.{
5461 .tag = tag,5525 .tag = tag,
5462 .data = .{5526 .data = .{
5463 .payload = try self.addExtra(Mir.LoadMemoryPie{5527 .payload = try self.addExtra(Mir.LoadMemoryPie{
5464 .register = @enumToInt(src_reg),5528 .register = @enumToInt(src_reg),
5465 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,5529 .atom_index = atom_index,
5466 .sym_index = load_struct.sym_index,5530 .sym_index = load_struct.sym_index,
5467 }),5531 }),
5468 },5532 },
...@@ -5775,7 +5839,13 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -5775,7 +5839,13 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
5775 .sym_index = decl.link.macho.sym_index,5839 .sym_index = decl.link.macho.sym_index,
5776 } };5840 } };
5777 } else if (self.bin_file.cast(link.File.Coff)) |_| {5841 } 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 } };
5779 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {5849 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
5780 try p9.seeDecl(decl_index);5850 try p9.seeDecl(decl_index);
5781 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;5851 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 {...@@ -5799,7 +5869,10 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
5799 .sym_index = local_sym_index,5869 .sym_index = local_sym_index,
5800 } };5870 } };
5801 } else if (self.bin_file.cast(link.File.Coff)) |_| {5871 } 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 } };
5803 } else if (self.bin_file.cast(link.File.Plan9)) |_| {5876 } else if (self.bin_file.cast(link.File.Plan9)) |_| {
5804 return self.fail("TODO lower unnamed const in Plan9", .{});5877 return self.fail("TODO lower unnamed const in Plan9", .{});
5805 } else {5878 } else {
src/arch/aarch64/Emit.zig+59-8
...@@ -145,6 +145,7 @@ pub fn emitMir(...@@ -145,6 +145,7 @@ pub fn emitMir(
145145
146 .load_memory_got => try emit.mirLoadMemoryPie(inst),146 .load_memory_got => try emit.mirLoadMemoryPie(inst),
147 .load_memory_direct => try emit.mirLoadMemoryPie(inst),147 .load_memory_direct => try emit.mirLoadMemoryPie(inst),
148 .load_memory_import => try emit.mirLoadMemoryPie(inst),
148 .load_memory_ptr_got => try emit.mirLoadMemoryPie(inst),149 .load_memory_ptr_got => try emit.mirLoadMemoryPie(inst),
149 .load_memory_ptr_direct => try emit.mirLoadMemoryPie(inst),150 .load_memory_ptr_direct => try emit.mirLoadMemoryPie(inst),
150151
...@@ -674,13 +675,14 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -674,13 +675,14 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
674 assert(emit.mir.instructions.items(.tag)[inst] == .call_extern);675 assert(emit.mir.instructions.items(.tag)[inst] == .call_extern);
675 const relocation = emit.mir.instructions.items(.data)[inst].relocation;676 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
677 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {685 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 };
684 // Add relocation to the decl.686 // Add relocation to the decl.
685 const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;687 const atom = macho_file.getAtomForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
686 const target = macho_file.getGlobalByIndex(relocation.sym_index);688 const target = macho_file.getGlobalByIndex(relocation.sym_index);
...@@ -692,8 +694,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -692,8 +694,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
692 .pcrel = true,694 .pcrel = true,
693 .length = 2,695 .length = 2,
694 });696 });
697 } else if (emit.bin_file.cast(link.File.Coff)) |_| {
698 unreachable; // Calling imports is handled via `.load_memory_import`
695 } else {699 } else {
696 return emit.fail("Implement call_extern for linking backends != MachO", .{});700 return emit.fail("Implement call_extern for linking backends != {{ COFF, MachO }}", .{});
697 }701 }
698}702}
699703
...@@ -855,7 +859,9 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -855,7 +859,9 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
855 try emit.writeInstruction(Instruction.adrp(reg.toX(), 0));859 try emit.writeInstruction(Instruction.adrp(reg.toX(), 0));
856860
857 switch (tag) {861 switch (tag) {
858 .load_memory_got => {862 .load_memory_got,
863 .load_memory_import,
864 => {
859 // ldr reg, reg, offset865 // ldr reg, reg, offset
860 try emit.writeInstruction(Instruction.ldr(866 try emit.writeInstruction(Instruction.ldr(
861 reg,867 reg,
...@@ -926,6 +932,51 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -926,6 +932,51 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
926 else => unreachable,932 else => unreachable,
927 },933 },
928 });934 });
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 });
929 } else {980 } else {
930 return emit.fail("TODO implement load_memory for PIE GOT indirection on this platform", .{});981 return emit.fail("TODO implement load_memory for PIE GOT indirection on this platform", .{});
931 }982 }
src/arch/aarch64/Mir.zig+4
...@@ -84,6 +84,10 @@ pub const Inst = struct {...@@ -84,6 +84,10 @@ pub const Inst = struct {
84 ///84 ///
85 /// Payload is `LoadMemoryPie`85 /// Payload is `LoadMemoryPie`
86 load_memory_direct,86 load_memory_direct,
87 /// Loads the contents into a register
88 ///
89 /// Payload is `LoadMemoryPie`
90 load_memory_import,
87 /// Loads the address into a register91 /// Loads the address into a register
88 ///92 ///
89 /// Payload is `LoadMemoryPie`93 /// Payload is `LoadMemoryPie`
src/link/Coff.zig+188-34
...@@ -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");
...@@ -125,9 +127,29 @@ const Entry = struct {...@@ -125,9 +127,29 @@ const Entry = struct {
125127
126pub const Reloc = struct {128pub const Reloc = struct {
127 @"type": enum {129 @"type": enum {
130 // x86, x86_64
131 /// RIP-relative displacement to a GOT pointer
128 got,132 got,
129 direct,133 /// RIP-relative displacement to an import pointer
130 import,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,
131 },153 },
132 target: SymbolWithLoc,154 target: SymbolWithLoc,
133 offset: u32,155 offset: u32,
...@@ -139,9 +161,20 @@ pub const Reloc = struct {...@@ -139,9 +161,20 @@ pub const Reloc = struct {
139 /// Returns an Atom which is the target node of this relocation edge (if any).161 /// Returns an Atom which is the target node of this relocation edge (if any).
140 fn getTargetAtom(self: Reloc, coff_file: *Coff) ?*Atom {162 fn getTargetAtom(self: Reloc, coff_file: *Coff) ?*Atom {
141 switch (self.@"type") {163 switch (self.@"type") {
142 .got => return coff_file.getGotAtomForSymbol(self.target),164 .got,
143 .direct => return coff_file.getAtomForSymbol(self.target),165 .got_page,
144 .import => return coff_file.getImportAtomForSymbol(self.target),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),
145 }178 }
146 }179 }
147};180};
...@@ -151,8 +184,6 @@ const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanag...@@ -151,8 +184,6 @@ const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanag
151const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));184const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));
152185
153const default_file_alignment: u16 = 0x200;186const default_file_alignment: u16 = 0x200;
154const default_image_base_dll: u64 = 0x10000000;
155const default_image_base_exe: u64 = 0x400000;
156const default_size_of_stack_reserve: u32 = 0x1000000;187const default_size_of_stack_reserve: u32 = 0x1000000;
157const default_size_of_stack_commit: u32 = 0x1000;188const default_size_of_stack_commit: u32 = 0x1000;
158const default_size_of_heap_reserve: u32 = 0x100000;189const default_size_of_heap_reserve: u32 = 0x100000;
...@@ -866,12 +897,14 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {...@@ -866,12 +897,14 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
866 for (relocs.items) |*reloc| {897 for (relocs.items) |*reloc| {
867 if (!reloc.dirty) continue;898 if (!reloc.dirty) continue;
868899
900 const source_vaddr = source_sym.value + reloc.offset;
869 const target_atom = reloc.getTargetAtom(self) orelse continue;901 const target_atom = reloc.getTargetAtom(self) orelse continue;
870 const target_vaddr = target_atom.getSymbol(self).value;902 const target_vaddr = target_atom.getSymbol(self).value;
871 const target_vaddr_with_addend = target_vaddr + reloc.addend;903 const target_vaddr_with_addend = target_vaddr + reloc.addend;
904 const image_base = self.getImageBase();
872905
873 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{906 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{
874 source_sym.value + reloc.offset,907 source_vaddr,
875 target_vaddr_with_addend,908 target_vaddr_with_addend,
876 self.getSymbolName(reloc.target),909 self.getSymbolName(reloc.target),
877 @tagName(reloc.@"type"),910 @tagName(reloc.@"type"),
...@@ -880,30 +913,137 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {...@@ -880,30 +913,137 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
880913
881 reloc.dirty = false;914 reloc.dirty = false;
882915
883 if (reloc.pcrel) {916 switch (self.base.options.target.cpu.arch) {
884 const source_vaddr = source_sym.value + reloc.offset;917 .aarch64 => {
885 const disp =918 var buffer: [@sizeOf(u64)]u8 = undefined;
886 @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4;919 switch (reloc.length) {
887 try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset);920 2 => {
888 continue;921 const amt = try self.base.file.?.preadAll(buffer[0..4], file_offset + reloc.offset);
889 }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) {931 switch (reloc.@"type") {
892 .p32 => try self.base.file.?.pwriteAll(932 .got_page, .import_page, .page => {
893 mem.asBytes(&@intCast(u32, target_vaddr_with_addend + default_image_base_exe)),933 const source_page = @intCast(i32, source_vaddr >> 12);
894 file_offset + reloc.offset,934 const target_page = @intCast(i32, target_vaddr_with_addend >> 12);
895 ),935 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
896 .p64 => switch (reloc.length) {936 var inst = aarch64.Instruction{
897 2 => try self.base.file.?.pwriteAll(937 .pc_relative_address = mem.bytesToValue(meta.TagPayload(
898 mem.asBytes(&@truncate(u32, target_vaddr_with_addend + default_image_base_exe)),938 aarch64.Instruction,
899 file_offset + reloc.offset,939 aarch64.Instruction.pc_relative_address,
900 ),940 ), buffer[0..4]),
901 3 => try self.base.file.?.pwriteAll(941 };
902 mem.asBytes(&(target_vaddr_with_addend + default_image_base_exe)),942 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
903 file_offset + reloc.offset,943 inst.pc_relative_address.immlo = @truncate(u2, pages);
904 ),944 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
905 else => unreachable,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 }
906 },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
907 }1047 }
908 }1048 }
909}1049}
...@@ -1831,11 +1971,7 @@ fn writeHeader(self: *Coff) !void {...@@ -1831,11 +1971,7 @@ fn writeHeader(self: *Coff) !void {
1831 const subsystem: coff.Subsystem = .WINDOWS_CUI;1971 const subsystem: coff.Subsystem = .WINDOWS_CUI;
1832 const size_of_image: u32 = self.getSizeOfImage();1972 const size_of_image: u32 = self.getSizeOfImage();
1833 const size_of_headers: u32 = mem.alignForwardGeneric(u32, self.getSizeOfHeaders(), default_file_alignment);1973 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) {1974 const image_base = self.getImageBase();
1835 .Exe => default_image_base_exe,
1836 .Lib => default_image_base_dll,
1837 else => unreachable,
1838 };
18391975
1840 const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address;1976 const base_of_code = self.sections.get(self.text_section_index.?).header.virtual_address;
1841 const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address;1977 const base_of_data = self.sections.get(self.data_section_index.?).header.virtual_address;
...@@ -2042,6 +2178,19 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {...@@ -2042,6 +2178,19 @@ pub fn getEntryPoint(self: Coff) ?SymbolWithLoc {
2042 return self.globals.items[global_index];2178 return self.globals.items[global_index];
2043}2179}
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
2045/// Returns pointer-to-symbol described by `sym_loc` descriptor.2194/// Returns pointer-to-symbol described by `sym_loc` descriptor.
2046pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol {2195pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol {
2047 assert(sym_loc.file == null); // TODO linking object files2196 assert(sym_loc.file == null); // TODO linking object files
...@@ -2248,3 +2397,8 @@ fn logSections(self: *Coff) void {...@@ -2248,3 +2397,8 @@ fn logSections(self: *Coff) void {
2248 });2397 });
2249 }2398 }
2250}2399}
2400
2401inline fn isArithmeticOp(inst: *const [4]u8) bool {
2402 const group_decode = @truncate(u5, inst[3]);
2403 return ((group_decode >> 2) == 4);
2404}