| .. 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. |