diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-10-17 17:36:40 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-17 17:36:40 +0200 |
| commit | eb5276c94eaab238551fdae9a2e77b0133e31cfb (patch) | |
| tree | a8040cc914bb1db73b2484087cf81d5f20bab28c /src/arch/x86_64/CodeGen.zig | |
| parent | 5039a5db8365413794b0522a51137d3e97d8ba5d (diff) | |
| parent | 742a130ce55ae776372f99b0724c32a462040caf (diff) | |
| download | zig-eb5276c94eaab238551fdae9a2e77b0133e31cfb.tar.gz zig-eb5276c94eaab238551fdae9a2e77b0133e31cfb.zip | |
Merge pull request #17556 from ziglang/elf-link-zig-proper
elf: port 99% of zld ELF linker to Zig proper
Diffstat (limited to 'src/arch/x86_64/CodeGen.zig')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 186 |
1 files changed, 129 insertions, 57 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 2b13689765..59d54bd04f 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -207,6 +207,12 @@ pub const MCValue = union(enum) { /// The value is a pointer to a value referenced indirectly via GOT. /// Payload is a symbol index. lea_got: u32, + /// The value is an extern variable referenced via GOT. + /// Payload is a symbol index. + load_extern_got: u32, + /// The value is a pointer to an extern variable referenced via GOT. + /// Payload is a symbol index. + lea_extern_got: u32, /// The value is a threadlocal variable. /// Payload is a symbol index. load_tlv: u32, @@ -295,6 +301,7 @@ pub const MCValue = union(enum) { .register_overflow, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, .reserved_frame, @@ -308,6 +315,7 @@ pub const MCValue = union(enum) { .load_direct => |sym_index| .{ .lea_direct = sym_index }, .load_got => |sym_index| .{ .lea_got = sym_index }, .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, + .load_extern_got => |sym_index| .{ .lea_extern_got = sym_index }, .load_frame => |frame_addr| .{ .lea_frame = frame_addr }, }; } @@ -325,6 +333,7 @@ pub const MCValue = union(enum) { .indirect, .load_direct, .load_got, + .load_extern_got, .load_tlv, .load_frame, .reserved_frame, @@ -335,6 +344,7 @@ pub const MCValue = union(enum) { .register_offset => |reg_off| .{ .indirect = reg_off }, .lea_direct => |sym_index| .{ .load_direct = sym_index }, .lea_got => |sym_index| .{ .load_got = sym_index }, + .lea_extern_got => |sym_index| .{ .load_extern_got = sym_index }, .lea_tlv => |sym_index| .{ .load_tlv = sym_index }, .lea_frame => |frame_addr| .{ .load_frame = frame_addr }, }; @@ -358,6 +368,8 @@ pub const MCValue = union(enum) { .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .load_frame, @@ -392,6 +404,8 @@ pub const MCValue = union(enum) { .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .lea_frame, @@ -434,6 +448,8 @@ pub const MCValue = union(enum) { .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), .load_got => |pl| try writer.print("[got:{d}]", .{pl}), .lea_got => |pl| try writer.print("got:{d}", .{pl}), + .load_extern_got => |pl| try writer.print("[extern_got:{d}]", .{pl}), + .lea_extern_got => |pl| try writer.print("extern_got:{d}", .{pl}), .load_tlv => |pl| try writer.print("[tlv:{d}]", .{pl}), .lea_tlv => |pl| try writer.print("tlv:{d}", .{pl}), .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }), @@ -461,6 +477,8 @@ const InstTracking = struct { .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .load_frame, @@ -520,6 +538,8 @@ const InstTracking = struct { .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .load_frame, @@ -555,6 +575,8 @@ const InstTracking = struct { .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .lea_frame, @@ -4371,6 +4393,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { .memory, .load_direct, .load_got, + .load_extern_got, .load_tlv, => try self.genSetReg(addr_reg, Type.usize, array.address()), .lea_direct, .lea_tlv => unreachable, @@ -5851,6 +5874,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro .register_offset, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()), @@ -5858,6 +5882,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro .indirect, .load_direct, .load_got, + .load_extern_got, .load_tlv, .load_frame, => { @@ -5996,6 +6021,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr .register_offset, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv), @@ -6003,6 +6029,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr .indirect, .load_direct, .load_got, + .load_extern_got, .load_tlv, .load_frame, => { @@ -6424,6 +6451,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC .register_overflow, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, .reserved_frame, @@ -6431,7 +6459,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC => unreachable, // unmodifiable destination .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), .register_pair => unreachable, // unimplemented - .memory, .load_got, .load_direct, .load_tlv => { + .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => { const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_reg_lock); @@ -7389,6 +7417,8 @@ fn genBinOp( .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .lea_frame, @@ -7445,6 +7475,8 @@ fn genBinOp( .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .lea_frame, @@ -8397,6 +8429,7 @@ fn genBinOpMir( .register_overflow, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, .reserved_frame, @@ -8485,6 +8518,8 @@ fn genBinOpMir( .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .load_frame, @@ -8517,6 +8552,7 @@ fn genBinOpMir( .register_offset, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, => { @@ -8532,6 +8568,7 @@ fn genBinOpMir( .memory, .load_direct, .load_got, + .load_extern_got, .load_tlv, => { const ptr_ty = try mod.singleConstPtrType(ty); @@ -8552,13 +8589,13 @@ fn genBinOpMir( } } }, - .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { + .memory, .indirect, .load_got, .load_extern_got, .load_direct, .load_tlv, .load_frame => { const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock }; const limb_abi_size: u32 = @min(abi_size, 8); const dst_info: OpInfo = switch (dst_mcv) { else => unreachable, - .memory, .load_got, .load_direct, .load_tlv => dst: { + .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => dst: { const dst_addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); @@ -8592,16 +8629,17 @@ fn genBinOpMir( .indirect, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .load_frame, .lea_frame, => null, - .memory, .load_got, .load_direct, .load_tlv => src: { + .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => src: { switch (resolved_src_mcv) { .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr))) != null and math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null) break :src null, - .load_got, .load_direct, .load_tlv => {}, + .load_got, .load_extern_got, .load_direct, .load_tlv => {}, else => unreachable, } @@ -8644,6 +8682,7 @@ fn genBinOpMir( switch (dst_mcv) { .memory, .load_got, + .load_extern_got, .load_direct, .load_tlv, => .{ .base = .{ .reg = dst_info.?.addr_reg }, .disp = off }, @@ -8728,6 +8767,8 @@ fn genBinOpMir( .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .load_frame, @@ -8743,6 +8784,7 @@ fn genBinOpMir( .register_offset, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, => switch (limb_i) { @@ -8792,6 +8834,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M .register_overflow, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, .reserved_frame, @@ -8840,6 +8883,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .lea_frame, @@ -8878,7 +8923,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M } }, .register_pair => unreachable, // unimplemented - .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => { + .memory, .indirect, .load_direct, .load_got, .load_extern_got, .load_tlv, .load_frame => { const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); const tmp_mcv = MCValue{ .register = tmp_reg }; const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); @@ -8971,6 +9016,7 @@ fn genVarDbgInfo( //} }, .memory => |address| .{ .memory = address }, .load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } }, + .load_extern_got => |sym_index| .{ .linker_load = .{ .type = .extern_got, .sym_index = sym_index } }, .load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } }, .immediate => |x| .{ .immediate = x }, .undef => .undef, @@ -9189,16 +9235,20 @@ fn genCall(self: *Self, info: union(enum) { if (self.bin_file.cast(link.File.Elf)) |elf_file| { const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl); const sym = elf_file.symbol(sym_index); - sym.flags.needs_got = true; - _ = try sym.getOrCreateGotEntry(sym_index, elf_file); - _ = try self.addInst(.{ - .tag = .call, - .ops = .direct_got_reloc, - .data = .{ .reloc = .{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym.esym_index, - } }, - }); + _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); + if (self.bin_file.options.pic) { + try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym.esym_index }); + try self.asmRegister(.{ ._, .call }, .rax); + } else { + _ = try self.addInst(.{ + .tag = .call, + .ops = .direct_got_reloc, + .data = .{ .reloc = .{ + .atom_index = try self.owner.getSymbolIndex(self), + .sym_index = sym.esym_index, + } }, + }); + } } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { const atom = try coff_file.getOrCreateAtomForDecl(owner_decl); const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; @@ -9406,13 +9456,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { .indirect, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, .reserved_frame, .air_ref, => unreachable, .register_pair, .load_frame => null, - .memory, .load_got, .load_direct, .load_tlv => dst: { + .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => dst: { switch (resolved_dst_mcv) { .memory => |addr| if (math.cast( i32, @@ -9421,7 +9472,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { i32, @as(i64, @bitCast(addr)) + abi_size - 8, ) != null) break :dst null, - .load_got, .load_direct, .load_tlv => {}, + .load_got, .load_extern_got, .load_direct, .load_tlv => {}, else => unreachable, } @@ -9464,13 +9515,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { .indirect, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, .reserved_frame, .air_ref, => unreachable, .register_pair, .load_frame => null, - .memory, .load_got, .load_direct, .load_tlv => src: { + .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => src: { switch (resolved_src_mcv) { .memory => |addr| if (math.cast( i32, @@ -9479,7 +9531,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { i32, @as(i64, @bitCast(addr)) + abi_size - 8, ) != null) break :src null, - .load_got, .load_direct, .load_tlv => {}, + .load_got, .load_extern_got, .load_direct, .load_tlv => {}, else => unreachable, } @@ -9898,6 +9950,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC .register_overflow, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, .reserved_frame, @@ -9924,6 +9977,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC .memory, .load_got, + .load_extern_got, .load_direct, .load_tlv, => { @@ -10481,7 +10535,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_| break :arg input_mcv, .indirect, .load_frame => break :arg input_mcv, - .load_direct, .load_got, .load_tlv => {}, + .load_direct, .load_got, .load_extern_got, .load_tlv => {}, else => { const temp_mcv = try self.allocTempRegOrMem(ty, false); try self.genCopy(ty, temp_mcv, input_mcv); @@ -11142,6 +11196,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError .register_overflow, .lea_direct, .lea_got, + .lea_extern_got, .lea_tlv, .lea_frame, .reserved_frame, @@ -11193,11 +11248,11 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError } }, .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv), - .memory, .load_direct, .load_got, .load_tlv => { + .memory, .load_direct, .load_got, .load_extern_got, .load_tlv => { switch (dst_mcv) { .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv), - .load_direct, .load_got, .load_tlv => {}, + .load_direct, .load_got, .load_extern_got, .load_tlv => {}, else => unreachable, } @@ -11359,7 +11414,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr else => unreachable, }, )), - .memory, .load_direct, .load_got, .load_tlv => { + .memory, .load_direct, .load_got, .load_extern_got, .load_tlv => { switch (src_mcv) { .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| return (try self.moveStrategy( @@ -11387,7 +11442,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr }, .Float, .Vector => {}, }, - .load_got, .load_tlv => {}, + .load_got, .load_extern_got, .load_tlv => {}, else => unreachable, } @@ -11401,17 +11456,18 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .{ .reg = addr_reg } }), ); }, - .lea_direct, .lea_got => |sym_index| { + .lea_direct, .lea_got, .lea_extern_got => |sym_index| { const atom_index = try self.owner.getSymbolIndex(self); _ = try self.addInst(.{ .tag = switch (src_mcv) { .lea_direct => .lea, - .lea_got => .mov, + .lea_got, .lea_extern_got => .mov, else => unreachable, }, .ops = switch (src_mcv) { .lea_direct => .direct_reloc, .lea_got => .got_reloc, + .lea_extern_got => .extern_got_reloc, else => unreachable, }, .data = .{ .rx = .{ @@ -11547,6 +11603,8 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal .lea_direct, .load_got, .lea_got, + .load_extern_got, + .lea_extern_got, .load_tlv, .lea_tlv, .load_frame, @@ -11637,36 +11695,49 @@ fn genLazySymbolRef( const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym = elf_file.symbol(sym_index); - sym.flags.needs_got = true; - _ = try sym.getOrCreateGotEntry(sym_index, elf_file); - const reloc = Mir.Reloc{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym.esym_index, - }; - switch (tag) { - .lea, .mov => _ = try self.addInst(.{ - .tag = .mov, - .ops = .direct_got_reloc, - .data = .{ .rx = .{ - .r1 = reg.to64(), - .payload = try self.addExtra(reloc), - } }, - }), - .call => _ = try self.addInst(.{ - .tag = .call, - .ops = .direct_got_reloc, - .data = .{ .reloc = reloc }, - }), - else => unreachable, - } - switch (tag) { - .lea, .call => {}, - .mov => try self.asmRegisterMemory( - .{ ._, tag }, - reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), - ), - else => unreachable, + _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); + + if (self.bin_file.options.pic) { + switch (tag) { + .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym.esym_index }), + .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym.esym_index }), + else => unreachable, + } + switch (tag) { + .lea, .mov => {}, + .call => try self.asmRegister(.{ ._, .call }, reg), + else => unreachable, + } + } else { + const reloc = Mir.Reloc{ + .atom_index = try self.owner.getSymbolIndex(self), + .sym_index = sym.esym_index, + }; + switch (tag) { + .lea, .mov => _ = try self.addInst(.{ + .tag = .mov, + .ops = .direct_got_reloc, + .data = .{ .rx = .{ + .r1 = reg.to64(), + .payload = try self.addExtra(reloc), + } }, + }), + .call => _ = try self.addInst(.{ + .tag = .call, + .ops = .direct_got_reloc, + .data = .{ .reloc = reloc }, + }), + else => unreachable, + } + switch (tag) { + .lea, .call => {}, + .mov => try self.asmRegisterMemory( + .{ ._, tag }, + reg.to64(), + Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), + ), + else => unreachable, + } } } else if (self.bin_file.cast(link.File.Plan9)) |p9_file| { const atom_index = p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| @@ -13539,6 +13610,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { .memory => |addr| .{ .memory = addr }, .load_direct => |sym_index| .{ .load_direct = sym_index }, .load_got => |sym_index| .{ .lea_got = sym_index }, + .load_extern_got => |sym_index| .{ .lea_extern_got = sym_index }, .load_tlv => |sym_index| .{ .lea_tlv = sym_index }, }, .fail => |msg| { |
