[ATfE] Redirect libc abort() to semihosting exit#665
[ATfE] Redirect libc abort() to semihosting exit#665voltur01 merged 4 commits intoarm:arm-softwarefrom
Conversation
The default libc abort() traps, thus exception handlers under semihosting crash QEMU because of nested exceptions - redirect abort() to exit() instead to cleanly finish execution with QEMU.
| __builtin_unreachable(); /* semihosting call doesn't return */ | ||
| } | ||
|
|
||
| void abort() { |
There was a problem hiding this comment.
I think we may be better off putting this in the CFI example rather than in the general support code.
AIUI abort() is meant to abort the program immediately without doing any cleanup, whereas exit() will run destructors, functions registered with atexit().
For a real world CFI I can see a case for aborting immediately without running any additional code, even exit handlers.
For our specific CFI example that's not a problem so we can locally override abort.
There was a problem hiding this comment.
It is a very good point, thanks!
I am afraid it is more than just the sample: all our exception handlers call __print_faulting_instruction which ends up in abort() here:
Would it be an option to call the semihosting exit service directly in abort() without delegating to exit() to do it? Actually, I just should call __llvm_libc_exit directly https://github.com/arm/arm-toolchain/blob/a3871cfc3d301ebc93be61e4882c19b4ec0f0fec/arm-software/embedded/llvmlibc-support/semihost/semihost.cpp#L28C6-L28C22 - it does not do any extra processing.
Let me update!
There was a problem hiding this comment.
Updated the code and description.
There was a problem hiding this comment.
For all that I said about exit() it seems like the baremetal implementation of llvm-libc exit just calls __llvm_libc_exit directly https://github.com/llvm/llvm-project/blob/main/libc/src/__support/OSUtil/baremetal/exit.cpp#L18
I think this means that with the current implementation of __llvm_libc_exit we can't support static destructors. It looks like we would need something like a call to __cxa_finalize() which do seem to be compiled into the library.
We would likely want to split out the code doing the semihosting exit in __llvm_libc_exit() into a separate function that could be called directly from abort().
Given that we don't have a working __llvm_libc_exit() function yet and it may take some research to work out what we need to do, I don't think we should hold this change up. We could leave a TODO as a comment or by raising an issue to implement calling atexit functions.
An example that generates a call to __cxa_atexit() to register a destructor.
extern void foo();
extern void bar();
struct C {
C() { foo(); }
~C() { bar(); }
int f() { return 0; }
};
C c;
int main(void) {
return c.f();
}
There was a problem hiding this comment.
Thanks, agreed, let me create a new function for just semihosting exit, then update existing __llvm_libc_exit() with a TODO and create an issue to resolve it separately.
smithp35
left a comment
There was a problem hiding this comment.
One last comment, but otherwise LGTM.
| extern "C" { | ||
|
|
||
| void __llvm_libc_exit(int status) { | ||
| void semihosting_call_exit(int status) { |
There was a problem hiding this comment.
Can we make this static or use leading __ if it is going to be callable externally, to avoid potential name clashes with user-code.
There was a problem hiding this comment.
Of course, marked as static similar to semihosting_call itself - thank you for review and patience!
The default libc abort() traps, thus exception handlers under semihosting crash QEMU because of nested exceptions - redirect abort() to semihosting exit instead to cleanly finish execution with QEMU.