Skip to content

Bug 41137: Build gcc-cross and tor-expert-bundle for linux-aarch64

NoisyCoil requested to merge NoisyCoil/tor-browser-build:bug_41137 into main

Merge Info

Related Issues

Backporting

Timeline

  • Immediate: patchset needed as soon as possible
  • Next Minor Stable Release: patchset that needs to be verified in nightly before backport
  • Eventually: patchset that needs to be verified in alpha before backport
  • No Backport (preferred): patchset for the next major stable

(Optional) Justification

  • Emergency security update: patchset fixes CVEs, 0-days, etc
  • Censorship event: patchset enables censorship circumvention
  • Critical bug-fix: patchset fixes a bug in core-functionality
  • Consistency: patchset which would make development easier if it were in both the alpha and release branches; developer tools, build system changes, etc
  • Sponsor required: patchset required for sponsor
  • Other: please explain

Issue Tracking

Review

Request Reviewer

  • Request review from an applications developer depending on modified system:
    • NOTE: if the MR modifies multiple areas, please /cc all the relevant reviewers (since gitlab only allows 1 reviewer)
    • accessibility : henry
    • android : clairehurst, dan
    • build system : boklm
    • extensions : ma1
    • firefox internals (XUL/JS/XPCOM) : ma1
    • fonts : pierov
    • frontend (implementation) : henry
    • frontend (review) : donuts, richard
    • localization : henry, pierov
    • macos : clairehurst, dan
    • nightly builds : boklm
    • rebases/release-prep : boklm, dan, ma1, pierov, richard
    • security : ma1
    • signing : boklm, richard
    • updater : pierov
    • misc/other : pierov, richard

Change Description

This MR adds support for building a gcc toolchain and the tor-expert-bundle for linux-aarch64. It does so by

  • rationalizing the process of cross-compiling a linux target (linux-cross) and making it extensible to other archs
  • adding a gcc-cross project
  • making small changes to container-image, binutils, openssl, go-bootstrap and go
  • building tor for linux-cross targets

The gcc-cross and tor-expert-bundle projects, and any project in between, can be built using

./rbm/rbm build $project --target alpha --target torbrowser-linux-$arch

where $arch is one of aarch64 or arm. linux-arm is not within the main scope of this MR, but enabling it only required a couple of minor changes, and it serves as a check that the cross-compilation logic is solid for generic linux targets.

In what follows I will detail the cross-compilation logic and some of the changes contained in this patchset. You can skip the cross-compilation logic if you are not interested, the patchset will still work! But in the future more work is likely to be done on linux-cross targets if this MR is accepted, so it's best if I lay it out here.

Cross-compilation logic

