Closed AmberCrafter closed 2 years ago
RFC mention x86-interrupt
was clobbered rax
.
Is that mean we need to use other register to pass the syscall's number? More over, should we need to consider other registers are callee-save registers or define them by myself?
AFAICT there are no guarantees about the contents of registers once the function has been entered. If you want to inspect/modify registers you could use the #[naked]
attribute on a function and implement the calling convention yourself.
@Freax13 Thanks for your suggestion. In these days, I trace the asm code of different kind x86-inerrupt function, and found the interesting behavior:
If we use the InterruptStackFrame, the asm code like below, which will overwrite the rax
however, if we unuse the InterruptStackFrame, it looks like this, which will not overwrite the rax
.
On the other hand, @xfoxfu (repo.) provides a good solution to do the type wrapping (extern "C" -> extern "x86-interrupt") which has already perplexed me for a long time.
however, if we unuse the InterruptStackFrame, it looks like this, which will not overwrite the
rax
.
There's no guarantee that this will always be the case. This might work for now, but can (and most certainly will) break at any time in the future.
On the other hand, @xfoxfu (repo.) provides a good solution to do the type wrapping (extern "C" -> extern "x86-interrupt") which has already perplexed me for a long time.
The thing that makes this work is their wrap!
macro which generates a naked function that pushes the registers onto the stack and prepares the registers for calling a function with the C abi before calling the wrapped function.
I think they could use the x86-interrupt
calling convention for their generated function and then they wouldn't have to transmute the function when setting the entry.
however, if we unuse the InterruptStackFrame, it looks like this, which will not overwrite the
rax
.There's no guarantee that this will always be the case. This might work for now, but can (and most certainly will) break at any time in the future.
@Freax13 Your right! I can't ensure these behaviors.
On the other hand, @xfoxfu (repo.) provides a good solution to do the type wrapping (extern "C" -> extern "x86-interrupt") which has already perplexed me for a long time.
The thing that makes this work is their
wrap!
macro which generates a naked function that pushes the registers onto the stack and prepares the registers for calling a function with the C abi before calling the wrapped function.I think they could use the
x86-interrupt
calling convention for their generated function and then they wouldn't have to transmute the function when setting the entry.
I think you mean like this
// idt setting
idt[0x80].set_handler_fn(syscall_handler_naked_wrap);
// handler function
#[naked]
pub extern "x86-interrupt" fn syscall_handler_naked_wrap(stack_frame: InterruptStackFrame) {
unsafe {
core::arch::asm!(
"
push rbp
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rsi, rsp // second arg: register list
mov rdi, rsp
add rdi, 15*8 // first arg: interrupt frame
call {}
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
pop rbp
iretq
",
sym syscall_handler_naked,
options(noreturn)
);
}
}
pub extern "C" fn syscall_handler_naked(sf: &mut InterruptStackFrame, regs: &mut Registers) {
// something i want to do...
serial_println!(
"
rax: {:?}\n
rdi: {:?}\n
rsi: {:?}\n
rdx: {:?}
",
regs.rax,
regs.rdi,
regs.rsi,
regs.rdx
);
serial_println!("{:?}", sf);
serial_println!("syscall finished!");
}
and it work for me. Hurray!!
I would like to implment the software interrupt on idt[0x80] ( likes linux's syscall ), but I've run into a calling convention problem:
eax
will be overwrited whenextern "x86-interrupt" fn foo {}
is executed. Is this the feature of thex86-interrupt
? Or am I missing anything? And where can I found the doucuments aboutx86-interrupt
?