| ... | @@ -118,6 +118,10 @@ pub const MCValue = union(enum) { | ... | @@ -118,6 +118,10 @@ pub const MCValue = union(enum) { |
| 118 | /// The value is in memory at a hard-coded address. | 118 | /// The value is in memory at a hard-coded address. |
| 119 | /// If the type is a pointer, it means the pointer address is at this memory location. | 119 | /// If the type is a pointer, it means the pointer address is at this memory location. |
| 120 | memory: u64, | 120 | memory: u64, |
| | 121 | /// The value is in memory but not allocated an address yet by the linker, so we store |
| | 122 | /// the symbol index instead. |
| | 123 | /// If the type is a pointer, it means the pointer is the symbol. |
| | 124 | linker_sym_index: u32, |
| 121 | /// The value is one of the stack variables. | 125 | /// The value is one of the stack variables. |
| 122 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. | 126 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. |
| 123 | stack_offset: i32, | 127 | stack_offset: i32, |
| ... | @@ -1686,8 +1690,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1686,8 +1690,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1686 | else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}), | 1690 | else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}), |
| 1687 | } | 1691 | } |
| 1688 | }, | 1692 | }, |
| 1689 | .memory => |addr| { | 1693 | .memory, |
| 1690 | const reg = try self.copyToTmpRegister(ptr_ty, .{ .memory = addr }); | 1694 | .linker_sym_index, |
| | 1695 | => { |
| | 1696 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 1691 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); | 1697 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| 1692 | }, | 1698 | }, |
| 1693 | .stack_offset => { | 1699 | .stack_offset => { |
| ... | @@ -1817,27 +1823,33 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1817,27 +1823,33 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1817 | }, | 1823 | }, |
| 1818 | } | 1824 | } |
| 1819 | }, | 1825 | }, |
| 1820 | .memory => |addr| { | 1826 | .linker_sym_index, |
| | 1827 | .memory, |
| | 1828 | => { |
| 1821 | value.freezeIfRegister(&self.register_manager); | 1829 | value.freezeIfRegister(&self.register_manager); |
| 1822 | defer value.unfreezeIfRegister(&self.register_manager); | 1830 | defer value.unfreezeIfRegister(&self.register_manager); |
| 1823 | | 1831 | |
| 1824 | const addr_reg: Register = blk: { | 1832 | const addr_reg: Register = blk: { |
| 1825 | if (self.bin_file.options.pie) { | 1833 | switch (ptr) { |
| 1826 | const addr_reg = try self.register_manager.allocReg(null); | 1834 | .linker_sym_index => |sym_index| { |
| 1827 | _ = try self.addInst(.{ | 1835 | const addr_reg = try self.register_manager.allocReg(null); |
| 1828 | .tag = .lea, | 1836 | _ = try self.addInst(.{ |
| 1829 | .ops = (Mir.Ops{ | 1837 | .tag = .lea, |
| 1830 | .reg1 = addr_reg.to64(), | 1838 | .ops = (Mir.Ops{ |
| 1831 | .flags = 0b10, | 1839 | .reg1 = addr_reg.to64(), |
| 1832 | }).encode(), | 1840 | .flags = 0b10, |
| 1833 | .data = .{ .got_entry = @truncate(u32, addr) }, | 1841 | }).encode(), |
| 1834 | }); | 1842 | .data = .{ .got_entry = sym_index }, |
| 1835 | break :blk addr_reg; | 1843 | }); |
| 1836 | } else { | 1844 | break :blk addr_reg; |
| 1837 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] | 1845 | }, |
| 1838 | // instead of wasting an instruction copying the address to a register | 1846 | .memory => |addr| { |
| 1839 | const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); | 1847 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] |
| 1840 | break :blk addr_reg; | 1848 | // instead of wasting an instruction copying the address to a register |
| | 1849 | const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); |
| | 1850 | break :blk addr_reg; |
| | 1851 | }, |
| | 1852 | else => unreachable, |
| 1841 | } | 1853 | } |
| 1842 | }; | 1854 | }; |
| 1843 | | 1855 | |
| ... | @@ -2148,6 +2160,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -2148,6 +2160,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2148 | .embedded_in_code, .memory => { | 2160 | .embedded_in_code, .memory => { |
| 2149 | return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); | 2161 | return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); |
| 2150 | }, | 2162 | }, |
| | 2163 | .linker_sym_index => { |
| | 2164 | return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{}); |
| | 2165 | }, |
| 2151 | .stack_offset => |off| { | 2166 | .stack_offset => |off| { |
| 2152 | if (off > math.maxInt(i32)) { | 2167 | if (off > math.maxInt(i32)) { |
| 2153 | return self.fail("stack offset too large", .{}); | 2168 | return self.fail("stack offset too large", .{}); |
| ... | @@ -2232,6 +2247,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -2232,6 +2247,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2232 | .embedded_in_code, .memory, .stack_offset => { | 2247 | .embedded_in_code, .memory, .stack_offset => { |
| 2233 | return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); | 2248 | return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{}); |
| 2234 | }, | 2249 | }, |
| | 2250 | .linker_sym_index => { |
| | 2251 | return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{}); |
| | 2252 | }, |
| 2235 | .compare_flags_unsigned => { | 2253 | .compare_flags_unsigned => { |
| 2236 | return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{}); | 2254 | return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{}); |
| 2237 | }, | 2255 | }, |
| ... | @@ -2243,6 +2261,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -2243,6 +2261,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 2243 | .embedded_in_code, .memory => { | 2261 | .embedded_in_code, .memory => { |
| 2244 | return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{}); | 2262 | return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{}); |
| 2245 | }, | 2263 | }, |
| | 2264 | .linker_sym_index => { |
| | 2265 | return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{}); |
| | 2266 | }, |
| 2246 | } | 2267 | } |
| 2247 | } | 2268 | } |
| 2248 | | 2269 | |
| ... | @@ -2296,6 +2317,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -2296,6 +2317,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2296 | .embedded_in_code, .memory, .stack_offset => { | 2317 | .embedded_in_code, .memory, .stack_offset => { |
| 2297 | return self.fail("TODO implement x86 multiply source memory", .{}); | 2318 | return self.fail("TODO implement x86 multiply source memory", .{}); |
| 2298 | }, | 2319 | }, |
| | 2320 | .linker_sym_index => { |
| | 2321 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); |
| | 2322 | }, |
| 2299 | .compare_flags_unsigned => { | 2323 | .compare_flags_unsigned => { |
| 2300 | return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{}); | 2324 | return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{}); |
| 2301 | }, | 2325 | }, |
| ... | @@ -2334,6 +2358,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -2334,6 +2358,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2334 | .embedded_in_code, .memory, .stack_offset => { | 2358 | .embedded_in_code, .memory, .stack_offset => { |
| 2335 | return self.fail("TODO implement x86 multiply source memory", .{}); | 2359 | return self.fail("TODO implement x86 multiply source memory", .{}); |
| 2336 | }, | 2360 | }, |
| | 2361 | .linker_sym_index => { |
| | 2362 | return self.fail("TODO implement x86 multiply source symbol at index in linker", .{}); |
| | 2363 | }, |
| 2337 | .compare_flags_unsigned => { | 2364 | .compare_flags_unsigned => { |
| 2338 | return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{}); | 2365 | return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{}); |
| 2339 | }, | 2366 | }, |
| ... | @@ -2345,6 +2372,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! | ... | @@ -2345,6 +2372,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) ! |
| 2345 | .embedded_in_code, .memory => { | 2372 | .embedded_in_code, .memory => { |
| 2346 | return self.fail("TODO implement x86 multiply destination memory", .{}); | 2373 | return self.fail("TODO implement x86 multiply destination memory", .{}); |
| 2347 | }, | 2374 | }, |
| | 2375 | .linker_sym_index => { |
| | 2376 | return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{}); |
| | 2377 | }, |
| 2348 | } | 2378 | } |
| 2349 | } | 2379 | } |
| 2350 | | 2380 | |
| ... | @@ -2448,6 +2478,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2448,6 +2478,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2448 | .dead => unreachable, | 2478 | .dead => unreachable, |
| 2449 | .embedded_in_code => unreachable, | 2479 | .embedded_in_code => unreachable, |
| 2450 | .memory => unreachable, | 2480 | .memory => unreachable, |
| | 2481 | .linker_sym_index => unreachable, |
| 2451 | .compare_flags_signed => unreachable, | 2482 | .compare_flags_signed => unreachable, |
| 2452 | .compare_flags_unsigned => unreachable, | 2483 | .compare_flags_unsigned => unreachable, |
| 2453 | } | 2484 | } |
| ... | @@ -2508,10 +2539,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2508,10 +2539,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2508 | if (self.air.value(callee)) |func_value| { | 2539 | if (self.air.value(callee)) |func_value| { |
| 2509 | if (func_value.castTag(.function)) |func_payload| { | 2540 | if (func_value.castTag(.function)) |func_payload| { |
| 2510 | const func = func_payload.data; | 2541 | const func = func_payload.data; |
| 2511 | // TODO I'm hacking my way through here by repurposing .memory for storing | | |
| 2512 | // index to the GOT target symbol index. | | |
| 2513 | try self.genSetReg(Type.initTag(.usize), .rax, .{ | 2542 | try self.genSetReg(Type.initTag(.usize), .rax, .{ |
| 2514 | .memory = func.owner_decl.link.macho.local_sym_index, | 2543 | .linker_sym_index = func.owner_decl.link.macho.local_sym_index, |
| 2515 | }); | 2544 | }); |
| 2516 | // callq *%rax | 2545 | // callq *%rax |
| 2517 | _ = try self.addInst(.{ | 2546 | _ = try self.addInst(.{ |
| ... | @@ -3547,6 +3576,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3547,6 +3576,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3547 | }, | 3576 | }, |
| 3548 | .memory, | 3577 | .memory, |
| 3549 | .embedded_in_code, | 3578 | .embedded_in_code, |
| | 3579 | .linker_sym_index, |
| 3550 | => { | 3580 | => { |
| 3551 | if (ty.abiSize(self.target.*) <= 8) { | 3581 | if (ty.abiSize(self.target.*) <= 8) { |
| 3552 | const reg = try self.copyToTmpRegister(ty, mcv); | 3582 | const reg = try self.copyToTmpRegister(ty, mcv); |
| ... | @@ -3952,29 +3982,28 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3952,29 +3982,28 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3952 | .data = undefined, | 3982 | .data = undefined, |
| 3953 | }); | 3983 | }); |
| 3954 | }, | 3984 | }, |
| | 3985 | .linker_sym_index => |sym_index| { |
| | 3986 | _ = try self.addInst(.{ |
| | 3987 | .tag = .lea, |
| | 3988 | .ops = (Mir.Ops{ |
| | 3989 | .reg1 = reg, |
| | 3990 | .flags = 0b10, |
| | 3991 | }).encode(), |
| | 3992 | .data = .{ .got_entry = sym_index }, |
| | 3993 | }); |
| | 3994 | // MOV reg, [reg] |
| | 3995 | _ = try self.addInst(.{ |
| | 3996 | .tag = .mov, |
| | 3997 | .ops = (Mir.Ops{ |
| | 3998 | .reg1 = reg, |
| | 3999 | .reg2 = reg, |
| | 4000 | .flags = 0b01, |
| | 4001 | }).encode(), |
| | 4002 | .data = .{ .imm = 0 }, |
| | 4003 | }); |
| | 4004 | }, |
| 3955 | .memory => |x| { | 4005 | .memory => |x| { |
| 3956 | // TODO can we move this entire logic into Emit.zig like with aarch64? | 4006 | if (x <= math.maxInt(i32)) { |
| 3957 | if (self.bin_file.options.pie) { | | |
| 3958 | // TODO we should flag up `x` as GOT symbol entry explicitly rather than as a hack. | | |
| 3959 | _ = try self.addInst(.{ | | |
| 3960 | .tag = .lea, | | |
| 3961 | .ops = (Mir.Ops{ | | |
| 3962 | .reg1 = reg, | | |
| 3963 | .flags = 0b10, | | |
| 3964 | }).encode(), | | |
| 3965 | .data = .{ .got_entry = @truncate(u32, x) }, | | |
| 3966 | }); | | |
| 3967 | // MOV reg, [reg] | | |
| 3968 | _ = try self.addInst(.{ | | |
| 3969 | .tag = .mov, | | |
| 3970 | .ops = (Mir.Ops{ | | |
| 3971 | .reg1 = reg, | | |
| 3972 | .reg2 = reg, | | |
| 3973 | .flags = 0b01, | | |
| 3974 | }).encode(), | | |
| 3975 | .data = .{ .imm = 0 }, | | |
| 3976 | }); | | |
| 3977 | } else if (x <= math.maxInt(i32)) { | | |
| 3978 | // mov reg, [ds:imm32] | 4007 | // mov reg, [ds:imm32] |
| 3979 | _ = try self.addInst(.{ | 4008 | _ = try self.addInst(.{ |
| 3980 | .tag = .mov, | 4009 | .tag = .mov, |
| ... | @@ -4285,9 +4314,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa | ... | @@ -4285,9 +4314,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa |
| 4285 | const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; | 4314 | const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; |
| 4286 | return MCValue{ .memory = got_addr }; | 4315 | return MCValue{ .memory = got_addr }; |
| 4287 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | 4316 | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 4288 | // TODO I'm hacking my way through here by repurposing .memory for storing | 4317 | // Because MachO is PIE-always-on, we defer memory address resolution until |
| 4289 | // index to the GOT target symbol index. | 4318 | // the linker has enough info to perform relocations. |
| 4290 | return MCValue{ .memory = decl.link.macho.local_sym_index }; | 4319 | return MCValue{ .linker_sym_index = decl.link.macho.local_sym_index }; |
| 4291 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 4320 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4292 | const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; | 4321 | const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; |
| 4293 | return MCValue{ .memory = got_addr }; | 4322 | return MCValue{ .memory = got_addr }; |