diff --git a/cranelift/filetests/filetests/isa/riscv64/call.clif b/cranelift/filetests/filetests/isa/riscv64/call.clif index 37a4fe4aa1..aaf1133434 100644 --- a/cranelift/filetests/filetests/isa/riscv64/call.clif +++ b/cranelift/filetests/filetests/isa/riscv64/call.clif @@ -810,3 +810,52 @@ block0: ; addi a1, zero, 1 ; ret + + +function %call_colocated(i16) -> i16 { + sig0 = () system_v + fn0 = colocated u0:0 sig0 + +block0(v0: i16): + call fn0() + return v0 +} + +; VCode: +; add sp,-16 +; sd ra,8(sp) +; sd fp,0(sp) +; mv fp,sp +; sd s3,-8(sp) +; add sp,-16 +; block0: +; mv s3,a0 +; call userextname0 +; mv a0,s3 +; add sp,+16 +; ld s3,-8(sp) +; ld ra,8(sp) +; ld fp,0(sp) +; add sp,+16 +; ret +; +; Disassembled: +; block0: ; offset 0x0 +; addi sp, sp, -0x10 +; sd ra, 8(sp) +; sd s0, 0(sp) +; ori s0, sp, 0 +; sd s3, -8(sp) +; addi sp, sp, -0x10 +; block1: ; offset 0x18 +; ori s3, a0, 0 +; auipc ra, 0 ; reloc_external RiscvCall u0:0 0 +; jalr ra +; ori a0, s3, 0 +; addi sp, sp, 0x10 +; ld s3, -8(sp) +; ld ra, 8(sp) +; ld s0, 0(sp) +; addi sp, sp, 0x10 +; ret + diff --git a/cranelift/filetests/filetests/runtests/call.clif b/cranelift/filetests/filetests/runtests/call.clif index 7df6586e3b..78fa62ad03 100644 --- a/cranelift/filetests/filetests/runtests/call.clif +++ b/cranelift/filetests/filetests/runtests/call.clif @@ -5,6 +5,7 @@ target aarch64 target aarch64 sign_return_address target aarch64 has_pauth sign_return_address target s390x +target riscv64 function %callee_i64(i64) -> i64 { diff --git a/cranelift/filetests/filetests/runtests/call_libcall.clif b/cranelift/filetests/filetests/runtests/call_libcall.clif index 3e9cafd37b..8800fe25f5 100644 --- a/cranelift/filetests/filetests/runtests/call_libcall.clif +++ b/cranelift/filetests/filetests/runtests/call_libcall.clif @@ -2,6 +2,7 @@ test run target x86_64 ; AArch64 Does not have these libcalls target s390x +target riscv64 function %libcall_ceilf32(f32) -> f32 { diff --git a/cranelift/jit/src/compiled_blob.rs b/cranelift/jit/src/compiled_blob.rs index 1d1d5cc4db..7c60454e79 100644 --- a/cranelift/jit/src/compiled_blob.rs +++ b/cranelift/jit/src/compiled_blob.rs @@ -3,6 +3,14 @@ use cranelift_module::ModuleExtName; use cranelift_module::ModuleReloc; use std::convert::TryFrom; +/// Reads a 32bit instruction at `iptr`, and writes it again after +/// being altered by `modifier` +unsafe fn modify_inst32(iptr: *mut u32, modifier: impl FnOnce(u32) -> u32) { + let inst = iptr.read_unaligned(); + let new_inst = modifier(inst); + iptr.write_unaligned(new_inst); +} + #[derive(Clone)] pub(crate) struct CompiledBlob { pub(crate) ptr: *mut u8, @@ -97,9 +105,34 @@ impl CompiledBlob { // immediate offset argument. let chop = 32 - 26; let imm26 = (diff as u32) << chop >> chop; - let ins = unsafe { iptr.read_unaligned() } | imm26; + unsafe { modify_inst32(iptr, |inst| inst | imm26) }; + } + Reloc::RiscvCall => { + // A R_RISCV_CALL relocation expects auipc+jalr instruction pair. + // It is the equivalent of two relocations: + // 1. R_RISCV_PCREL_HI20 on the `auipc` + // 2. R_RISCV_PCREL_LO12_I on the `jalr` + + let base = get_address(name); + let what = unsafe { base.offset(isize::try_from(addend).unwrap()) }; + let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap() as u32; + + // See https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses + // for a better explanation of the following code. + // + // Unlike the regular symbol relocations, here both "sub-relocations" point + // to the same address. + let hi20 = pcrel.wrapping_add(0x800) & 0xFFFFF000; + let lo12 = (pcrel - hi20) & 0xFFF; + unsafe { - iptr.write_unaligned(ins); + // Do a R_RISCV_PCREL_HI20 on the `auipc` + let auipc_addr = at as *mut u32; + modify_inst32(auipc_addr, |auipc| (auipc & 0xFFF) | hi20); + + // Do a R_RISCV_PCREL_LO12_I on the `jalr` + let jalr_addr = at.offset(4) as *mut u32; + modify_inst32(jalr_addr, |jalr| (jalr & 0xFFFFF) | (lo12 << 20)); } } _ => unimplemented!(),