[Mono-devel-list] AMD64, PInvoke + Native Exceptions
Willibald Krenn
Willibald.Krenn at gmx.at
Wed Oct 27 15:05:05 EDT 2004
Hi!
> This could be implemented, I guess. The implementation might be based on
> the one in gcj.
While I've no clue of how gcj catches native exceptions (I assume it
uses the standard C library), I tried to find some 'hack' that works for
a JIT compiler that is dynamically emitting wrapper methods on AMD64.
First Problem: On AMD64 C-exception handling is based on unwind
information available in the .eh_frame(?) section (which is read only)
of the ELF file. So generating that unwind information is obviously out
of question for several reasons.
Consequently there is probably only one way to go: Trick the subroutine
into thinking the caller was some function with a try-catch block.
Interestingly enough, this does work - and seems to be not that costly.
(At least one additional jump and either one callee saved register or a
stack slot is being used. Plus the calculation of the correct return
address..)
As this won't do anything about the LMF structures that need to be
saved, I've tried to implement a signal handler that just throws a C
exception and see if it reaches the catch block. Well, it does: The
catch block will be executed and all callee saved registers have the
correct values.
But I dunno, if this is the way to go, because my short search on signal
handlers and exceptions on google revealed that everyone seems to
discourage that approach. ("Just set a flag in a signal handler..")
In that case, the LMF structure clearly has an advantage because it's
completely unimportant what's on the runtime stack. But then again: I
read in the Summit Notes that the exception on sigsev will eventually be
disabled and after a SIGSEV it's not guaranteed that the stack will be
'ok'?!
For the curious here's what i've done:
void ExHandler(void)
{
/*The faked try-catch block*/
try
{
/*...skipping some 'tricks' for gcc...*/
FakeReturn:
__asm__ __volatile__(
/* "jmp *%r15\n\t" */ /*callee saved reg or*/
"ret\n\t" /*stack slot*/
);
}
/*If the native function throws an exception, we'll start
* _here_ with exception handling! So basically this would be the
* entrypoint of a custom JIT exception handling routine.
* */
catch(...)
{
/* RAX => pointer to _Unwind_Exception
* R15 => where normal execution should have continued (if not on
* stack)
* RBX, RBP, RSP, R12..R14 restored
* */
/*set myException pointer*/
__asm__ __volatile__ ("movq $myException, %r11\n\t"
"movq %rax,(%r11)\n\t"
);
/*__asm__ __volatile__ ("int3");*/
}
}
The call into a native function that might throw an exception in psuedo asm:
__asm__ (
"push ($AfterCallPtr)"
/*"movq ($AfterCallPtr), %r15"*/
"push ($FakeReturnPtr)"
"jmp ToBeCalled\n\t");
AfterCall:
Looking forward for comments,
Willi
More information about the Mono-devel-list
mailing list