Tracking issue for the x86-interrupt
calling convention, which was added in PR #39832. The feature gate name is abi_x86_interrupt
. This feature will not be considered for stabilization without an RFC.
The x86-interrupt
calling convention can be used for defining interrupt handlers on 32-bit and 64-bit x86 targets. The compiler then uses iret
instead of ret
for returning and ensures that all registers are restored to their original values.
extern "x86-interrupt" fn handler(stack_frame: &ExceptionStackFrame) {鈥
for interrupts and exceptions without error code and
extern "x86-interrupt" fn handler_with_err_code(stack_frame: &ExceptionStackFrame,
error_code: u64) {鈥
for exceptions that push an error code (e.g., page faults or general protection faults). The programmer must ensure that the correct version is used for each interrupt.
For more details see the LLVM PR, and the corresponding proposal.
~The x86_64 automatically aligns the stack on a 16-byte boundary when an interrupts occurs in 64-bit mode. However, the CPU pushes an 8-byte error code for some exceptions, which destroys the 16-byte alignment. At the moment, LLVM doesn't handle this case correctly and always assumes a 16-byte alignment. This leads to alignment issues on targets with SSE support, since LLVM uses misaligned movaps
instructions for saving the xmm
registers. This issue is tracked as bug 26413.~ A fix for this problem is submitted in D30049 and merged in rL299383.
~LLVM always tries to backup the xmm
registers on 64-bit platforms even if the target doesn't support SSE. This leads to invalid opcode exceptions whenever an interrupt handler is invoked.~ The fix was merged to LLVM trunk in rL295347. Backported in rust-lang/llvm#63.
and esp, 16
). However, LLVM doesn't do that at the moment, which might lead to alignment errors, especially for targets with SSE support. This issue is tracked in bug 26477.If we're going to have an x86-interrupt abi, would it also make sense to have an x86-syscall? Or x86-sysenter?
(D30049 was merged to LLVM trunk on the 3rd of April, for the record.)
@kyrias Thanks for the hint, I updated the issue text. I'll try to create a backport PR in the next few days.
Triage: not aware of any movement stabilizing this.
Personal note: this is one of my favorite rust features :)
Both of the 64-bit issues have long since been fixed, and Rust's minimum LLVM is newer than the fix, so it's just the MMX/x87 floating point and 32-bit issues remaining, which appear to have been untouched since 2017.
@kyrias I updated the issue description. I also added https://github.com/rust-lang/rust/issues/57270, which will be hopefully fixed soon with the LLVM 9 upgrade.
@phil-opp I think this issue can be updated to cross off #57270
On the x87/MMX issue, we should just mandate that to use the interrupt ABI, you have to build the code with target-features
of -x87
and -mmx
(-mmx
could be a default now that MMX support is gone from Rust). It looks like LLVM and GCC just never intend to support saving/restoring the MMX/x87 registers, so it's probably not worth trying to make it work (as nobody should be using those features anyway.
We may also want to similarly disallow all SSE code in interrupt handlers (GCC bans SSE code, Clang allows it), as that might make it easier to make sure we are doing the right thing.
@phil-opp I think this issue can be updated to cross off #57270
Done!
Just came across the following from a conference paper, and thought I would quote here as a data point:
We implement the low-level interrupt entry and exit code in assembly. While Rust provides support for the x86-interrupt function ABI (a way to write a Rust function that takes the x86 interrupt stack frame as an argument), in practice, it is not useful as we need the ability to interpose on the entry and exit from the interrupt, for example, to save all CPU registers.
(section 4.1 of https://www.usenix.org/system/files/osdi20-narayanan_vikram.pdf)
Most helpful comment
If we're going to have an x86-interrupt abi, would it also make sense to have an x86-syscall? Or x86-sysenter?