[LLVMdev] One way to support unwind on x86

Bjarke Walling bwp at bwp.dk
Mon Mar 2 18:40:17 PST 2009


Hi,

I want to support the unwind instruction on x86. Specifically I want to:

 *  Provide an efficient runtime implementation that does not
    depend on reading the DWARF EH information.
 *  It should be self hosted, meaning the runtime is static
    linked in. I want to use it kernel mode.
 *  Unwinding should be a read-only operation regarding the
    stack, so I can create a stack dump in the landing pad.
 *  Provide a pass that raises C++ exception handling to just
    unwind instructions and thread-local data.

My idea on handling the DWARF EH actions is to compile it to machine
instructions. Fx. given an Instruction Pointer, unwinding a call frame
might be described as:

    add  esp, 12 ; Remove the current call frame.
    jmp  unwind  ; Continue the unwinding process.

Other call frames might be more complex to handle. It depends on the
moves needed to restore the registers of the previous call frame (the
caller) and to remove the current frame.

I want to tag all calls and invokes in a manner that can be easily
recognized by a runtime. I can tolerate a small overhead on calls. The
idea is to do something like this:

      call  some_function
      jmp   continue
      jmp   case_of_unwinding
    continue:

The case-of-unwinding will either unwind the current call frame or
jump to the landing pad (if it was an invoke instruction). I think the
overhead will in fact be quite small because of branch prediction on
modern processors. The size overhead by tagging all calls, compared to
only tagging unwind areas and actions in DWARF, does not matter much
to me.

On x86 a call stores the next Instruction Pointer address on the
stack. The runtime would be something like this (assuming the first
jmp instruction after the call is always short):

    unwind:
      ; We are on a call frame boundary. Assuming we can
      ; always destroy the content of EAX (true for C calling
      ; convention), we get the next Instruction Pointer (the
      ; instruction after the call):
      pop  eax
      ; We advance our virtual Instruction Pointer to after
      ; the first jmp. Here we assume it is a two-byte
      ; encoded short jmp, but in practice we can support
      ; both short and long jmps:
      inc  eax
      inc  eax
      ; Then we invoke the local unwind handling. It will
      ; in turn either unwind another call frame or jump to
      ; the landing pad:
      jmp  eax

The pass to raise C++ exceptions to use unwind is another discussion.
The most valuable thing for me is to support unwind.

What do you think about the idea?
Can it be achieved or did I overlook something important?

I guess it should be implemented as a few passes. I think the one that
inserts code after each call machine instruction is the most difficult
to implement. Is it even possible to insert jmp instructions without
them being optimized away? I also need to access information about the
call frame.

My last question: Is it possible to implement a flag for the back-end
that selects which kind of exception handling to use? Ie. my idea
versus DWARF + libgcc.

Cheers,
Bjarke Walling



More information about the llvm-dev mailing list