mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 02:24:33 +01:00
Prevent register clobbering on x86_64 threadlocal access
On the x86_64 self hosted backend, thread locals are accessed through __tls_get_addr on PIC. Usually this goes through a fast path which does not lose any registers, however in some cases (notably any dlopened library on my machine) this can take a slow path which calls out to C ABI functions Catch this case and backup registers as necessary Fix a few other ones while we're here. Credit to mlugg Fixes #30183
This commit is contained in:
parent
b9eefe17af
commit
fc78a61c4c
1 changed files with 32 additions and 4 deletions
|
|
@ -173048,11 +173048,39 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
|||
const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
|
||||
const nav = ip.getNav(ty_nav.nav);
|
||||
const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.isThreadlocal(ip);
|
||||
if (is_threadlocal) if (cg.target.ofmt == .coff or cg.mod.pic) {
|
||||
try cg.spillRegisters(&.{ .rdi, .rax });
|
||||
} else {
|
||||
try cg.spillRegisters(&.{.rax});
|
||||
|
||||
if (is_threadlocal) switch (cg.target.ofmt) {
|
||||
.elf => if (cg.mod.pic) {
|
||||
// LD model: `__tls_get_addr` uses the standard ABI
|
||||
try cg.spillEflagsIfOccupied();
|
||||
try cg.spillRegisters(abi.getCallerPreservedRegs(.x86_64_sysv));
|
||||
} else {
|
||||
// LE model: manual lowering uses these two registers
|
||||
try cg.spillRegisters(&.{ .rdi, .rax });
|
||||
},
|
||||
|
||||
.coff => {
|
||||
// manual lowering uses these registers
|
||||
try cg.spillRegisters(&.{ .rdi, .rax });
|
||||
},
|
||||
|
||||
.macho => switch (cg.target.cpu.arch) {
|
||||
.x86 => {
|
||||
// `tlv_get_addr` returns in eax, clobbers ecx, preserves other GPRs
|
||||
try cg.spillEflagsIfOccupied();
|
||||
try cg.spillRegisters(&.{ .rax, .rcx });
|
||||
},
|
||||
.x86_64 => {
|
||||
// `tlv_get_addr` returns in rax, preserves other GPRs
|
||||
try cg.spillEflagsIfOccupied();
|
||||
try cg.spillRegisters(&.{.rax});
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
var res = try cg.tempInit(.fromInterned(ty_nav.ty), .{ .lea_nav = ty_nav.nav });
|
||||
if (is_threadlocal) while (try res.toRegClass(true, .general_purpose, cg)) {};
|
||||
try res.finish(inst, &.{}, &.{}, cg);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue