On Thu, Sep 17, 2015 at 12:26 PM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Tue, Sep 15, 2015 at 1:11 PM, H.J. Lu <hjl.to...@gmail.com> wrote: >>> To implement interrupt and exception handlers for x86 processors, a >>> compiler should support: >>> >>> 1. void * __builtin_ia32_interrupt_data (void) >> >> I got a feedback on the name of this builtin function. Since >> it also works for 64-bit, we should avoid ia32 in its name. >> We'd like to change it to >> >> void * __builtin_interrupt_data (void) >> > > Here is the updated spec. >
This updated spec adds unsigned int __builtin_exception_error (void) unsigned long long int __builtin_exception_error (void) This function returns the exception error code pushed onto the stack by processor. Its return value is 64 bits in 64-bit mode and 32 bits in 32-bit mode. This function can only be used in exception handler. It also changes the definition of void * __builtin_interrupt_data (void) so that it returns a pointer to the data layout pushed onto stack by processor for both interrupt and exception handlers. -- H.J. --- The interrupt and exception handlers are called by x86 processors. X86 hardware pushes information onto stack and calls the handler. The requirements are 1. Both interrupt and exception handlers must use the 'IRET' instruction, instead of the 'RET' instruction, to return from the handlers. 2. All registers are callee-saved in interrupt and exception handlers. 3. The difference between interrupt and exception handlers is the exception handler must pop 'ERROR_CODE' off the stack before the 'IRET' instruction. The design goals of interrupt and exception handlers for x86 processors are: 1. No new calling convention in compiler. 2. Support both 32-bit and 64-bit modes. 3. Flexible for compilers to optimize. 4. Easy to use by programmers. To implement interrupt and exception handlers for x86 processors, a compiler should support: 1. void * __builtin_interrupt_data (void) This function returns a pointer to the return address pushed onto the stack by processor. The __builtin_frame_address builtin isn't suitable for interrupt and exception handlers since it returns the stack frame address on the callee side and compiler may generate a new stack frame for stack alignment. 2. unsigned int __builtin_exception_error (void) unsigned long long int __builtin_exception_error (void) This function returns the exception error code pushed onto the stack by processor. Its return value is 64 bits in 64-bit mode and 32 bits in 32-bit mode. This function can only be used in exception handler. 3. 'interrupt' attribute Use this attribute to indicate that the specified void function without arguments is an interrupt handler. The compiler generates function entry and exit sequences suitable for use in an interrupt handler when this attribute is present. The 'IRET' instruction, instead of the 'RET' instruction, is used to return from interrupt handlers. All registers, except for the EFLAGS register which is restored by the 'IRET' instruction, are preserved by the compiler. The red zone isn't supported in the interrupted function; that is an interrupt handler may access stack within 128 bytes of the current stack pointer. You can use the builtin '__builtin_interrupt_data' function to access the interrupt data pushed onto the stack by processor: void f () __attribute__ ((interrupt)) { void *p = __builtin_interrupt_data (); ... } 4. 'exception' attribute Use 'exception' instead of 'interrupt' for handlers intended to be used for 'exception' (i.e. those that must pop 'ERROR_CODE' off the stack before the 'IRET' instruction). You can use the builtin '__builtin_exception_error' function to access the exception error code pushed onto the stack by processor as well as the builtin '__builtin_interrupt_data' function to access the exception data on stack: void f () __attribute__ ((exception)) { unsigned int error = __builtin_exception_error (); void *p = __builtin_interrupt_data (); ... }