Do I have to leave the error code on the stack for exceptions that put the error code there?
As others mentioned, you have to do either:
pop %eax
/* Do something with %eax */
iret
Or if you want to ignore the error code:
add $4, %esp
iret
If you don't, iret
will interpret the error code as the new CS, and you are likely to get a general protection fault as mentioned at: Why does iret from a page fault handler generate interrupt 13 (general protection fault) and error code 0x18?
Minimal Working this page handler that I've created to illustrate this. Try commenting out the pop
and see it blow up.
Compare the above with a Division error exception which does not to pop the stack.
Note that if you do simply int $14
, no extra byte gets pushed: this only happens on the actual exception.
Intel Manual Volume 3 System Programming Guide - 325384-056US September 2015 Table 6-1. "Protected-Mode Exceptions and Interrupts" column "Error Code" contains the list of interrupts that push the error code or not.
38.9.2.2 "Page Fault Error Codes" explains what the error means.
A neat way to deal with this is to push a dummy error code 0
on the stack for the interrupts that don't do this to make things uniform. James Molloy's tutorial does exactly that.
The Linux kernel 4.2 seems to do something similar. Under arch/x86/entry/entry64.S it models interrupts with has_error_code
:
trace_idtentry page_fault do_page_fault has_error_code=1
and then uses it on the same file as:
.ifeq \has_error_code
pushq $-1 /* ORIG_RAX: no syscall to restart */
.endif
which does the push when has_error_code=0
.