The linux-cross target defines the compiler and the generic configure options for linux cross-compiled targets. When cross-compiling, there are a few things we must take into account:

  1. we need to build both a native compiler (to build the host tools) and a cross compiler (to build the target binaries)
  2. some projects are built for the host, others are built for the target, others still are built for the host and will build binaries for the target. linux-cross needs a way to select which of the above compilers to use for each project
  3. projects built for the host which build binaries for the target may need both the compilers (e.g. rust apparently does, while clang doesn't while building clang, but does while building firefox)
  4. we don't want to build the host tools multiple times (think about cmake, python, etc.), so their projects must have the native compiler alone among their dependencies

In light of the above, this MR implements linux cross-compilation as follows. First, a copy of the native compiler (and of cross-binutils), separately built as dependencies, are embedded into the cross-compiler artifact. This avoids huge headaches with passing headers and library paths around when building rust and firefox (admittedly outside the scope of this MR, but something we must take into account from the get-go if we don't want to re-write the cross compiler from scratch later).

Second, by default, projects built for the linux-cross target will use the cross-compiler. However, to avoid tens of unmanageable target_replace, projects which only build host tools and whose building does not need the cross compiler are marked with a no_crosscompile variable, and are built using the native compiler. Selecting the native compiler when no_crosscompile: 1 is done automatically by the linux-cross target via the definition of compiler in rbm.conf.

In general, a project should be marked as no_crosscompile if:

  • it is built using the linux-cross target
  • its building requires a compiler, and that compiler is the native compiler

However, this is not enough to comply with point 4. above. The reason for this is Jeremy Rand sneaked in a quite useful change in projects/container-image: in current main, when building for target linux-cross, the build container calls dpkg --add-architecture $debian_arch before installing packages. Since this changes the container's setup and thus its id, all projects built in a container under the linux-cross target in current main, and all projects which depend on such projects, have different ids and will be built twice, whether or not they are actually cross-compiling anything. This includes the host tools.

To fix this, I deactivated dpkg --add-architecture $debian_arch in the container's setup when no_crosscompile is set for the container's parent project. Thanks to this change, to comply with point 4., a project must be marked as no_crosscompile if:

  • it is built using the linux-cross target (either directly or indirectly, as a dependence of another project)
  • its building does not require the cross-compiler
  • it is built in a container

On the other hand, it must not be marked as no_crosscompile if it requires the cross-compiler (unless the project's own linux-cross targets defines no_crosscompile: 0 of course).

Details

Some of the changes are explained in the commit messages, in comments or in patch headers. In addition to those:

  • binutils is the only project in all tor-browser-build which needs to be both compiled and cross-compiled (meaning that it provides cross-binutils) and which does not need a separate build script for cross compilation. It is not natively compiled in this MR, but it will be eventually, when building the browser. It must be called with the linux-cross target when and only when we want cross-binutils
  • gcc and the cross gcc toolchain are built in completely different ways, so I separated the cross toolchain into a gcc-cross project. As mentioned previously, gcc-cross contains a copy of the cross binutils and of the native compiler, which are built separately and imported as dependencies
  • in gcc-cross, two glibc patches are backported to overcome build failures due to linking issues. These are specific to linux-aarch64, and to this version of glibc (I chose v2.24 because this is the last version which, when used as part of the gcc cross-toolchain, is able to compile binaries which work on Debian Stretch). The *.patch files bear the names of the original authors and the hashes of the original commit, so you can easily find them in the glibc git repo. However I had to refresh them for the glibc version contained in this MR. In more detail:
    • glibc-cross-linux-aarch64.patch overcomes relocation R_AARCH64_ABS32 against 'a local symbol' can not be used when making a shared object. More info here
    • glibc-cross-linux-aarch64-2.patch overcomes relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol '_dl_argv' which may bind externally can not be used when making a shared object. More info here
  • there are of course a lot of details regarding how gcc-cross is built. As a general rule, I started from Jeremy's code (which is still there and makes up for the majority of the gcc-cross build script I believe) and changed it until I got a cross compiler which is able to fully build the browser
  • go-bootstrap is correctly built once for all targets. go would be too for all linux targets if osname was not in its filename, but I'm not going to change this now because it is outside of the scope of this MR (does not apply when building with the torbrowser-linux-$arch target)

How Tested

I tested the gcc-cross compiler by building tor-expert-bundle for both linux-aarch64 and linux-arm. I tested the tor-expert-bundle as part of a full linux-aarch64 build of the Tor Browser using this linux-cross branch, which is a rewrite of !920 that avoids rebuilding the host tools and that does not contain the native linux-aarch64 build enablement patches. The linux-arm tor-expert-bundle artifact is untested (although I checked that all the binaries contained therein are for the correct architecture).

A note

I talked to Jeremy Rand and, from what I understood, he is fine with me changing his linux-cross code as long as openssl still builds the linux-arm target (i.e. if there are no regressions in the code). This MR builds a full linux-arm tor-expert-bundle (and it's the base for cross-building a whole linux-aarch64 Tor Browser), so I think we're good from this perspective, although as I mentioned those binaries are untested.

Edited by NoisyCoil

Merge request reports