@@ -6,6 +6,8 @@ use cranelift_module::{ModuleError, ModuleReloc, ModuleRelocTarget, ModuleResult
66use crate :: JITMemoryProvider ;
77use crate :: memory:: JITMemoryKind ;
88
9+ const VENEER_SIZE : usize = 24 ; // ldr + br + pointer
10+
911/// Reads a 32bit instruction at `iptr`, and writes it again after
1012/// being altered by `modifier`
1113unsafe fn modify_inst32 ( iptr : * mut u32 , modifier : impl FnOnce ( u32 ) -> u32 ) {
@@ -19,6 +21,7 @@ pub(crate) struct CompiledBlob {
1921 ptr : * mut u8 ,
2022 size : usize ,
2123 relocs : Vec < ModuleReloc > ,
24+ veneer_count : usize ,
2225 #[ cfg( feature = "wasmtime-unwinder" ) ]
2326 wasmtime_exception_data : Option < Vec < u8 > > ,
2427}
@@ -34,8 +37,17 @@ impl CompiledBlob {
3437 #[ cfg( feature = "wasmtime-unwinder" ) ] wasmtime_exception_data : Option < Vec < u8 > > ,
3538 kind : JITMemoryKind ,
3639 ) -> ModuleResult < Self > {
40+ // Reserve veneers for all function calls just in case
41+ let mut veneer_count = 0 ;
42+ for reloc in & relocs {
43+ match reloc. kind {
44+ Reloc :: Arm64Call => veneer_count += 1 ,
45+ _ => { }
46+ }
47+ }
48+
3749 let ptr = memory
38- . allocate ( data. len ( ) , align, kind)
50+ . allocate ( data. len ( ) + veneer_count * VENEER_SIZE , align, kind)
3951 . map_err ( |e| ModuleError :: Allocation { err : e } ) ?;
4052
4153 unsafe {
@@ -46,6 +58,7 @@ impl CompiledBlob {
4658 ptr,
4759 size : data. len ( ) ,
4860 relocs,
61+ veneer_count,
4962 #[ cfg( feature = "wasmtime-unwinder" ) ]
5063 wasmtime_exception_data,
5164 } )
@@ -69,6 +82,7 @@ impl CompiledBlob {
6982 ptr,
7083 size,
7184 relocs,
85+ veneer_count : 0 ,
7286 #[ cfg( feature = "wasmtime-unwinder" ) ]
7387 wasmtime_exception_data,
7488 } )
@@ -93,6 +107,8 @@ impl CompiledBlob {
93107 ) {
94108 use std:: ptr:: write_unaligned;
95109
110+ let mut next_veneer_idx = 0 ;
111+
96112 for (
97113 i,
98114 & ModuleReloc {
@@ -143,19 +159,50 @@ impl CompiledBlob {
143159 let what = unsafe { base. offset ( isize:: try_from ( addend) . unwrap ( ) ) } ;
144160 // The instruction is 32 bits long.
145161 let iptr = at as * mut u32 ;
162+
146163 // The offset encoded in the `bl` instruction is the
147164 // number of bytes divided by 4.
148165 let diff = ( ( what as isize ) - ( at as isize ) ) >> 2 ;
149166 // Sign propagating right shift disposes of the
150167 // included bits, so the result is expected to be
151- // either all sign bits or 0, depending on if the original
152- // value was negative or positive.
153- assert ! ( ( diff >> 25 == -1 ) || ( diff >> 25 == 0 ) ) ;
154- // The lower 26 bits of the `bl` instruction form the
155- // immediate offset argument.
156- let chop = 32 - 26 ;
157- let imm26 = ( diff as u32 ) << chop >> chop;
158- unsafe { modify_inst32 ( iptr, |inst| inst | imm26) } ;
168+ // either all sign bits or 0 when in-range, depending
169+ // on if the original value was negative or positive.
170+ if ( diff >> 25 == -1 ) || ( diff >> 25 == 0 ) {
171+ // The lower 26 bits of the `bl` instruction form the
172+ // immediate offset argument.
173+ let chop = 32 - 26 ;
174+ let imm26 = ( diff as u32 ) << chop >> chop;
175+ unsafe { modify_inst32 ( iptr, |inst| inst | imm26) } ;
176+ } else {
177+ // If the target is out of range for a direct call, insert a veneer at the
178+ // end of the function.
179+ let veneer_idx = next_veneer_idx;
180+ next_veneer_idx += 1 ;
181+ assert ! ( veneer_idx <= self . veneer_count) ;
182+ let veneer =
183+ unsafe { self . ptr . byte_add ( self . size + veneer_idx * VENEER_SIZE ) } ;
184+
185+ // Write the veneer
186+ // x16 is reserved as scratch register to be used by veneers and PLT entries
187+ unsafe {
188+ write_unaligned (
189+ veneer. cast :: < u32 > ( ) ,
190+ 0x58000050 , // ldr x16, 0x8
191+ ) ;
192+ write_unaligned (
193+ veneer. byte_add ( 4 ) . cast :: < u32 > ( ) ,
194+ 0xd61f0200 , // br x16
195+ ) ;
196+ write_unaligned ( veneer. byte_add ( 8 ) . cast :: < u64 > ( ) , what. addr ( ) as u64 ) ;
197+ } ;
198+
199+ // Set the veneer as target of the call
200+ let diff = ( ( veneer as isize ) - ( at as isize ) ) >> 2 ;
201+ assert ! ( ( diff >> 25 == -1 ) || ( diff >> 25 == 0 ) ) ;
202+ let chop = 32 - 26 ;
203+ let imm26 = ( diff as u32 ) << chop >> chop;
204+ unsafe { modify_inst32 ( iptr, |inst| inst | imm26) } ;
205+ }
159206 }
160207 Reloc :: Aarch64AdrGotPage21 => {
161208 panic ! ( "GOT relocation shouldn't be generated when !is_pic" ) ;
0 commit comments