Let's say I have a function that looks like this:

void a()
{
   int n = x();

   __try
   {
       y();
   }
   __finally
   {
       z(n);
       w();
   }
}

... assuming a hypothetical extension to C syntax that turns a __try {
... } __finally { ... } into the proper TRY_FINALLY_EXPR (maybe just a
matter of adapting the equivalent ObjectiveC keyword...?). As per
Unwind ABI, it gets compiled to something like this:

void a()
{
   int n = x();

   y();
   z(n);
   w();

cleanup:
   z(n);
   w();
   Unwind_Resume(...);
}

But I need it to compile to something quite different:

void __a_cleanup(<<frame pointer>>)
{
   z(<<frame>>.n);
   w();
}

void a()
{
   int n = x();
   y();
   __a_cleanup(<<frame pointer>>);
}

This is not a cosmetic matter: I'm developing a new exception handling
scheme for GCC, compatible with native Windows exceptions (henceforth:
SEH), where unwinding doesn't lower the stack at each frame unwound
relying on cleanup code to call Unwind_Resume, but instead calls all
cleanup code in a loop, from a stack frame *above* where the exception
was thrown.

Specifically, the frame that catches an exception is tasked with
unwinding the stack from the throwing frame up to itself, calling the
standard function RtlUnwind, and after RtlUnwind is done, it's
supposed to longjmp to the landing pad on its own. It is an
unescapeable fact that __finally { ... } blocks need to be callable
out-of-band, with the "right" frame pointer but the "wrong" stack
pointer (the call stack is, approximately, <throw>,
RtlDispatchException, <language-specific handler>, RtlUnwind, <cleanup
block>).

I have considered a couple of options, but none appear especially
appealing to me. One is to make __a_cleanup a full-blown nested
function; I have looked into nested functions, but their
implementation seems very complex and ad-hoc, hard to adapt to a
different (and simpler) task. The other option, which seemed quite
straightforward to me at first, was to have a builtin function to call
a function with a saved frame pointer; it turns out, though, that GCC
still addresses relative to stack pointer even without FPO - on x86, I
see that the outgoing arguments area is addressed at fixed positive
offsets from ESP - unlike Visual C++ where all the compiler does to
implement __finally blocks is to juggle EBP around.

So there we are. Any suggestions?

Reply via email to