From 9d66361514b8a20dfda03a43f213b6ec01a338bf Mon Sep 17 00:00:00 2001 From: Xing Xue Date: Thu, 17 Oct 2024 13:07:18 -0400 Subject: [PATCH] [libunwind][AIX] Remove weak declaration "__xlcxx_personality_v0" (#112436) `__xlcxx_personality_v0` is the personality routine in `libc++abi` for the EH of applications generated by the legacy IBM C++ compiler. Since the EH info generated by the legacy compiler does not provide the location of the personality routine, this routine is hard-coded as the handler for legacy EH in the unwinder. The symbol is resolved dynamically using `dlopen()` to avoid a hard dependency of `libunwind` on `libc++abi` for cases such as non-C++ applications. The weak declaration of `__xlcxx_personality_v0` was originally intended to bypass `dlopen()` if the C++ application generated by the legacy compiler is statically linked with the new LLVM C++ compiler. Unfortunately, this causes problems with runtime linking for Clang-compiled code using the unwinder that does not link with `libc++abi`. On the other hand, the C++ runtime libraries shipped for AIX are actually stripped and statically linking is not supported. So, we can fix the problem by removing the `__xlcxx_personality_v0` weak declaration. Besides, `dlopen()` would work as long as the libc++abi shared library is available. --- libunwind/src/UnwindCursor.hpp | 52 ++++++++++-------------- libunwind/test/aix_runtime_link.pass.cpp | 20 +++++++++ 2 files changed, 42 insertions(+), 30 deletions(-) create mode 100644 libunwind/test/aix_runtime_link.pass.cpp diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index ce6dced535e781b..2a3aba28fb6ca50 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -2033,7 +2033,6 @@ typedef _Unwind_Reason_Code __xlcxx_personality_v0_t(int, _Unwind_Action, uint64_t, _Unwind_Exception *, struct _Unwind_Context *); -__attribute__((__weak__)) __xlcxx_personality_v0_t __xlcxx_personality_v0; } static __xlcxx_personality_v0_t *xlcPersonalityV0; @@ -2126,42 +2125,35 @@ bool UnwindCursor::getInfoFromTBTable(pint_t pc, R ®isters) { // function __xlcxx_personality_v0(), which is the personality for the state // table and is exported from libc++abi, is directly assigned as the // handler here. When a legacy XLC++ frame is encountered, the symbol - // is resolved dynamically using dlopen() to avoid hard dependency from - // libunwind on libc++abi. + // is resolved dynamically using dlopen() to avoid a hard dependency of + // libunwind on libc++abi in cases such as non-C++ applications. // Resolve the function pointer to the state table personality if it has - // not already. + // not already been done. if (xlcPersonalityV0 == NULL) { xlcPersonalityV0InitLock.lock(); if (xlcPersonalityV0 == NULL) { - // If libc++abi is statically linked in, symbol __xlcxx_personality_v0 - // has been resolved at the link time. - xlcPersonalityV0 = &__xlcxx_personality_v0; + // Resolve __xlcxx_personality_v0 using dlopen(). + const char *libcxxabi = "libc++abi.a(libc++abi.so.1)"; + void *libHandle; + // The AIX dlopen() sets errno to 0 when it is successful, which + // clobbers the value of errno from the user code. This is an AIX + // bug because according to POSIX it should not set errno to 0. To + // workaround before AIX fixes the bug, errno is saved and restored. + int saveErrno = errno; + libHandle = dlopen(libcxxabi, RTLD_MEMBER | RTLD_NOW); + if (libHandle == NULL) { + _LIBUNWIND_TRACE_UNWINDING("dlopen() failed with errno=%d\n", errno); + assert(0 && "dlopen() failed"); + } + xlcPersonalityV0 = reinterpret_cast<__xlcxx_personality_v0_t *>( + dlsym(libHandle, "__xlcxx_personality_v0")); if (xlcPersonalityV0 == NULL) { - // libc++abi is dynamically linked. Resolve __xlcxx_personality_v0 - // using dlopen(). - const char libcxxabi[] = "libc++abi.a(libc++abi.so.1)"; - void *libHandle; - // The AIX dlopen() sets errno to 0 when it is successful, which - // clobbers the value of errno from the user code. This is an AIX - // bug because according to POSIX it should not set errno to 0. To - // workaround before AIX fixes the bug, errno is saved and restored. - int saveErrno = errno; - libHandle = dlopen(libcxxabi, RTLD_MEMBER | RTLD_NOW); - if (libHandle == NULL) { - _LIBUNWIND_TRACE_UNWINDING("dlopen() failed with errno=%d\n", - errno); - assert(0 && "dlopen() failed"); - } - xlcPersonalityV0 = reinterpret_cast<__xlcxx_personality_v0_t *>( - dlsym(libHandle, "__xlcxx_personality_v0")); - if (xlcPersonalityV0 == NULL) { - _LIBUNWIND_TRACE_UNWINDING("dlsym() failed with errno=%d\n", errno); - assert(0 && "dlsym() failed"); - } - dlclose(libHandle); - errno = saveErrno; + _LIBUNWIND_TRACE_UNWINDING("dlsym() failed with errno=%d\n", errno); + assert(0 && "dlsym() failed"); } + dlclose(libHandle); + errno = saveErrno; } xlcPersonalityV0InitLock.unlock(); } diff --git a/libunwind/test/aix_runtime_link.pass.cpp b/libunwind/test/aix_runtime_link.pass.cpp new file mode 100644 index 000000000000000..deb192c07981eb0 --- /dev/null +++ b/libunwind/test/aix_runtime_link.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Test that libunwind loads successfully independently of libc++abi with +// runtime linking on AIX. + +// REQUIRES: target={{.+}}-aix{{.*}} +// ADDITIONAL_COMPILE_FLAGS: -Wl,-brtl + +#include +extern "C" int printf(const char *, ...); +int main(void) { + void *fp = (void *)&_Unwind_Backtrace; + printf("%p\n", fp); +}