[cfe-dev] RFC: Support x86 interrupt and exception handlers

H.J. Lu via cfe-dev cfe-dev at lists.llvm.org
Mon Sep 21 09:27:18 PDT 2015


On Thu, Sep 17, 2015 at 12:26 PM, H.J. Lu <hjl.tools at gmail.com> wrote:
> On Tue, Sep 15, 2015 at 1:11 PM, H.J. Lu <hjl.tools at 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 ();
  ...
}



More information about the cfe-dev mailing list