Skip to content

ARM Thumb relocation fails to handle sign of veneer jumps

While working on http://hackage.haskell.org/trac/ghc/ticket/7794 on Linux/ARM (ARMv7, hard float), I found that 'inplace/bin/ghc-stage2 --interactive' was raising various signals along the lines of SIGSEGV/SIGILL on startup. Considerable hair-pulling and gdb later, I found that this was a jump into space when it should have been jumping to nl_langinfo from localeEncoding in base. After even more poking around with gdb, I've tracked this down to a linker bug and have a patch.

When the linker processes an R_ARM_THM_CALL or R_ARM_THM_JUMP24 relocation, it sometimes needs to generate a "veneer" jump target if the true destination is out of range. This is done almost entirely correctly. However, it reuses the sign bit decoded from the original instruction when re-encoding. This means that if the veneer is on the opposite side of the branch instruction from the unrelocated target, the branch target will be encoded incorrectly. This is a common case since the veneer is typically generated after the code being relocated but a to-be-relocated R_ARM_THM_CALL instruction will typically be a branch to PC-4 (a.k.a. the branch source itself).

The simple, and I hope obvious, fix is to compute the sign from the new offset. The attached patch should apply to both master and ghc-7.6.

Trac metadata
Trac field Value
Version 7.6.2
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Runtime System
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information