summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoritz Angermann <moritz.angermann@gmail.com>2021-06-22 15:39:44 +0800
committerZubin Duggal <zubin.duggal@gmail.com>2021-09-21 22:28:28 +0530
commitb6345f562d70ed7045ebd4e736aec23461dc238e (patch)
treebee52dc96ca4125759bdc7aaf8480ee58a3b76c9
parent697b1bda04229fba32a2a602bcc39d1b795b59a1 (diff)
downloadhaskell-b6345f562d70ed7045ebd4e736aec23461dc238e.tar.gz
[aarch64-macho] Fix off-by-one error in the linker
We need to be careful about the sign bit for BR26 relocation otherwise we end up encoding a large positive number and reading back a large negative number. (cherry picked from commit d6ab9c60288369ec991826b158d751dd4cb3319e) (cherry picked from commit e0aa6de799463d0868da7e8a5ad29141141e7855)
-rw-r--r--rts/linker/MachO.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/rts/linker/MachO.c b/rts/linker/MachO.c
index f8bcdca657..6c47d98f9d 100644
--- a/rts/linker/MachO.c
+++ b/rts/linker/MachO.c
@@ -615,7 +615,17 @@ relocateSectionAarch64(ObjectCode * oc, Section * section)
} else {
value = (uint64_t)symbol->addr; // address of the symbol.
}
- if((value - pc + addend) >> (2 + 26)) {
+ // We've got:
+ // + 2 bits, for alignment
+ // + 26 bits for for the relocation value
+ // - 1 bit for signage.
+ //
+ // Thus we can encode 26 bits for relocation, including the sign
+ // bit. However as branches need to be 4-byte aligned, we only
+ // need 26 bits to address a 28 bit range. Thus discarding the
+ // sign bit, we can encode a range of +/- 27bits.
+ //
+ if((value - pc + addend) >> (2 + 26 - 1)) {
/* we need a stub */
/* check if we already have that stub */
if(findStub(section, (void**)&value)) {