Skip to content

Commit

Permalink
riscv64: Add GOT relocations for PIC code (#7184)
Browse files Browse the repository at this point in the history
* riscv64: Use `CALL_PLT` relocation for all calls

* riscv64: Set the ELF RVC flag only when the C extension is enabled

* riscv64: Use PC Relative Relocations for all Calls

* riscv64: Add support for PIC symbols
  • Loading branch information
afonso360 authored Oct 9, 2023
1 parent 89449b6 commit ecc1b79
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 146 deletions.
23 changes: 16 additions & 7 deletions cranelift/codegen/src/binemit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
///
Expand All @@ -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
Expand All @@ -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"),
Expand Down
136 changes: 71 additions & 65 deletions cranelift/codegen/src/isa/riscv64/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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 } => {
Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/riscv64/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1991,7 +1991,7 @@ impl MachInstLabelUse for LabelUse {

fn from_reloc(reloc: Reloc, addend: Addend) -> Option<LabelUse> {
match (reloc, addend) {
(Reloc::RiscvCall, _) => Some(Self::PCRel32),
(Reloc::RiscvCallPlt, _) => Some(Self::PCRel32),
_ => None,
}
}
Expand Down
2 changes: 1 addition & 1 deletion cranelift/filetests/filetests/isa/riscv64/call.clif
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cranelift/filetests/filetests/isa/riscv64/return-call.clif
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 6 additions & 14 deletions cranelift/filetests/filetests/isa/riscv64/stack-limit.clif
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
50 changes: 15 additions & 35 deletions cranelift/filetests/filetests/isa/riscv64/stack.clif
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit ecc1b79

Please sign in to comment.