From 0ccc9ce46c85948fc60c6b2172cc31a9b6dcdc71 Mon Sep 17 00:00:00 2001 From: Toru Nayuki Date: Tue, 15 Feb 2022 10:22:24 +0000 Subject: [PATCH] RISC-V support in universal engine --- lib/compiler-llvm/src/object_file.rs | 25 ++++++++++++++- .../src/artifact_builders/trampoline.rs | 21 ++++++++++++ lib/compiler/src/engine/link.rs | 32 +++++++++++++++++++ lib/types/src/compilation/relocation.rs | 13 ++++++-- lib/vm/src/trap/traphandlers.rs | 2 +- 5 files changed, 89 insertions(+), 4 deletions(-) diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs index 1ad0b0a886d..eb182f34d6c 100644 --- a/lib/compiler-llvm/src/object_file.rs +++ b/lib/compiler-llvm/src/object_file.rs @@ -197,6 +197,16 @@ where object::RelocationKind::Elf(object::elf::R_RISCV_CALL_PLT), 0, ) => RelocationKind::RiscvCall, + ( + object::Architecture::Riscv64, + object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_HI20), + 0, + ) => RelocationKind::RiscvPCRelHi20, + ( + object::Architecture::Riscv64, + object::RelocationKind::Elf(object::elf::R_RISCV_PCREL_LO12_I), + 0, + ) => RelocationKind::RiscvPCRelLo12I, _ => { return Err(CompileError::Codegen(format!( "unknown relocation {:?}", @@ -204,7 +214,7 @@ where ))); } }; - let addend = reloc.addend(); + let mut addend = reloc.addend(); let target = match reloc.target() { object::read::RelocationTarget::Symbol(index) => { let symbol = elf.symbol_by_index(index).map_err(map_object_err)?; @@ -235,6 +245,19 @@ where symbol_name_to_relocation_target(symbol_name)? { reloc_target + } else if let object::SymbolSection::Section(section_index) = symbol.section() { + // TODO: Encode symbol address into addend, I think this is a bit hacky. + addend = addend.wrapping_add(symbol.address() as i64); + + if section_index == root_section_index { + root_section_reloc_target + } else { + if visited.insert(section_index) { + worklist.push(section_index); + } + + elf_section_to_target(section_index) + } } else { return Err(CompileError::Codegen(format!( "relocation targets unknown symbol {:?}", diff --git a/lib/compiler/src/artifact_builders/trampoline.rs b/lib/compiler/src/artifact_builders/trampoline.rs index 5a7de39c118..b3b49733df7 100644 --- a/lib/compiler/src/artifact_builders/trampoline.rs +++ b/lib/compiler/src/artifact_builders/trampoline.rs @@ -25,6 +25,17 @@ const X86_64_TRAMPOLINE: [u8; 16] = [ 0xff, 0x25, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; +// can it be shorter than this? +// 4 padding bytes are used to preserve alignment. +// AUIPC t1,0 17 03 00 00 +// LD t1, 16(t1) 03 33 03 01 +// JR t1 67 00 03 00 [00 00 00 00] +// JMPADDR 00 00 00 00 00 00 00 00 +const RISCV64_TRAMPOLINE: [u8; 24] = [ + 0x17, 0x03, 0x00, 0x00, 0x03, 0x33, 0x03, 0x01, 0x67, 0x00, 0x03, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +]; + fn make_trampoline( target: &Target, libcall: LibCall, @@ -50,6 +61,15 @@ fn make_trampoline( addend: 0, }); } + Architecture::Riscv64(_) => { + code.extend(&RISCV64_TRAMPOLINE); + relocations.push(Relocation { + kind: RelocationKind::Abs8, + reloc_target: RelocationTarget::LibCall(libcall), + offset: code.len() as u32 - 8, + addend: 0, + }); + } arch => panic!("Unsupported architecture: {}", arch), }; } @@ -59,6 +79,7 @@ pub fn libcall_trampoline_len(target: &Target) -> usize { match target.triple().architecture { Architecture::Aarch64(_) => AARCH64_TRAMPOLINE.len(), Architecture::X86_64 => X86_64_TRAMPOLINE.len(), + Architecture::Riscv64(_) => RISCV64_TRAMPOLINE.len(), arch => panic!("Unsupported architecture: {}", arch), } } diff --git a/lib/compiler/src/engine/link.rs b/lib/compiler/src/engine/link.rs index 153d581b446..2ddf1173759 100644 --- a/lib/compiler/src/engine/link.rs +++ b/lib/compiler/src/engine/link.rs @@ -2,6 +2,7 @@ use crate::get_libcall_trampoline; use crate::FunctionExtent; +use std::collections::HashMap; use std::ptr::{read_unaligned, write_unaligned}; use wasmer_types::entity::PrimaryMap; use wasmer_types::{LocalFunctionIndex, ModuleInfo}; @@ -16,6 +17,7 @@ fn apply_relocation( allocated_sections: &PrimaryMap, libcall_trampolines: SectionIndex, libcall_trampoline_len: usize, + riscv_pcrel_hi20s: &mut HashMap, ) { let target_func_address: usize = match r.reloc_target { RelocationTarget::LocalFunc(index) => *allocated_functions[index].ptr as usize, @@ -93,6 +95,32 @@ fn apply_relocation( | read_unaligned(reloc_address as *mut u32); write_unaligned(reloc_address as *mut u32, reloc_delta); }, + RelocationKind::RiscvPCRelHi20 => unsafe { + let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64); + + // save for later reference with RiscvPCRelLo12I + riscv_pcrel_hi20s.insert(reloc_address, reloc_delta as u32); + + let reloc_delta = ((reloc_delta.wrapping_add(0x800) & 0xfffff000) as u32) + | read_unaligned(reloc_address as *mut u32); + write_unaligned(reloc_address as *mut u32, reloc_delta); + }, + RelocationKind::RiscvPCRelLo12I => unsafe { + let (reloc_address, reloc_abs) = r.for_address(body, target_func_address as u64); + let reloc_delta = ((riscv_pcrel_hi20s.get(&(reloc_abs as usize)).expect( + "R_RISCV_PCREL_LO12_I relocation target must be a symbol with R_RISCV_PCREL_HI20", + ) & 0xfff) + << 20) + | read_unaligned(reloc_address as *mut u32); + write_unaligned(reloc_address as *mut u32, reloc_delta); + }, + RelocationKind::RiscvCall => unsafe { + let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64); + let reloc_delta = ((reloc_delta & 0xfff) << 52) + | (reloc_delta.wrapping_add(0x800) & 0xfffff000) + | read_unaligned(reloc_address as *mut u64); + write_unaligned(reloc_address as *mut u64, reloc_delta); + }, kind => panic!( "Relocation kind unsupported in the current architecture {}", kind @@ -111,6 +139,8 @@ pub fn link_module( libcall_trampolines: SectionIndex, trampoline_len: usize, ) { + let mut riscv_pcrel_hi20s: HashMap = HashMap::new(); + for (i, section_relocs) in section_relocations.iter() { let body = *allocated_sections[i] as usize; for r in section_relocs { @@ -121,6 +151,7 @@ pub fn link_module( allocated_sections, libcall_trampolines, trampoline_len, + &mut riscv_pcrel_hi20s, ); } } @@ -134,6 +165,7 @@ pub fn link_module( allocated_sections, libcall_trampolines, trampoline_len, + &mut riscv_pcrel_hi20s, ); } } diff --git a/lib/types/src/compilation/relocation.rs b/lib/types/src/compilation/relocation.rs index 84c63c2d8c8..b1a18e42da0 100644 --- a/lib/types/src/compilation/relocation.rs +++ b/lib/types/src/compilation/relocation.rs @@ -50,6 +50,10 @@ pub enum RelocationKind { Arm64Movw2, /// Arm64 movk/z part 3 Arm64Movw3, + /// RISC-V PC-relative high 20bit + RiscvPCRelHi20, + /// RISC-V PC-relative low 12bit, I-type + RiscvPCRelLo12I, /// RISC-V call target RiscvCall, /// Elf x86_64 32 bit signed PC relative offset to two GOT entries for GD symbol. @@ -76,6 +80,8 @@ impl fmt::Display for RelocationKind { Self::Arm64Movw2 => write!(f, "Arm64MovwG2"), Self::Arm64Movw3 => write!(f, "Arm64MovwG3"), Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"), + Self::RiscvPCRelHi20 => write!(f, "RiscvPCRelHi20"), + Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"), // Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"), } } @@ -119,7 +125,8 @@ impl Relocation { | RelocationKind::Arm64Movw0 | RelocationKind::Arm64Movw1 | RelocationKind::Arm64Movw2 - | RelocationKind::Arm64Movw3 => { + | RelocationKind::Arm64Movw3 + | RelocationKind::RiscvPCRelLo12I => { let reloc_address = start + self.offset as usize; let reloc_addend = self.addend as isize; let reloc_abs = target_func_address @@ -153,7 +160,9 @@ impl Relocation { .wrapping_add(reloc_addend as u32); (reloc_address, reloc_delta_u32 as u64) } - RelocationKind::Arm64Call | RelocationKind::RiscvCall => { + RelocationKind::Arm64Call + | RelocationKind::RiscvCall + | RelocationKind::RiscvPCRelHi20 => { let reloc_address = start + self.offset as usize; let reloc_addend = self.addend as isize; let reloc_delta_u32 = target_func_address diff --git a/lib/vm/src/trap/traphandlers.rs b/lib/vm/src/trap/traphandlers.rs index ce892a596b5..fc8af76fcfc 100644 --- a/lib/vm/src/trap/traphandlers.rs +++ b/lib/vm/src/trap/traphandlers.rs @@ -1053,4 +1053,4 @@ pub fn lazy_per_thread_init() -> Result<(), Trap> { } } } -} \ No newline at end of file +}