authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-05 19:09:20+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-06 00:34:24+01:00
logf132f426b9a11774323eafc669da0c9731deb85b
tree7c00096b199fc33087c0c0bfbda0d684cf38c30b
parent4b3b487627d71fa082b0316383344b49c95bab0e

x86_64: add distinct MCValue representing symbol index in the linker

For PIE targets, we defer getting an address of value until the linker has allocated all atoms and performed the relocations. In codegen, we represent this via `MCValue.linker_sym_index` value.

1 files changed, 76 insertions(+), 47 deletions(-)

src/arch/x86_64/CodeGen.zig+76-47
......@@ -118,6 +118,10 @@ pub const MCValue = union(enum) {
118118 /// The value is in memory at a hard-coded address.
119119 /// If the type is a pointer, it means the pointer address is at this memory location.
120120 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,
121125 /// The value is one of the stack variables.
122126 /// If the type is a pointer, it means the pointer address is in the stack at this offset.
123127 stack_offset: i32,
......@@ -1686,8 +1690,10 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
16861690 else => return self.fail("TODO implement loading from register into {}", .{dst_mcv}),
16871691 }
16881692 },
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);
16911697 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
16921698 },
16931699 .stack_offset => {
......@@ -1817,27 +1823,33 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
18171823 },
18181824 }
18191825 },
1820 .memory => |addr| {
1826 .linker_sym_index,
1827 .memory,
1828 => {
18211829 value.freezeIfRegister(&self.register_manager);
18221830 defer value.unfreezeIfRegister(&self.register_manager);
18231831
18241832 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,
18411853 }
18421854 };
18431855
......@@ -2148,6 +2160,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
21482160 .embedded_in_code, .memory => {
21492161 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
21502162 },
2163 .linker_sym_index => {
2164 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
2165 },
21512166 .stack_offset => |off| {
21522167 if (off > math.maxInt(i32)) {
21532168 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
22322247 .embedded_in_code, .memory, .stack_offset => {
22332248 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
22342249 },
2250 .linker_sym_index => {
2251 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});
2252 },
22352253 .compare_flags_unsigned => {
22362254 return self.fail("TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
22372255 },
......@@ -2243,6 +2261,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
22432261 .embedded_in_code, .memory => {
22442262 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});
22452263 },
2264 .linker_sym_index => {
2265 return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{});
2266 },
22462267 }
22472268}
22482269
......@@ -2296,6 +2317,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
22962317 .embedded_in_code, .memory, .stack_offset => {
22972318 return self.fail("TODO implement x86 multiply source memory", .{});
22982319 },
2320 .linker_sym_index => {
2321 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
2322 },
22992323 .compare_flags_unsigned => {
23002324 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});
23012325 },
......@@ -2334,6 +2358,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
23342358 .embedded_in_code, .memory, .stack_offset => {
23352359 return self.fail("TODO implement x86 multiply source memory", .{});
23362360 },
2361 .linker_sym_index => {
2362 return self.fail("TODO implement x86 multiply source symbol at index in linker", .{});
2363 },
23372364 .compare_flags_unsigned => {
23382365 return self.fail("TODO implement x86 multiply source compare flag (unsigned)", .{});
23392366 },
......@@ -2345,6 +2372,9 @@ fn genIMulOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !
23452372 .embedded_in_code, .memory => {
23462373 return self.fail("TODO implement x86 multiply destination memory", .{});
23472374 },
2375 .linker_sym_index => {
2376 return self.fail("TODO implement x86 multiply destination symbol at index in linker", .{});
2377 },
23482378 }
23492379}
23502380
......@@ -2448,6 +2478,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
24482478 .dead => unreachable,
24492479 .embedded_in_code => unreachable,
24502480 .memory => unreachable,
2481 .linker_sym_index => unreachable,
24512482 .compare_flags_signed => unreachable,
24522483 .compare_flags_unsigned => unreachable,
24532484 }
......@@ -2508,10 +2539,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
25082539 if (self.air.value(callee)) |func_value| {
25092540 if (func_value.castTag(.function)) |func_payload| {
25102541 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.
25132542 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,
25152544 });
25162545 // callq *%rax
25172546 _ = try self.addInst(.{
......@@ -3547,6 +3576,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
35473576 },
35483577 .memory,
35493578 .embedded_in_code,
3579 .linker_sym_index,
35503580 => {
35513581 if (ty.abiSize(self.target.*) <= 8) {
35523582 const reg = try self.copyToTmpRegister(ty, mcv);
......@@ -3952,29 +3982,28 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
39523982 .data = undefined,
39533983 });
39543984 },
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 },
39554005 .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)) {
39784007 // mov reg, [ds:imm32]
39794008 _ = try self.addInst(.{
39804009 .tag = .mov,
......@@ -4285,9 +4314,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
42854314 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
42864315 return MCValue{ .memory = got_addr };
42874316 } 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 };
42914320 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
42924321 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
42934322 return MCValue{ .memory = got_addr };