Skip to content

Commit 5e4bfa7

Browse files
authored
cranelift-jit: Fix arm64 adrp relocations (#11735)
The relative address accidentally got zero-extended rather than sign-extended, causing relocation targets before the adrp instruction to be 4GB off.
1 parent 7b3d6ae commit 5e4bfa7

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

cranelift/jit/src/compiled_blob.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,17 @@ impl CompiledBlob {
101101
let base = get_address(name);
102102
let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
103103
let get_page = |x| x & (!0xfff);
104-
let pcrel = i32::try_from(get_page(what as isize) - get_page(at as isize))
105-
.unwrap()
106-
.cast_unsigned();
104+
// NOTE: This should technically be i33 given that this relocation type allows
105+
// a range from -4GB to +4GB, not -2GB to +2GB. But this doesn't really matter
106+
// as the target is unlikely to be more than 2GB from the adrp instruction. We
107+
// need to be careful to not cast to an unsigned int until after doing >> 12 to
108+
// compute the upper 21bits of the pcrel address however as otherwise the top
109+
// bit of the 33bit pcrel address would be forced 0 through zero extension
110+
// instead of being sign extended as it should be.
111+
let pcrel =
112+
i32::try_from(get_page(what as isize) - get_page(at as isize)).unwrap();
107113
let iptr = at as *mut u32;
108-
let hi21 = pcrel >> 12;
114+
let hi21 = (pcrel >> 12).cast_unsigned();
109115
let lo = (hi21 & 0x3) << 29;
110116
let hi = (hi21 & 0x1ffffc) << 3;
111117
unsafe { modify_inst32(iptr, |inst| inst | lo | hi) };

0 commit comments

Comments
 (0)