Fast LLVM with the gold linker results in segfaults
Summary
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).
Expected behavior
Built cross-compiled programs should work as expected, without having to remove the fast-llvm
flag.
Environment
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)
Analysis
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.
References
This issue was originally described in this Haskell.nix PR, where the workaround was to not use fast-llvm
.