summaryrefslogtreecommitdiff
path: root/runtimes
diff options
context:
space:
mode:
authorChristopher Di Bella <cjdb@google.com>2021-08-17 20:23:22 +0000
committerChristopher Di Bella <cjdb@google.com>2022-02-16 17:06:45 +0000
commitc5a20b518203613497fa864867fc232648006068 (patch)
tree6151c885938813bd5d5eea4ee49cbb12ef6b1991 /runtimes
parent0c58e9f4a474c60ed863e6a66c0e1202b4bd6c78 (diff)
downloadllvm-c5a20b518203613497fa864867fc232648006068.tar.gz
[llvm-libgcc] initial commit
Note: the term "libgcc" refers to the all of `libgcc.a`, `libgcc_eh.a`, and `libgcc_s.so`. Enabling libunwind as a replacement for libgcc on Linux has proven to be challenging since libgcc_s.so is a required dependency in the [Linux standard base][5]. Some software is transitively dependent on libgcc because glibc makes hardcoded calls to functions in libgcc_s. For example, the function `__GI___backtrace` eventually makes its way to a [hardcoded dlopen to libgcc_s' _Unwind_Backtrace][1]. Since libgcc_{eh.a,s.so} and libunwind have the same ABI, but different implementations, the two libraries end up [cross-talking, which ultimately results in a segfault][2]. To solve this problem, libunwind needs to build a “libgcc”. That is, link the necessary functions from compiler-rt and libunwind into an archive and shared object that advertise themselves as `libgcc.a`, `libgcc_eh.a`, and `libgcc_s.so`, so that glibc’s baked calls are diverted to the correct objects in memory. Fortunately for us, compiler-rt and libunwind use the same ABI as the libgcc family, so the problem is solvable at the llvm-project configuration level: no program source needs to be edited. Thus, the end result is for a user to configure their LLVM build with a flag that indicates they want to archive compiler-rt/unwind as libgcc. We achieve this by compiling libunwind with all the symbols necessary for compiler-rt to emulate the libgcc family, and then generate symlinks named for our "libgcc" that point to their corresponding libunwind counterparts. We alternatively considered patching glibc so that the source doesn't directly refer to libgcc, but rather _defaults_ to libgcc, so that a system preferring compiler-rt/libunwind can point to these libraries at the config stage instead. Even if we modified the Linux standard base, this alternative won't work because binaries that are built using libgcc will still end up having crosstalk between the differing implementations. This problem has been solved in this manner for [FreeBSD][3], and this CL has been tested against [Chrome OS][4]. [1]: https://github.com/bminor/glibc/blob/master/sysdeps/arm/backtrace.c#L68 [2]: https://bugs.chromium.org/p/chromium/issues/detail?id=1162190#c16 [3]: https://github.com/freebsd/freebsd-src/tree/main/lib/libgcc_s [4]: https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/2945947 [5]: https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/libgcc-s.html Differential Revision: https://reviews.llvm.org/D108416
Diffstat (limited to 'runtimes')
-rw-r--r--runtimes/CMakeLists.txt17
1 files changed, 17 insertions, 0 deletions
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 8613a91fc90a..86dc7fb75fda 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -178,6 +178,23 @@ if(LLVM_INCLUDE_TESTS)
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
endif()
+# llvm-libgcc incorporates both compiler-rt and libunwind as subprojects with very
+# specific flags, which causes clashes when they're independently built too.
+if("llvm-libgcc" IN_LIST runtimes)
+ if("compiler-rt" IN_LIST runtimes OR "compiler-rt" IN_LIST LLVM_ENABLE_PROJECTS)
+ message(FATAL_ERROR
+ "Attempting to build both compiler-rt and llvm-libgcc will cause irreconcilable "
+ "target clashes. Please choose one or the other, but not both.")
+ endif()
+
+ if("libunwind" IN_LIST runtimes)
+ message(
+ FATAL_ERROR
+ "Attempting to build both libunwind and llvm-libgcc will cause irreconcilable "
+ "target clashes. Please choose one or the other, but not both.")
+ endif()
+endif()
+
# We do this in two loops so that HAVE_* is set for each runtime before the
# other runtimes are added.
foreach(entry ${runtimes})