| author | |
| committer | |
| log | 28288dcbbf5258fe7461bbe0f6b2feeba0c2de5d |
| tree | b2517ebf4369ffb2c078b4ceced49a3f83e33c4a |
| parent | 1d680459197e7ba5e163d99e07fdfe54c2ad9225 |
| parent | 165ae04a03206af34707b5505dc042338ce4731e |
| signature |
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 |
| 36 | 36 | ||
| 37 | fn getStdOutHandle() os.fd_t { | 37 | fn 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 { |
| 62 | 62 | ||
| 63 | fn getStdErrHandle() os.fd_t { | 63 | fn 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 { |
| 88 | 88 | ||
| 89 | fn getStdInHandle() os.fd_t { | 89 | fn 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 in | 149 | /// 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( |
| 145 | 145 | ||
| 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), |
| 150 | 151 | ||
| ... | @@ -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; |
| 676 | 677 | ||
| 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 | } |
| 699 | 703 | ||
| ... | @@ -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)); |
| 856 | 860 | ||
| 857 | switch (tag) { | 861 | switch (tag) { |
| 858 | .load_memory_got => { | 862 | .load_memory_got, |
| 863 | .load_memory_import, | ||
| 864 | => { | ||
| 859 | // ldr reg, reg, offset | 865 | // 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 register | 91 | /// 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; |
| 9 | const log = std.log.scoped(.link); | 9 | const log = std.log.scoped(.link); |
| 10 | const math = std.math; | 10 | const math = std.math; |
| 11 | const mem = std.mem; | 11 | const mem = std.mem; |
| 12 | const meta = std.meta; | ||
| 12 | 13 | ||
| 13 | const Allocator = std.mem.Allocator; | 14 | const Allocator = std.mem.Allocator; |
| 14 | 15 | ||
| 16 | const aarch64 = @import("../arch/aarch64/bits.zig"); | ||
| 15 | const codegen = @import("../codegen.zig"); | 17 | const codegen = @import("../codegen.zig"); |
| 16 | const link = @import("../link.zig"); | 18 | const link = @import("../link.zig"); |
| 17 | const lld = @import("Coff/lld.zig"); | 19 | const lld = @import("Coff/lld.zig"); |
| ... | @@ -125,9 +127,29 @@ const Entry = struct { | ... | @@ -125,9 +127,29 @@ const Entry = struct { |
| 125 | 127 | ||
| 126 | pub const Reloc = struct { | 128 | pub 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 |
| 151 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); | 184 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| 152 | 185 | ||
| 153 | const default_file_alignment: u16 = 0x200; | 186 | const default_file_alignment: u16 = 0x200; |
| 154 | const default_image_base_dll: u64 = 0x10000000; | ||
| 155 | const default_image_base_exe: u64 = 0x400000; | ||
| 156 | const default_size_of_stack_reserve: u32 = 0x1000000; | 187 | const default_size_of_stack_reserve: u32 = 0x1000000; |
| 157 | const default_size_of_stack_commit: u32 = 0x1000; | 188 | const default_size_of_stack_commit: u32 = 0x1000; |
| 158 | const default_size_of_heap_reserve: u32 = 0x100000; | 189 | const 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; |
| 868 | 899 | ||
| 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(); | ||
| 872 | 905 | ||
| 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 { |
| 880 | 913 | ||
| 881 | reloc.dirty = false; | 914 | reloc.dirty = false; |
| 882 | 915 | ||
| 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 | } | ||
| 890 | 930 | ||
| 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 | }; | ||
| 1839 | 1975 | ||
| 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 | } |
| 2044 | 2180 | ||
| 2181 | pub 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. |
| 2046 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { | 2195 | pub fn getSymbolPtr(self: *Coff, sym_loc: SymbolWithLoc) *coff.Symbol { |
| 2047 | assert(sym_loc.file == null); // TODO linking object files | 2196 | 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 | |||
| 2401 | inline fn isArithmeticOp(inst: *const [4]u8) bool { | ||
| 2402 | const group_decode = @truncate(u5, inst[3]); | ||
| 2403 | return ((group_decode >> 2) == 4); | ||
| 2404 | } |