diff --git a/cranelift/codegen/src/binemit/mod.rs b/cranelift/codegen/src/binemit/mod.rs index d5582d87f3be..d8d804bbdc28 100644 --- a/cranelift/codegen/src/binemit/mod.rs +++ b/cranelift/codegen/src/binemit/mod.rs @@ -85,12 +85,14 @@ pub enum Reloc { /// This is equivalent to `R_AARCH64_LD64_GOT_LO12_NC` (312) in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#static-aarch64-relocations) Aarch64Ld64GotLo12Nc, - /// procedure call. - /// call symbol - /// expands to the following assembly and relocation: - /// auipc ra, 0 - /// jalr ra, ra, 0 - RiscvCall, + /// RISC-V Call PLT: 32-bit PC-relative function call, macros call, tail (PIC) + /// + /// Despite having PLT in the name, this relocation is also used for normal calls. + /// The non-PLT version of this relocation has been deprecated. + /// + /// This is the `R_RISCV_CALL_PLT` relocation from the RISC-V ELF psABI document. + /// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#procedure-calls + RiscvCallPlt, /// RISC-V TLS GD: High 20 bits of 32-bit PC-relative TLS GD GOT reference, /// @@ -104,6 +106,12 @@ pub enum Reloc { /// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses RiscvPCRelLo12I, + /// High 20 bits of a 32-bit PC-relative GOT offset relocation + /// + /// This is the `R_RISCV_GOT_HI20` relocation from the RISC-V ELF psABI document. + /// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses + RiscvGotHi20, + /// s390x TLS GD64 - 64-bit offset of tls_index for GD symbol in GOT S390xTlsGd64, /// s390x TLS GDCall - marker to enable optimization of TLS calls @@ -125,8 +133,9 @@ impl fmt::Display for Reloc { Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"), Self::X86SecRel => write!(f, "SecRel"), Self::Arm32Call | Self::Arm64Call => write!(f, "Call"), - Self::RiscvCall => write!(f, "RiscvCall"), + Self::RiscvCallPlt => write!(f, "RiscvCallPlt"), Self::RiscvTlsGdHi20 => write!(f, "RiscvTlsGdHi20"), + Self::RiscvGotHi20 => write!(f, "RiscvGotHi20"), Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"), Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"), Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"), diff --git a/cranelift/codegen/src/isa/riscv64/inst/emit.rs b/cranelift/codegen/src/isa/riscv64/inst/emit.rs index 2fc5749deea4..da7845de7996 100644 --- a/cranelift/codegen/src/isa/riscv64/inst/emit.rs +++ b/cranelift/codegen/src/isa/riscv64/inst/emit.rs @@ -1323,55 +1323,16 @@ impl Inst { } } &Inst::Call { ref info } => { - // call - match info.dest { - ExternalName::User { .. } => { - if info.opcode.is_call() { - sink.add_call_site(info.opcode); - } - sink.add_reloc(Reloc::RiscvCall, &info.dest, 0); - if let Some(s) = state.take_stack_map() { - sink.add_stack_map(StackMapExtent::UpcomingBytes(8), s); - } - Inst::construct_auipc_and_jalr( - Some(writable_link_reg()), - writable_link_reg(), - 0, - ) - .into_iter() - .for_each(|i| i.emit_uncompressed(sink, emit_info, state, start_off)); - } - ExternalName::LibCall(..) - | ExternalName::TestCase { .. } - | ExternalName::KnownSymbol(..) => { - // use indirect call. it is more simple. - // load ext name. - Inst::LoadExtName { - rd: writable_spilltmp_reg2(), - name: Box::new(info.dest.clone()), - offset: 0, - } - .emit(&[], sink, emit_info, state); - - // call - Inst::CallInd { - info: Box::new(CallIndInfo { - rn: spilltmp_reg2(), - // This doesen't really matter but we might as well send - // the correct info. - uses: info.uses.clone(), - defs: info.defs.clone(), - clobbers: info.clobbers, - opcode: Opcode::CallIndirect, - caller_callconv: info.caller_callconv, - callee_callconv: info.callee_callconv, - // Send this as 0 to avoid updating the pop size twice. - callee_pop_size: 0, - }), - } - .emit(&[], sink, emit_info, state); - } + if info.opcode.is_call() { + sink.add_call_site(info.opcode); } + sink.add_reloc(Reloc::RiscvCallPlt, &info.dest, 0); + if let Some(s) = state.take_stack_map() { + sink.add_stack_map(StackMapExtent::UpcomingBytes(8), s); + } + Inst::construct_auipc_and_jalr(Some(writable_link_reg()), writable_link_reg(), 0) + .into_iter() + .for_each(|i| i.emit_uncompressed(sink, emit_info, state, start_off)); let callee_pop_size = i64::from(info.callee_pop_size); state.virtual_sp_offset -= callee_pop_size; @@ -1419,7 +1380,7 @@ impl Inst { ); sink.add_call_site(ir::Opcode::ReturnCall); - sink.add_reloc(Reloc::RiscvCall, &**callee, 0); + sink.add_reloc(Reloc::RiscvCallPlt, &**callee, 0); Inst::construct_auipc_and_jalr(None, writable_spilltmp_reg(), 0) .into_iter() .for_each(|i| i.emit_uncompressed(sink, emit_info, state, start_off)); @@ -2309,26 +2270,71 @@ impl Inst { ref name, offset, } => { - let label_data = sink.get_label(); - let label_end = sink.get_label(); + if emit_info.shared_flag.is_pic() { + // Load a PC-relative address into a register. + // RISC-V does this slightly differently from other arches. We emit a relocation + // with a label, instead of the symbol itself. + // + // See: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#pc-relative-symbol-addresses + // + // Emit the following code: + // label: + // auipc rd, 0 # R_RISCV_GOT_HI20 (symbol_name) + // ld rd, rd, 0 # R_RISCV_PCREL_LO12_I (label) + + // Create the lable that is going to be published to the final binary object. + let auipc_label = sink.get_label(); + sink.bind_label(auipc_label, &mut state.ctrl_plane); + + // Get the current PC. + sink.add_reloc(Reloc::RiscvGotHi20, &**name, 0); + Inst::Auipc { + rd: rd, + imm: Imm20::from_i32(0), + } + .emit_uncompressed(sink, emit_info, state, start_off); - // Load the value from a label - Inst::Load { - rd, - op: LoadOP::Ld, - flags: MemFlags::trusted(), - from: AMode::Label(label_data), - } - .emit(&[], sink, emit_info, state); + // The `ld` here, points to the `auipc` label instead of directly to the symbol. + sink.add_reloc(Reloc::RiscvPCRelLo12I, &auipc_label, 0); + Inst::Load { + rd, + op: LoadOP::Ld, + flags: MemFlags::trusted(), + from: AMode::RegOffset(rd.to_reg(), 0, I64), + } + .emit_uncompressed(sink, emit_info, state, start_off); + } else { + // In the non PIC sequence we relocate the absolute address into + // a prealocatted space, load it into a register and jump over it. + // + // Emit the following code: + // ld rd, label_data + // j label_end + // label_data: + // <8 byte space> # ABS8 + // label_end: + + let label_data = sink.get_label(); + let label_end = sink.get_label(); + + // Load the value from a label + Inst::Load { + rd, + op: LoadOP::Ld, + flags: MemFlags::trusted(), + from: AMode::Label(label_data), + } + .emit(&[], sink, emit_info, state); - // Jump over the data - Inst::gen_jump(label_end).emit(&[], sink, emit_info, state); + // Jump over the data + Inst::gen_jump(label_end).emit(&[], sink, emit_info, state); - sink.bind_label(label_data, &mut state.ctrl_plane); - sink.add_reloc(Reloc::Abs8, name.as_ref(), offset); - sink.put8(0); + sink.bind_label(label_data, &mut state.ctrl_plane); + sink.add_reloc(Reloc::Abs8, name.as_ref(), offset); + sink.put8(0); - sink.bind_label(label_end, &mut state.ctrl_plane); + sink.bind_label(label_end, &mut state.ctrl_plane); + } } &Inst::ElfTlsGetAddr { rd, ref name } => { diff --git a/cranelift/codegen/src/isa/riscv64/inst/mod.rs b/cranelift/codegen/src/isa/riscv64/inst/mod.rs index fed91b230321..12d00c319a27 100644 --- a/cranelift/codegen/src/isa/riscv64/inst/mod.rs +++ b/cranelift/codegen/src/isa/riscv64/inst/mod.rs @@ -1991,7 +1991,7 @@ impl MachInstLabelUse for LabelUse { fn from_reloc(reloc: Reloc, addend: Addend) -> Option { match (reloc, addend) { - (Reloc::RiscvCall, _) => Some(Self::PCRel32), + (Reloc::RiscvCallPlt, _) => Some(Self::PCRel32), _ => None, } } diff --git a/cranelift/filetests/filetests/isa/riscv64/call.clif b/cranelift/filetests/filetests/isa/riscv64/call.clif index c97543c7214f..10f17f5599ba 100644 --- a/cranelift/filetests/filetests/isa/riscv64/call.clif +++ b/cranelift/filetests/filetests/isa/riscv64/call.clif @@ -847,7 +847,7 @@ block0(v0: i16): ; addi sp, sp, -0x10 ; block1: ; offset 0x18 ; mv s1, a0 -; auipc ra, 0 ; reloc_external RiscvCall u0:0 0 +; auipc ra, 0 ; reloc_external RiscvCallPlt u0:0 0 ; jalr ra ; mv a0, s1 ; addi sp, sp, 0x10 diff --git a/cranelift/filetests/filetests/isa/riscv64/return-call.clif b/cranelift/filetests/filetests/isa/riscv64/return-call.clif index a119160e1f08..7eb4190dd9f8 100644 --- a/cranelift/filetests/filetests/isa/riscv64/return-call.clif +++ b/cranelift/filetests/filetests/isa/riscv64/return-call.clif @@ -82,7 +82,7 @@ block0(v0: i64): ; ld t6, 0(s0) ; addi sp, s0, 0x10 ; mv s0, t6 -; auipc t6, 0 ; reloc_external RiscvCall %callee_i64 0 +; auipc t6, 0 ; reloc_external RiscvCallPlt %callee_i64 0 ; jr t6 ;;;; Test passing `f64`s ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/cranelift/filetests/filetests/isa/riscv64/simd-abi-large-spill.clif b/cranelift/filetests/filetests/isa/riscv64/simd-abi-large-spill.clif index f8412ce89cde..9e32f3c27075 100644 --- a/cranelift/filetests/filetests/isa/riscv64/simd-abi-large-spill.clif +++ b/cranelift/filetests/filetests/isa/riscv64/simd-abi-large-spill.clif @@ -53,7 +53,7 @@ block0: ; .byte 0x87, 0xd5, 0x0f, 0x02 ; .byte 0x57, 0x70, 0x08, 0xcc ; .byte 0xa7, 0x05, 0x01, 0x02 -; auipc ra, 0 ; reloc_external RiscvCall u2:0 0 +; auipc ra, 0 ; reloc_external RiscvCallPlt u2:0 0 ; jalr ra ; mv a0, s1 ; .byte 0x87, 0x05, 0x01, 0x02 diff --git a/cranelift/filetests/filetests/isa/riscv64/stack-limit.clif b/cranelift/filetests/filetests/isa/riscv64/stack-limit.clif index d33f83bdd740..64fd50b5b5b3 100644 --- a/cranelift/filetests/filetests/isa/riscv64/stack-limit.clif +++ b/cranelift/filetests/filetests/isa/riscv64/stack-limit.clif @@ -216,16 +216,12 @@ block0(v0: i64): ; .byte 0x00, 0x00, 0x00, 0x00 ; trap: stk_ovf ; lui a0, 0x62 ; addi a0, a0, -0x580 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %Probestack 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %Probestack 0 +; jalr ra ; lui t6, 0xfff9e ; addi t6, t6, 0x580 ; add sp, t6, sp -; block1: ; offset 0x58 +; block1: ; offset 0x48 ; lui t6, 0x62 ; addi t6, t6, -0x580 ; add sp, t6, sp @@ -330,16 +326,12 @@ block0(v0: i64): ; .byte 0x00, 0x00, 0x00, 0x00 ; trap: stk_ovf ; lui a0, 0x62 ; addi a0, a0, -0x580 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %Probestack 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %Probestack 0 +; jalr ra ; lui t6, 0xfff9e ; addi t6, t6, 0x580 ; add sp, t6, sp -; block1: ; offset 0x60 +; block1: ; offset 0x50 ; lui t6, 0x62 ; addi t6, t6, -0x580 ; add sp, t6, sp diff --git a/cranelift/filetests/filetests/isa/riscv64/stack.clif b/cranelift/filetests/filetests/isa/riscv64/stack.clif index a5215b51f4c2..1400328f1950 100644 --- a/cranelift/filetests/filetests/isa/riscv64/stack.clif +++ b/cranelift/filetests/filetests/isa/riscv64/stack.clif @@ -74,16 +74,12 @@ block0: ; mv s0, sp ; lui a0, 0x18 ; addi a0, a0, 0x6b0 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %Probestack 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %Probestack 0 +; jalr ra ; lui t6, 0xfffe8 ; addi t6, t6, -0x6b0 ; add sp, t6, sp -; block1: ; offset 0x3c +; block1: ; offset 0x2c ; mv a0, sp ; lui t6, 0x18 ; addi t6, t6, 0x6b0 @@ -164,16 +160,12 @@ block0: ; mv s0, sp ; lui a0, 0x18 ; addi a0, a0, 0x6b0 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %Probestack 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %Probestack 0 +; jalr ra ; lui t6, 0xfffe8 ; addi t6, t6, -0x6b0 ; add sp, t6, sp -; block1: ; offset 0x3c +; block1: ; offset 0x2c ; ld a0, 0(sp) ; lui t6, 0x18 ; addi t6, t6, 0x6b0 @@ -254,16 +246,12 @@ block0(v0: i64): ; mv s0, sp ; lui a0, 0x18 ; addi a0, a0, 0x6b0 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %Probestack 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %Probestack 0 +; jalr ra ; lui t6, 0xfffe8 ; addi t6, t6, -0x6b0 ; add sp, t6, sp -; block1: ; offset 0x3c +; block1: ; offset 0x2c ; sd a0, 0(sp) ; lui t6, 0x18 ; addi t6, t6, 0x6b0 @@ -949,16 +937,12 @@ block0(v0: i128): ; mv s0, sp ; lui a0, 0x18 ; addi a0, a0, 0x6b0 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %Probestack 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %Probestack 0 +; jalr ra ; lui t6, 0xfffe8 ; addi t6, t6, -0x6b0 ; add sp, t6, sp -; block1: ; offset 0x3c +; block1: ; offset 0x2c ; sd a0, 0(sp) ; sd a1, 8(sp) ; lui t6, 0x18 @@ -1083,16 +1067,12 @@ block0: ; mv s0, sp ; lui a0, 0x18 ; addi a0, a0, 0x6b0 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %Probestack 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %Probestack 0 +; jalr ra ; lui t6, 0xfffe8 ; addi t6, t6, -0x6b0 ; add sp, t6, sp -; block1: ; offset 0x3c +; block1: ; offset 0x2c ; ld a0, 0(sp) ; ld a1, 8(sp) ; lui t6, 0x18 diff --git a/cranelift/filetests/filetests/isa/riscv64/symbol-value-pic.clif b/cranelift/filetests/filetests/isa/riscv64/symbol-value-pic.clif new file mode 100644 index 000000000000..049e9717d54e --- /dev/null +++ b/cranelift/filetests/filetests/isa/riscv64/symbol-value-pic.clif @@ -0,0 +1,24 @@ +test compile precise-output +set unwind_info=false +set is_pic +target riscv64 + +function %f() -> i64 { + gv0 = symbol %my_global + +block0: + v0 = symbol_value.i64 gv0 + return v0 +} + +; VCode: +; block0: +; load_sym a0,%my_global+0 +; ret +; +; Disassembled: +; block0: ; offset 0x0 +; auipc a0, 0 ; reloc_external RiscvGotHi20 %my_global 0 +; ld a0, 0(a0) ; reloc_external RiscvPCRelLo12I func+0 0 +; ret + diff --git a/cranelift/filetests/filetests/isa/riscv64/tls-elf.clif b/cranelift/filetests/filetests/isa/riscv64/tls-elf.clif index ab352c4f1b75..85ae4452462a 100644 --- a/cranelift/filetests/filetests/isa/riscv64/tls-elf.clif +++ b/cranelift/filetests/filetests/isa/riscv64/tls-elf.clif @@ -41,12 +41,8 @@ block0(v0: i32): ; mv s1, a0 ; auipc a0, 0 ; reloc_external RiscvTlsGdHi20 u1:0 0 ; mv a0, a0 ; reloc_external RiscvPCRelLo12I func+28 0 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %ElfTlsGetAddr 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %ElfTlsGetAddr 0 +; jalr ra ; mv a1, a0 ; mv a0, s1 ; addi sp, sp, 0x10 @@ -56,8 +52,6 @@ block0(v0: i32): ; addi sp, sp, 0x10 ; ret - - function u0:1(i64) -> i64 system_v { gv0 = symbol colocated tls u1:0 @@ -93,12 +87,8 @@ block0(v0: i64): ; block1: ; offset 0x10 ; auipc a0, 0 ; reloc_external RiscvTlsGdHi20 u1:0 0 ; mv a0, a0 ; reloc_external RiscvPCRelLo12I func+16 0 -; auipc t5, 0 -; ld t5, 0xc(t5) -; j 0xc -; .byte 0x00, 0x00, 0x00, 0x00 ; reloc_external Abs8 %ElfTlsGetAddr 0 -; .byte 0x00, 0x00, 0x00, 0x00 -; jalr t5 +; auipc ra, 0 ; reloc_external RiscvCallPlt %ElfTlsGetAddr 0 +; jalr ra ; mv a4, zero ; sb a4, 0(a0) ; mv a0, zero diff --git a/cranelift/jit/src/compiled_blob.rs b/cranelift/jit/src/compiled_blob.rs index de01855c6d7b..f4f134023ea2 100644 --- a/cranelift/jit/src/compiled_blob.rs +++ b/cranelift/jit/src/compiled_blob.rs @@ -93,8 +93,8 @@ impl CompiledBlob { let imm26 = (diff as u32) << chop >> chop; unsafe { modify_inst32(iptr, |inst| inst | imm26) }; } - Reloc::RiscvCall => { - // A R_RISCV_CALL relocation expects auipc+jalr instruction pair. + Reloc::RiscvCallPlt => { + // A R_RISCV_CALL_PLT 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` diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs index 435ff39856b8..a0aa1e3ae7fa 100644 --- a/cranelift/object/src/backend.rs +++ b/cranelift/object/src/backend.rs @@ -79,11 +79,24 @@ impl ObjectBuilder { binary_format, ))); } - // FIXME(#4994) get the right variant from the TargetIsa + + // FIXME(#4994): Get the right float ABI variant from the TargetIsa + let mut eflags = object::elf::EF_RISCV_FLOAT_ABI_DOUBLE; + + // Set the RVC eflag if we have the C extension enabled. + let has_c = isa + .isa_flags() + .iter() + .filter(|f| f.name == "has_zca" || f.name == "has_zcd") + .all(|f| f.as_bool().unwrap_or_default()); + if has_c { + eflags |= object::elf::EF_RISCV_RVC; + } + file_flags = object::FileFlags::Elf { os_abi: object::elf::ELFOSABI_NONE, abi_version: 0, - e_flags: object::elf::EF_RISCV_RVC | object::elf::EF_RISCV_FLOAT_ABI_DOUBLE, + e_flags: eflags, }; object::Architecture::Riscv64 } @@ -791,14 +804,14 @@ impl ObjectModule { 0, ) } - Reloc::RiscvCall => { + Reloc::RiscvCallPlt => { assert_eq!( self.object.format(), object::BinaryFormat::Elf, - "RiscvCall is not supported for this file format" + "RiscvCallPlt is not supported for this file format" ); ( - RelocationKind::Elf(object::elf::R_RISCV_CALL), + RelocationKind::Elf(object::elf::R_RISCV_CALL_PLT), RelocationEncoding::Generic, 0, ) @@ -827,6 +840,18 @@ impl ObjectModule { 0, ) } + Reloc::RiscvGotHi20 => { + assert_eq!( + self.object.format(), + object::BinaryFormat::Elf, + "RiscvGotHi20 is not supported for this file format" + ); + ( + RelocationKind::Elf(object::elf::R_RISCV_GOT_HI20), + RelocationEncoding::Generic, + 0, + ) + } // FIXME reloc => unimplemented!("{:?}", reloc), };