diff options
author | Xing Xue <xingxue@outlook.com> | 2022-10-27 22:11:06 +0300 |
---|---|---|
committer | Xing Xue <xingxue@outlook.com> | 2022-10-27 22:11:06 +0300 |
commit | a499051f10a2d0150b60c14493558476039f701a (patch) | |
tree | 74aa173c914a217a8a00554648bf8bc18c4dc727 /libcxxabi/src/aix_state_tab_eh.inc | |
parent | c0095050dacff8a7b0e9066cfd1c37c684bc4fa3 (diff) |
[libc++abi][AIX] Use reserved slot in stack to pass the address of exception object
Summary:
The existing implementation of the personality for legacy IBM xlclang++ compiler generated code passes the address of exception object in r14 for the landing pad to retrieve with a call to __xlc_exception_handle(). This clobbers the content of r14 in user code (and potentially, when running cleanup actions, the address of another exception object being passed). This patch changes to use the stack slot reserved for compilers to pass the address. It has been confirmed that xlclang++-generated code does not use this slot.
Reviewed by: hubert.reinterpretcast, cebowleratibm
Diffstat (limited to 'libcxxabi/src/aix_state_tab_eh.inc')
-rw-r--r-- | libcxxabi/src/aix_state_tab_eh.inc | 50 |
1 files changed, 42 insertions, 8 deletions
diff --git a/libcxxabi/src/aix_state_tab_eh.inc b/libcxxabi/src/aix_state_tab_eh.inc index 387613104524..f5b229a9cab2 100644 --- a/libcxxabi/src/aix_state_tab_eh.inc +++ b/libcxxabi/src/aix_state_tab_eh.inc @@ -14,6 +14,10 @@ #include <stdio.h> #include <sys/debug.h> +#if !__has_cpp_attribute(clang::optnone) +#error This file requires clang::optnone attribute support +#endif + /* The legacy IBM xlC and xlclang++ compilers use the state table for EH instead of the range table. Destructors, or addresses of the possible catch @@ -183,10 +187,6 @@ enum FSMMagic : uint32_t { number3 = 0x1cedbeef // State table generated by xlclang++ compiler. }; -constexpr uint32_t REG_EXCP_OBJ = 14; // Register to pass the address of the exception - // object from the personality to xlclang++ - // compiled code. - constexpr size_t dtorArgument = 0x02; // Flag to destructor indicating to free // virtual bases, don't delete object. @@ -555,8 +555,16 @@ __xlcxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionCl if (actions & _UA_CLEANUP_PHASE) { // Phase 2 cleanup: if (results.reason == _URC_HANDLER_FOUND) { + // Store the address of unwind_exception in the stack field + // reserved for compilers (SP + 3 * sizeof(uintptr_t)) in the stack of + // the caller of the function containing the landing pad (within the link + // area for the call to the latter) for __xlc_exception_handle() + // to retrieve. + uintptr_t *currentSP = reinterpret_cast<uintptr_t*>(_Unwind_GetGR(context, 1)); + uintptr_t *callersSP = reinterpret_cast<uintptr_t*>(currentSP[0]); + callersSP[3] = reinterpret_cast<uintptr_t>(unwind_exception); + _LIBCXXABI_TRACE_STATETAB("Handshake: set unwind_exception=%p in stack=%p\n", reinterpret_cast<void*>(unwind_exception), reinterpret_cast<void*>(callersSP)); // Jump to the handler. - _Unwind_SetGR(context, REG_EXCP_OBJ, reinterpret_cast<uintptr_t>(unwind_exception)); _Unwind_SetIP(context, results.landingPad); return _URC_INSTALL_CONTEXT; } @@ -633,12 +641,38 @@ _LIBCXXABI_FUNC_VIS void __xlc_throw_badexception() { __cxa_throw(newexception, const_cast<std::type_info*>(&typeid(std::bad_exception)), 0); } +// force_a_stackframe +// This function is called by __xlc_exception_handle() to ensure a stack frame +// is created for __xlc_exception_handle(). +__attribute__((noinline, optnone)) +static void force_a_stackframe() {} + // __xlc_exception_handle // This function is for xlclang++. It returns the address of the exception -// object set in gpr14 by the personality routine for xlclang++ compiled code. +// object stored in the reserved field in the stack of the caller of the +// function that calls __xlc_exception_handle() (within the link area for the +// call to the latter). The address is stored by the personality routine for +// xlclang++ compiled code. The implementation of __xlc_exception_handle() +// assumes a stack frame is created for it. The following ensures this +// assumption holds true: 1) a call to force_a_stackframe() is made inside +// __xlc_exception_handle() to make it non-leaf; and 2) optimizations are +// disabled for this function with attribute 'optnone'. Note: this function +// may not work as expected if these are changed. +__attribute__((optnone)) _LIBCXXABI_FUNC_VIS uintptr_t __xlc_exception_handle() { - uintptr_t exceptionObject; - asm("mr %0, 14" : "=r"(exceptionObject)); + // Make a call to force_a_stackframe() so that the compiler creates a stack + // frame for this function. + force_a_stackframe(); + + // Get the SP of this function, i.e., __xlc_exception_handle(). + uintptr_t *lastStack; + asm("mr %0, 1" : "=r"(lastStack)); + // Get the SP of the caller of __xlc_exception_handle(). + uintptr_t *callerStack = reinterpret_cast<uintptr_t*>(lastStack[0]); + // Get the SP of the caller of the caller. + uintptr_t *callerStack2 = reinterpret_cast<uintptr_t*>(callerStack[0]); + uintptr_t exceptionObject = callerStack2[3]; + _LIBCXXABI_TRACE_STATETAB("Handshake: exceptionObject=%p from stack=%p\n", reinterpret_cast<void*>(exceptionObject), reinterpret_cast<void*>(callerStack2)); return exceptionObject; } |