| ... | ... | @@ -118,6 +118,10 @@ pub const MCValue = union(enum) { |
| 118 | 118 | /// The value is in memory at a hard-coded address. |
| 119 | 119 | /// If the type is a pointer, it means the pointer address is at this memory location. |
| 120 | 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 | 125 | /// The value is one of the stack variables. |
| 122 | 126 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. |
| 123 | 127 | stack_offset: i32, |
| ... | ... | @@ -1686,8 +1690,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1686 | 1690 | else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}), |
| 1687 | 1691 | } |
| 1688 | 1692 | }, |
| 1689 | | .memory => |addr| { |
| 1690 | | const reg = try self.copyToTmpRegister(ptr_ty, .{ .memory = addr }); |
| 1693 | .memory, |
| 1694 | .linker_sym_index, |
| 1695 | => { |
| 1696 | const reg = try self.copyToTmpRegister(ptr_ty, ptr); |
| 1691 | 1697 | try self.load(dst_mcv, .{ .register = reg }, ptr_ty); |
| 1692 | 1698 | }, |
| 1693 | 1699 | .stack_offset => { |
| ... | ... | @@ -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 | 1829 | value.freezeIfRegister(&self.register_manager); |
| 1822 | 1830 | defer value.unfreezeIfRegister(&self.register_manager); |
| 1823 | 1831 | |
| 1824 | 1832 | const addr_reg: Register = blk: { |
| 1825 | | if (self.bin_file.options.pie) { |
| 1826 | | const addr_reg = try self.register_manager.allocReg(null); |
| 1827 | | _ = try self.addInst(.{ |
| 1828 | | .tag = .lea, |
| 1829 | | .ops = (Mir.Ops{ |
| 1830 | | .reg1 = addr_reg.to64(), |
| 1831 | | .flags = 0b10, |
| 1832 | | }).encode(), |
| 1833 | | .data = .{ .got_entry = @truncate(u32, addr) }, |
| 1834 | | }); |
| 1835 | | break :blk addr_reg; |
| 1836 | | } else { |
| 1837 | | // TODO: in case the address fits in an imm32 we can use [ds:imm32] |
| 1838 | | // instead of wasting an instruction copying the address to a register |
| 1839 | | const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr }); |
| 1840 | | break :blk addr_reg; |
| 1833 | switch (ptr) { |
| 1834 | .linker_sym_index => |sym_index| { |
| 1835 | const addr_reg = try self.register_manager.allocReg(null); |
| 1836 | _ = try self.addInst(.{ |
| 1837 | .tag = .lea, |
| 1838 | .ops = (Mir.Ops{ |
| 1839 | .reg1 = addr_reg.to64(), |
| 1840 | .flags = 0b10, |
| 1841 | }).encode(), |
| 1842 | .data = .{ .got_entry = sym_index }, |
| 1843 | }); |
| 1844 | break :blk addr_reg; |
| 1845 | }, |
| 1846 | .memory => |addr| { |
| 1847 | // TODO: in case the address fits in an imm32 we can use [ds:imm32] |
| 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 | 2160 | .embedded_in_code, .memory => { |
| 2149 | 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 | 2166 | .stack_offset => |off| { |
| 2152 | 2167 | if (off > math.maxInt(i32)) { |
| 2153 | 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 | 2247 | .embedded_in_code, .memory, .stack_offset => { |
| 2233 | 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 | 2253 | .compare_flags_unsigned => { |
| 2236 | 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 | 2261 | .embedded_in_code, .memory => { |
| 2244 | 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 | 2317 | .embedded_in_code, .memory, .stack_offset => { |
| 2297 | 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 | 2323 | .compare_flags_unsigned => { |
| 2300 | 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 | 2358 | .embedded_in_code, .memory, .stack_offset => { |
| 2335 | 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 | 2364 | .compare_flags_unsigned => { |
| 2338 | 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 | 2372 | .embedded_in_code, .memory => { |
| 2346 | 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 | 2478 | .dead => unreachable, |
| 2449 | 2479 | .embedded_in_code => unreachable, |
| 2450 | 2480 | .memory => unreachable, |
| 2481 | .linker_sym_index => unreachable, |
| 2451 | 2482 | .compare_flags_signed => unreachable, |
| 2452 | 2483 | .compare_flags_unsigned => unreachable, |
| 2453 | 2484 | } |
| ... | ... | @@ -2508,10 +2539,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2508 | 2539 | if (self.air.value(callee)) |func_value| { |
| 2509 | 2540 | if (func_value.castTag(.function)) |func_payload| { |
| 2510 | 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 | 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 | 2545 | // callq *%rax |
| 2517 | 2546 | _ = try self.addInst(.{ |
| ... | ... | @@ -3547,6 +3576,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3547 | 3576 | }, |
| 3548 | 3577 | .memory, |
| 3549 | 3578 | .embedded_in_code, |
| 3579 | .linker_sym_index, |
| 3550 | 3580 | => { |
| 3551 | 3581 | if (ty.abiSize(self.target.*) <= 8) { |
| 3552 | 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 | 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 | 4005 | .memory => |x| { |
| 3956 | | // TODO can we move this entire logic into Emit.zig like with aarch64? |
| 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)) { |
| 4006 | if (x <= math.maxInt(i32)) { |
| 3978 | 4007 | // mov reg, [ds:imm32] |
| 3979 | 4008 | _ = try self.addInst(.{ |
| 3980 | 4009 | .tag = .mov, |
| ... | ... | @@ -4285,9 +4314,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa |
| 4285 | 4314 | const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes; |
| 4286 | 4315 | return MCValue{ .memory = got_addr }; |
| 4287 | 4316 | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 4288 | | // TODO I'm hacking my way through here by repurposing .memory for storing |
| 4289 | | // index to the GOT target symbol index. |
| 4290 | | return MCValue{ .memory = decl.link.macho.local_sym_index }; |
| 4317 | // Because MachO is PIE-always-on, we defer memory address resolution until |
| 4318 | // the linker has enough info to perform relocations. |
| 4319 | return MCValue{ .linker_sym_index = decl.link.macho.local_sym_index }; |
| 4291 | 4320 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4292 | 4321 | const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; |
| 4293 | 4322 | return MCValue{ .memory = got_addr }; |