[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.
This commit is contained in:
@@ -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<A, R>::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;
|
||||
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;
|
||||
// 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;
|
||||
}
|
||||
xlcPersonalityV0InitLock.unlock();
|
||||
}
|
||||
|
||||
20
libunwind/test/aix_runtime_link.pass.cpp
Normal file
20
libunwind/test/aix_runtime_link.pass.cpp
Normal file
@@ -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 <unwind.h>
|
||||
extern "C" int printf(const char *, ...);
|
||||
int main(void) {
|
||||
void *fp = (void *)&_Unwind_Backtrace;
|
||||
printf("%p\n", fp);
|
||||
}
|
||||
Reference in New Issue
Block a user