diff --git a/artiq/firmware/libdyld/elf.rs b/artiq/firmware/libdyld/elf.rs index 0385bc768..d8712b9fd 100644 --- a/artiq/firmware/libdyld/elf.rs +++ b/artiq/firmware/libdyld/elf.rs @@ -131,6 +131,7 @@ pub const EM_TILEPRO: u16 = 188; pub const EM_MICROBLAZE: u16 = 189; pub const EM_TILEGX: u16 = 191; pub const EM_NUM: u16 = 192; +pub const EM_RISCV: u16 = 243; pub const EM_ALPHA: u16 = 36902; pub const EV_NONE: u8 = 0; pub const EV_CURRENT: u8 = 1; @@ -2229,6 +2230,61 @@ pub const R_OR1K_TLS_TPOFF: u8 = 32; pub const R_OR1K_TLS_DTPOFF: u8 = 33; pub const R_OR1K_TLS_DTPMOD: u8 = 34; pub const R_OR1K_NUM: u8 = 35; +pub const R_RISCV_NONE: u8 = 0; +pub const R_RISCV_32: u8 = 1; +pub const R_RISCV_64: u8 = 2; +pub const R_RISCV_RELATIVE: u8 = 3; +pub const R_RISCV_COPY: u8 = 4; +pub const R_RISCV_JUMP_SLOT: u8 = 5; +pub const R_RISCV_TLS_DTPMOD32: u8 = 6; +pub const R_RISCV_TLS_DTPMOD64: u8 = 7; +pub const R_RISCV_TLS_DTPREL32: u8 = 8; +pub const R_RISCV_TLS_DTPREL64: u8 = 9; +pub const R_RISCV_TLS_TPREL32: u8 = 10; +pub const R_RISCV_TLS_TPREL64: u8 = 11; +pub const R_RISCV_BRANCH: u8 = 16; +pub const R_RISCV_JAL: u8 = 17; +pub const R_RISCV_CALL: u8 = 18; +pub const R_RISCV_CALL_PLT: u8 = 19; +pub const R_RISCV_GOT_HI20: u8 = 20; +pub const R_RISCV_TLS_GOT_HI20: u8 = 21; +pub const R_RISCV_TLS_GD_HI20: u8 = 22; +pub const R_RISCV_PCREL_HI20: u8 = 23; +pub const R_RISCV_PCREL_LO12_I: u8 = 24; +pub const R_RISCV_PCREL_LO12_S: u8 = 25; +pub const R_RISCV_HI20: u8 = 26; +pub const R_RISCV_LO12_I: u8 = 27; +pub const R_RISCV_LO12_S: u8 = 28; +pub const R_RISCV_TPREL_HI20: u8 = 29; +pub const R_RISCV_TPREL_LO12_I: u8 = 30; +pub const R_RISCV_TPREL_LO12_S: u8 = 31; +pub const R_RISCV_TPREL_ADD: u8 = 32; +pub const R_RISCV_ADD8: u8 = 33; +pub const R_RISCV_ADD16: u8 = 34; +pub const R_RISCV_ADD32: u8 = 35; +pub const R_RISCV_ADD64: u8 = 36; +pub const R_RISCV_SUB8: u8 = 37; +pub const R_RISCV_SUB16: u8 = 38; +pub const R_RISCV_SUB32: u8 = 39; +pub const R_RISCV_SUB64: u8 = 40; +pub const R_RISCV_GNU_VTINHERIT: u8 = 41; +pub const R_RISCV_GNU_VTENTRY: u8 = 42; +pub const R_RISCV_ALIGN: u8 = 43; +pub const R_RISCV_RVC_BRANCH: u8 = 44; +pub const R_RISCV_RVC_JUMP: u8 = 45; +pub const R_RISCV_RVC_LUI: u8 = 46; +pub const R_RISCV_GPREL_I: u8 = 47; +pub const R_RISCV_GPREL_S: u8 = 48; +pub const R_RISCV_TPREL_I: u8 = 49; +pub const R_RISCV_TPREL_S: u8 = 50; +pub const R_RISCV_RELAX: u8 = 51; +pub const R_RISCV_SUB6: u8 = 52; +pub const R_RISCV_SET6: u8 = 53; +pub const R_RISCV_SET8: u8 = 54; +pub const R_RISCV_SET16: u8 = 55; +pub const R_RISCV_SET32: u8 = 56; +pub const R_RISCV_32_PCREL: u8 = 57; +pub const R_RISCV_NUM: u8 = 58; pub type Elf32_Half = u16; pub type Elf64_Half = u16; diff --git a/artiq/firmware/libdyld/lib.rs b/artiq/firmware/libdyld/lib.rs index bbf4f59c5..0788c38d4 100644 --- a/artiq/firmware/libdyld/lib.rs +++ b/artiq/firmware/libdyld/lib.rs @@ -75,9 +75,16 @@ impl<'a> fmt::Display for Error<'a> { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Arch { + RiscV, + OpenRisc, +} + pub struct Library<'a> { image_off: Elf32_Addr, image_sz: usize, + arch: Arch, strtab: &'a [u8], symtab: &'a [Elf32_Sym], pltrel: &'a [Elf32_Rela], @@ -133,8 +140,12 @@ impl<'a> Library<'a> { // This is unsafe because it mutates global data (the PLT). pub unsafe fn rebind(&self, name: &[u8], addr: Elf32_Word) -> Result<(), Error<'a>> { for rela in self.pltrel.iter() { - match ELF32_R_TYPE(rela.r_info) { - R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => { + match (ELF32_R_TYPE(rela.r_info), self.arch) { + (R_OR1K_32, Arch::OpenRisc) | + (R_OR1K_GLOB_DAT, Arch::OpenRisc) | + (R_OR1K_JMP_SLOT, Arch::OpenRisc) | + (R_RISCV_32, Arch::RiscV) | + (R_RISCV_JUMP_SLOT, Arch::RiscV) => { let sym = self.symtab.get(ELF32_R_SYM(rela.r_info) as usize) .ok_or("symbol out of bounds of symbol table")?; let sym_name = self.name_starting_at(sym.st_name as usize)?; @@ -162,14 +173,18 @@ impl<'a> Library<'a> { } let value; - match ELF32_R_TYPE(rela.r_info) { - R_OR1K_NONE => + match (ELF32_R_TYPE(rela.r_info), self.arch) { + (R_OR1K_NONE, Arch::OpenRisc) | (R_RISCV_NONE, Arch::RiscV) => return Ok(()), - R_OR1K_RELATIVE => + (R_OR1K_RELATIVE, Arch::OpenRisc) | (R_RISCV_RELATIVE, Arch::RiscV) => value = self.image_off + rela.r_addend as Elf32_Word, - R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => { + (R_OR1K_32, Arch::OpenRisc) | + (R_OR1K_GLOB_DAT, Arch::OpenRisc) | + (R_OR1K_JMP_SLOT, Arch::OpenRisc) | + (R_RISCV_32, Arch::RiscV) | + (R_RISCV_JUMP_SLOT, Arch::RiscV) => { let sym = sym.ok_or("relocation requires an associated symbol")?; let sym_name = self.name_starting_at(sym.st_name as usize)?; @@ -202,20 +217,7 @@ impl<'a> Library<'a> { let ehdr = read_unaligned::(data, 0) .map_err(|()| "cannot read ELF header")?; - const IDENT: [u8; EI_NIDENT] = [ - ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, - ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE, - /* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0 - ]; - - #[cfg(target_arch = "or1k")] - const ARCH: u16 = EM_OPENRISC; - #[cfg(not(target_arch = "or1k"))] - const ARCH: u16 = EM_NONE; - - if ehdr.e_ident != IDENT || ehdr.e_type != ET_DYN || ehdr.e_machine != ARCH { - return Err("not a shared library for current architecture")? - } + let arch = arch(&ehdr).ok_or("not a shared library for current architecture")?; let mut dyn_off = None; for i in 0..ehdr.e_phnum { @@ -314,6 +316,7 @@ impl<'a> Library<'a> { let library = Library { image_off: image.as_ptr() as Elf32_Word, image_sz: image.len(), + arch: arch, strtab: strtab, symtab: symtab, pltrel: pltrel, @@ -337,3 +340,25 @@ impl<'a> Library<'a> { Ok(library) } } + +fn arch(ehdr: &Elf32_Ehdr) -> Option { + const IDENT_OPENRISC: [u8; EI_NIDENT] = [ + ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, + ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE, + /* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0 + ]; + const IDENT_RISCV: [u8; EI_NIDENT] = [ + ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, + ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, + /* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0 + ]; + match (ehdr.e_ident, ehdr.e_machine) { + #[cfg(target_arch = "riscv32")] + (IDENT_RISCV, EM_RISCV) => Some(Arch::RiscV), + + #[cfg(target_arch = "or1k")] + (IDENT_OPENRISC, EM_OPENRISC) => Some(Arch::OpenRisc), + + _ => None, + } +}