|  | .. llvm-libgcc: | 
|  |  | 
|  | =========== | 
|  | llvm-libgcc | 
|  | =========== | 
|  |  | 
|  | .. contents:: | 
|  | :local: | 
|  |  | 
|  | **Note that these instructions assume a Linux and bash-friendly environment. | 
|  | YMMV if you’re on a non Linux-based platform.** | 
|  |  | 
|  | .. _introduction: | 
|  |  | 
|  | Motivation | 
|  | ============ | 
|  |  | 
|  | 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 libgcc "front" 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 | 
|  | distro manager 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. | 
|  |  | 
|  | .. _alternatives | 
|  |  | 
|  | Alternatives | 
|  | ============ | 
|  |  | 
|  | 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 cross-talk between | 
|  | the differing implementations. | 
|  |  | 
|  | .. _target audience: | 
|  |  | 
|  | Target audience | 
|  | =============== | 
|  |  | 
|  | llvm-libgcc is not for the casual LLVM user. It is intended to be used by distro | 
|  | managers who want to replace libgcc with compiler-rt and libunwind, but cannot | 
|  | fully abandon the libgcc family (e.g. because they are dependent on glibc). Such | 
|  | managers must have worked out their compatibility requirements ahead of using | 
|  | llvm-libgcc. | 
|  |  | 
|  | .. _cmake options: | 
|  |  | 
|  | CMake options | 
|  | ============= | 
|  |  | 
|  | .. option:: `LLVM_LIBGCC_EXPLICIT_OPT_IN` | 
|  |  | 
|  | **Required** | 
|  |  | 
|  | Since llvm-libgcc is such a fundamental, low-level component, we have made it | 
|  | difficult to accidentally build, by requiring you to set an opt-in flag. | 
|  |  | 
|  | .. _Building llvm-libgcc | 
|  |  | 
|  | Building llvm-libgcc | 
|  | -------------------- | 
|  |  | 
|  | The first build tree is a mostly conventional build tree and gets you a Clang | 
|  | build with these compiler-rt symbols exposed. | 
|  |  | 
|  | .. code-block:: bash | 
|  | # Assumes $(PWD) is /path/to/llvm-project | 
|  | $ cmake -GNinja -S llvm -B build-primary                    \ | 
|  | -DCMAKE_BUILD_TYPE=Release                              \ | 
|  | -DCMAKE_CROSSCOMPILING=On                               \ | 
|  | -DCMAKE_INSTALL_PREFIX=/tmp/aarch64-unknown-linux-gnu   \ | 
|  | -DLLVM_ENABLE_PROJECTS='clang'                          \ | 
|  | -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;llvm-libgcc"   \ | 
|  | -DLLVM_TARGETS_TO_BUILD=AArch64                         \ | 
|  | -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-unknown-linux-gnu  \ | 
|  | -DLLVM_LIBGCC_EXPLICIT_OPT_IN=Yes | 
|  | $ ninja -C build-primary install | 
|  |  | 
|  | It's very important to notice that neither ``compiler-rt``, nor ``libunwind``, | 
|  | are listed in ``LLVM_ENABLE_RUNTIMES``. llvm-libgcc makes these subprojects, and | 
|  | adding them to this list will cause you problems due to there being duplicate | 
|  | targets. As such, configuring the runtimes build will reject explicitly mentioning | 
|  | either project with ``llvm-libgcc``. | 
|  |  | 
|  | To avoid issues when building with ``-DLLVM_ENABLE_RUNTIMES=all``, ``llvm-libgcc`` | 
|  | is not included, and all runtimes targets must be manually listed. | 
|  |  | 
|  | ## Verifying your results | 
|  |  | 
|  | This gets you a copy of libunwind with the libgcc symbols. You can verify this | 
|  | using ``readelf``. | 
|  |  | 
|  | .. code-block:: bash | 
|  |  | 
|  | $ llvm-readelf -W --dyn-syms "${LLVM_LIBGCC_SYSROOT}/lib/libunwind.so" | grep FUNC | grep GCC_3.0 | 
|  |  | 
|  |  | 
|  | Roughly sixty symbols should appear, all suffixed with ``@@GCC_3.0``. You can | 
|  | replace ``GCC_3.0`` with any of the supported version names in the version | 
|  | script you’re exporting to verify that the symbols are exported. | 
|  |  | 
|  |  | 
|  | .. _supported platforms: | 
|  |  | 
|  | Supported platforms | 
|  | =================== | 
|  |  | 
|  | llvm-libgcc currently supports the following target triples: | 
|  |  | 
|  | * ``aarch64-*-*-*`` | 
|  | * ``armv7a-*-*-gnueabihf`` | 
|  | * ``i386-*-*-*`` | 
|  | * ``x86_64-*-*-*`` | 
|  |  | 
|  | If you would like to support another triple (e.g. ``powerpc64-*-*-*``), you'll | 
|  | need to generate a new version script, and then edit ``lib/gcc_s.ver``. | 
|  |  | 
|  | .. _Generating a new version script | 
|  |  | 
|  | Generating a new version script | 
|  | ------------------------------- | 
|  |  | 
|  | To generate a new version script, we need to generate the list of symbols that | 
|  | exist in the set (``clang-builtins.a`` ∪ ``libunwind.a``) ∩ ``libgcc_s.so.1``. | 
|  | The prerequisites for generating a version script are a binaries for the three | 
|  | aforementioned libraries targeting your architecture (without having built | 
|  | llvm-libgcc). | 
|  |  | 
|  | Once these libraries are in place, to generate a new version script, run the | 
|  | following command. | 
|  |  | 
|  | .. code-block:: bash | 
|  |  | 
|  | /path/to/llvm-project | 
|  | $ export ARCH=powerpc64 | 
|  | $ llvm/tools/llvm-libgcc/generate_version_script.py       \ | 
|  | --compiler_rt=/path/to/libclang_rt.builtins-${ARCH}.a \ | 
|  | --libunwind=/path/to/libunwind.a                      \ | 
|  | --libgcc_s=/path/to/libgcc_s.so.1                     \ | 
|  | --output=${ARCH} | 
|  |  | 
|  | This will generate a new version script a la | 
|  | ``/path/to/llvm-project/llvm/tools/llvm-libgcc/gcc_s-${ARCH}.ver``, which we use | 
|  | in the next section. | 
|  |  | 
|  | .. _Editing ``lib/gcc_s.ver`` | 
|  |  | 
|  | Editing ``lib/gcc_s.ver`` | 
|  | ------------------------- | 
|  |  | 
|  | Our freshly generated version script is unique to the specific architecture that | 
|  | it was generated for, but a lot of the symbols are shared among many platforms. | 
|  | As such, we don't check in unique version scripts, but rather have a single | 
|  | version script that's run through the C preprocessor to prune symbols we won't | 
|  | be using in ``lib/gcc_s.ver``. | 
|  |  | 
|  | Working out which symbols are common is largely a manual process at the moment, | 
|  | because some symbols may be shared across different architectures, but not in | 
|  | the same versions of libgcc. As such, a symbol appearing in ``lib/gcc_s.ver`` | 
|  | doesn't guarantee that the symbol is available for our new architecture: we need | 
|  | to verify that the versions are the same, and if they're not, add the symbol to | 
|  | the new version section, with the appropriate include guards. | 
|  |  | 
|  | There are a few macros that aim to improve readability. | 
|  |  | 
|  | * ``ARM_GNUEABIHF``, which targets exactly ``arm-*-*-gnueabihf``. | 
|  | * ``GLOBAL_X86``, which should be used to target both x86 and x86_64, regardless | 
|  | of the triple. | 
|  | * ``GLOBAL_32BIT``, which is be used to target 32-bit platforms. | 
|  | * ``GLOBAL_64BIT``, which is be used to target 64-bit platforms. |