Fast LLVM with the gold linker results in segfaults
In a cross-compiling scenario (from x86_64 to armv6l, GHC 8.6.5 with Haskell.nix), using the gold linker with the
fast-llvm flag, built Haskell program were segfaulting at startup. Compiling without the
fast-llvm flag solves the issue.
Steps to reproduce
The issue manifests itself when trying to execute any program cross-compiled with this building environment, even the
remote-iserv program built by Haskell.nix for the target platform (armv6l), or when trying to cross-compile any program requiring
remote-iserv (e.g. using TH).
Built cross-compiled programs should work as expected, without having to remove the
The issue were encountered with the following environment:
- Cross-copmpilation from x86_64 to armv6l using Haskell.nix (ref: d1102d342c2f5720a10d77d520d37858af103bf6)
- GHC 8.6.5
- GLIBC 2.27
- The gold linker 1.16 (binutils 2.31.1)
- NixOS 19.09 (x86_64)
The following is what I've found while analyzing the issue. I couldn't find any info related to it in the issue tracker. Note that I've only tested it in an Armv6l + LLVM + GLIBC + GHC 8.6.5 environment, but I haven't tested it on other configurations.
The segfault is happening because the produced Haskell programs have some relocatable data (
.data.rel.ro section) in a read-only segment, when they should actually be in a read-write segment segment, that will be write-protected after relocation (
GNU_RELRO segment) by GLIBC. Updating the relocatable data then ends up in segfault.
Compiling Haskell code may produce relocatable data (in the
.data.rel.ro section) that needs relocation. However, when using the LLVM backend with the
fast-llvm flag, the LLVM mangler and GNU assembler are bypassed. And it turns out the LLVM backend alone considers the relocatable data as constant, marking the associated section as read-only. The gold linker seeing that section being read-only then act accordingly, ending up in segfault at startup. Using the ld linker instead of the gold linker, it seems that ld recognizes the
.data.rel.ro section as special by name, and marks it writable anyway.
After removing the
fast-llvm flag, the GNU assembler is the one producing the object code. However, when seeing the
.data.rel.ro section, it recognizes it as special (like the ld linker) and automatically marks it as writeable. The gold linker then recognizes it as containing relocatable data, and thus use a
GNU_RELRO segment, ending up in a functional compiled program.
This issue was originally described in this Haskell.nix PR, where the workaround was to not use