linux: add getcontext for x86_64

This commit is contained in:
kcbanner 2023-06-26 00:57:28 -04:00
parent 6abf1fbfe6
commit 41832aa1e6
2 changed files with 70 additions and 1 deletions

View File

@ -86,6 +86,7 @@ pub const timeval = arch_bits.timeval;
pub const timezone = arch_bits.timezone; pub const timezone = arch_bits.timezone;
pub const ucontext_t = arch_bits.ucontext_t; pub const ucontext_t = arch_bits.ucontext_t;
pub const user_desc = arch_bits.user_desc; pub const user_desc = arch_bits.user_desc;
pub const getcontext = arch_bits.getcontext;
pub const tls = @import("linux/tls.zig"); pub const tls = @import("linux/tls.zig");
pub const pie = @import("linux/start_pie.zig"); pub const pie = @import("linux/start_pie.zig");
@ -4694,7 +4695,7 @@ else
/// processes. /// processes.
RTPRIO, RTPRIO,
/// Maximum CPU time in µs that a process scheduled under a real-time /// Maximum CPU time in µs that a process scheduled under a real-time
/// scheduling policy may consume without making a blocking system /// scheduling policy may consume without making a blocking system
/// call before being forcibly descheduled. /// call before being forcibly descheduled.
RTTIME, RTTIME,

View File

@ -395,3 +395,71 @@ pub const ucontext_t = extern struct {
sigmask: sigset_t, sigmask: sigset_t,
fpregs_mem: [64]usize, fpregs_mem: [64]usize,
}; };
fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index;
}
pub inline fn getcontext(context: *ucontext_t) usize {
asm volatile (
\\ movq %%r8, (%[r8_offset])(%[context])
\\ movq %%r9, (%[r9_offset])(%[context])
\\ movq %%r10, (%[r10_offset])(%[context])
\\ movq %%r11, (%[r11_offset])(%[context])
\\ movq %%r12, (%[r12_offset])(%[context])
\\ movq %%r13, (%[r13_offset])(%[context])
\\ movq %%r14, (%[r14_offset])(%[context])
\\ movq %%r15, (%[r15_offset])(%[context])
\\ movq %%rdi, (%[rdi_offset])(%[context])
\\ movq %%rsi, (%[rsi_offset])(%[context])
\\ movq %%rbp, (%[rbp_offset])(%[context])
\\ movq %%rbx, (%[rbx_offset])(%[context])
\\ movq %%rdx, (%[rdx_offset])(%[context])
\\ movq %%rax, (%[rax_offset])(%[context])
\\ movq %%rcx, (%[rcx_offset])(%[context])
\\ movq %%rsp, (%[rsp_offset])(%[context])
\\ leaq (%%rip), %%rcx
\\ movq %%rcx, (%[rip_offset])(%[context])
\\ pushfq
\\ popq (%[efl_offset])(%[context])
\\ leaq (%[fpmem_offset])(%[context]), %%rcx
\\ movq %%rcx, (%[fpstate_offset])(%[context])
\\ fnstenv (%%rcx)
\\ stmxcsr (%[mxcsr_offset])(%[context])
:
: [context] "{rdi}" (context),
[r8_offset] "p" (comptime gpRegisterOffset(REG.R8)),
[r9_offset] "p" (comptime gpRegisterOffset(REG.R9)),
[r10_offset] "p" (comptime gpRegisterOffset(REG.R10)),
[r11_offset] "p" (comptime gpRegisterOffset(REG.R11)),
[r12_offset] "p" (comptime gpRegisterOffset(REG.R12)),
[r13_offset] "p" (comptime gpRegisterOffset(REG.R13)),
[r14_offset] "p" (comptime gpRegisterOffset(REG.R14)),
[r15_offset] "p" (comptime gpRegisterOffset(REG.R15)),
[rdi_offset] "p" (comptime gpRegisterOffset(REG.RDI)),
[rsi_offset] "p" (comptime gpRegisterOffset(REG.RSI)),
[rbp_offset] "p" (comptime gpRegisterOffset(REG.RBP)),
[rbx_offset] "p" (comptime gpRegisterOffset(REG.RBX)),
[rdx_offset] "p" (comptime gpRegisterOffset(REG.RDX)),
[rax_offset] "p" (comptime gpRegisterOffset(REG.RAX)),
[rcx_offset] "p" (comptime gpRegisterOffset(REG.RCX)),
[rsp_offset] "p" (comptime gpRegisterOffset(REG.RSP)),
[rip_offset] "p" (comptime gpRegisterOffset(REG.RIP)),
[efl_offset] "p" (comptime gpRegisterOffset(REG.EFL)),
[fpstate_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")),
[fpmem_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem")),
[mxcsr_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")),
: "memory", "rcx"
);
// TODO: Read GS/FS registers?
// TODO: `flags` isn't present in the getcontext man page, figure out what to write here
context.flags = 0;
context.link = null;
const altstack_result = linux.sigaltstack(null, &context.stack);
if (altstack_result != 0) return altstack_result;
return linux.sigprocmask(0, null, &context.sigmask);
}