forked from OSchip/llvm-project
188 lines
7.1 KiB
ReStructuredText
188 lines
7.1 KiB
ReStructuredText
.. 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.
|