Skip to content

Commit 478ec8a

Browse files
authored
Merge pull request gz#40 from landhb/riscv64
Add RISCV Support
2 parents 85fab0c + 365857a commit 478ec8a

File tree

7 files changed

+331
-1
lines changed

7 files changed

+331
-1
lines changed

src/arch/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{ElfLoaderErr, Machine};
22

33
pub mod aarch64;
44
pub mod arm;
5+
pub mod riscv;
56
pub mod x86;
67
pub mod x86_64;
78

@@ -15,6 +16,7 @@ pub enum RelocationType {
1516
x86_64(x86_64::RelocationTypes),
1617
Arm(arm::RelocationTypes),
1718
AArch64(aarch64::RelocationTypes),
19+
RiscV(riscv::RelocationTypes),
1820
}
1921

2022
impl RelocationType {
@@ -25,6 +27,7 @@ impl RelocationType {
2527
Machine::X86_64 => RelocationType::x86_64(x86_64::RelocationTypes::from(type_num)),
2628
Machine::Arm => RelocationType::Arm(arm::RelocationTypes::from(type_num)),
2729
Machine::AArch64 => RelocationType::AArch64(aarch64::RelocationTypes::from(type_num)),
30+
Machine::RISC_V => RelocationType::RiscV(riscv::RelocationTypes::from(type_num)),
2831
_ => return Err(ElfLoaderErr::UnsupportedArchitecture),
2932
};
3033
Ok(typ)

src/arch/riscv/mod.rs

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
//! RISCV relocation types
2+
//!
3+
4+
#[cfg(test)]
5+
mod test;
6+
7+
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
8+
#[allow(non_camel_case_types)]
9+
#[repr(u32)]
10+
pub enum RelocationTypes {
11+
/// No relocation.
12+
R_RISCV_NONE,
13+
/// Add 32 bit zero extended symbol value
14+
R_RISCV_32,
15+
/// Add 64 bit symbol value.
16+
R_RISCV_64,
17+
/// Add load address of shared object.
18+
R_RISCV_RELATIVE,
19+
/// Copy data from shared object.
20+
R_RISCV_COPY,
21+
/// Set GOT entry to code address.
22+
R_RISCV_JUMP_SLOT,
23+
/// 32 bit ID of module containing symbol
24+
R_RISCV_TLS_DTPMOD32,
25+
/// ID of module containing symbol
26+
R_RISCV_TLS_DTPMOD64,
27+
/// 32 bit relative offset in TLS block
28+
R_RISCV_TLS_DTPREL32,
29+
/// Relative offset in TLS block
30+
R_RISCV_TLS_DTPREL64,
31+
/// 32 bit relative offset in static TLS block
32+
R_RISCV_TLS_TPREL32,
33+
/// Relative offset in static TLS block
34+
R_RISCV_TLS_TPREL64,
35+
/// PC-relative branch
36+
R_RISCV_BRANCH,
37+
/// PC-relative jump
38+
R_RISCV_JAL,
39+
/// PC-relative call
40+
R_RISCV_CALL,
41+
/// PC-relative call (PLT)
42+
R_RISCV_CALL_PLT,
43+
/// PC-relative GOT reference
44+
R_RISCV_GOT_HI20,
45+
/// PC-relative TLS IE GOT offset
46+
R_RISCV_TLS_GOT_HI20,
47+
/// PC-relative TLS GD reference
48+
R_RISCV_TLS_GD_HI20,
49+
/// PC-relative reference
50+
R_RISCV_PCREL_HI20,
51+
/// PC-relative reference
52+
R_RISCV_PCREL_LO12_I,
53+
/// PC-relative reference
54+
R_RISCV_PCREL_LO12_S,
55+
/// Absolute address
56+
R_RISCV_HI20,
57+
/// Absolute address
58+
R_RISCV_LO12_I,
59+
/// Absolute address
60+
R_RISCV_LO12_S,
61+
/// TLS LE thread offset
62+
R_RISCV_TPREL_HI20,
63+
/// TLS LE thread offset
64+
R_RISCV_TPREL_LO12_I,
65+
/// TLS LE thread offset
66+
R_RISCV_TPREL_LO12_S,
67+
/// TLS LE thread usage
68+
R_RISCV_TPREL_ADD,
69+
/// 8-bit label addition
70+
R_RISCV_ADD8,
71+
/// 16-bit label addition
72+
R_RISCV_ADD16,
73+
/// 32-bit label addition
74+
R_RISCV_ADD32,
75+
/// 64-bit label addition
76+
R_RISCV_ADD64,
77+
/// 8-bit label subtraction
78+
R_RISCV_SUB8,
79+
/// 16-bit label subtraction
80+
R_RISCV_SUB16,
81+
/// 32-bit label subtraction
82+
R_RISCV_SUB32,
83+
/// 64-bit label subtraction
84+
R_RISCV_SUB64,
85+
/// GNU C++ vtable hierarchy
86+
R_RISCV_GNU_VTINHERIT,
87+
/// GNU C++ vtable member usage
88+
R_RISCV_GNU_VTENTRY,
89+
/// Alignment statement
90+
R_RISCV_ALIGN,
91+
/// PC-relative branch offset
92+
R_RISCV_RVC_BRANCH,
93+
/// PC-relative jump offset
94+
R_RISCV_RVC_JUMP,
95+
/// Absolute address
96+
R_RISCV_RVC_LUI,
97+
/// GP-relative reference
98+
R_RISCV_GPREL_I,
99+
/// GP-relative reference
100+
R_RISCV_GPREL_S,
101+
/// TP-relative TLS LE load
102+
R_RISCV_TPREL_I,
103+
/// TP-relative TLS LE store
104+
R_RISCV_TPREL_S,
105+
/// Instruction pair can be relaxed
106+
R_RISCV_RELAX,
107+
/// Local label subtraction
108+
R_RISCV_SUB6,
109+
/// Local label subtraction
110+
R_RISCV_SET6,
111+
/// Local label subtraction
112+
R_RISCV_SET8,
113+
/// Local label subtraction
114+
R_RISCV_SET16,
115+
/// Local label subtraction
116+
R_RISCV_SET32,
117+
118+
/// Unknown
119+
Unknown(u32),
120+
}
121+
122+
impl RelocationTypes {
123+
/// Construct new riscv::RelocationTypes
124+
pub fn from(typ: u32) -> RelocationTypes {
125+
use RelocationTypes::*;
126+
match typ {
127+
0 => R_RISCV_NONE,
128+
1 => R_RISCV_32,
129+
2 => R_RISCV_64,
130+
3 => R_RISCV_RELATIVE,
131+
4 => R_RISCV_COPY,
132+
5 => R_RISCV_JUMP_SLOT,
133+
6 => R_RISCV_TLS_DTPMOD32,
134+
7 => R_RISCV_TLS_DTPMOD64,
135+
8 => R_RISCV_TLS_DTPREL32,
136+
9 => R_RISCV_TLS_DTPREL64,
137+
10 => R_RISCV_TLS_TPREL32,
138+
11 => R_RISCV_TLS_TPREL64,
139+
16 => R_RISCV_BRANCH,
140+
17 => R_RISCV_JAL,
141+
18 => R_RISCV_CALL,
142+
19 => R_RISCV_CALL_PLT,
143+
20 => R_RISCV_GOT_HI20,
144+
21 => R_RISCV_TLS_GOT_HI20,
145+
22 => R_RISCV_TLS_GD_HI20,
146+
23 => R_RISCV_PCREL_HI20,
147+
24 => R_RISCV_PCREL_LO12_I,
148+
25 => R_RISCV_PCREL_LO12_S,
149+
26 => R_RISCV_HI20,
150+
27 => R_RISCV_LO12_I,
151+
28 => R_RISCV_LO12_S,
152+
29 => R_RISCV_TPREL_HI20,
153+
30 => R_RISCV_TPREL_LO12_I,
154+
31 => R_RISCV_TPREL_LO12_S,
155+
32 => R_RISCV_TPREL_ADD,
156+
33 => R_RISCV_ADD8,
157+
34 => R_RISCV_ADD16,
158+
35 => R_RISCV_ADD32,
159+
36 => R_RISCV_ADD64,
160+
37 => R_RISCV_SUB8,
161+
38 => R_RISCV_SUB16,
162+
39 => R_RISCV_SUB32,
163+
40 => R_RISCV_SUB64,
164+
41 => R_RISCV_GNU_VTINHERIT,
165+
42 => R_RISCV_GNU_VTENTRY,
166+
43 => R_RISCV_ALIGN,
167+
44 => R_RISCV_RVC_BRANCH,
168+
45 => R_RISCV_RVC_JUMP,
169+
46 => R_RISCV_RVC_LUI,
170+
47 => R_RISCV_GPREL_I,
171+
48 => R_RISCV_GPREL_S,
172+
49 => R_RISCV_TPREL_I,
173+
50 => R_RISCV_TPREL_S,
174+
51 => R_RISCV_RELAX,
175+
52 => R_RISCV_SUB6,
176+
53 => R_RISCV_SET6,
177+
54 => R_RISCV_SET8,
178+
55 => R_RISCV_SET16,
179+
56 => R_RISCV_SET32,
180+
x => Unknown(x),
181+
}
182+
}
183+
}

src/arch/riscv/test.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
use std::fs;
2+
3+
use crate::arch::test::*;
4+
use crate::*;
5+
6+
#[test]
7+
fn load_pie_elf() {
8+
init();
9+
let binary_blob = fs::read("test/test.riscv64").expect("Can't read binary");
10+
let binary = ElfBinary::new(binary_blob.as_slice()).expect("Got proper ELF file");
11+
12+
assert!(binary.is_pie());
13+
14+
let mut loader = TestLoader::new(0x1000_0000);
15+
binary.load(&mut loader).expect("Can't load?");
16+
17+
for action in loader.actions.iter() {
18+
println!("{:?}", action);
19+
}
20+
21+
// View allocate/load actions with readelf -l [binary]
22+
// Program Headers:
23+
// Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
24+
// PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x000188 0x000188 R 0x8
25+
// INTERP 0x0001c8 0x00000000000001c8 0x00000000000001c8 0x00001a 0x00001a R 0x1
26+
// [Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
27+
// LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000780 0x000780 R E 0x10000
28+
// LOAD 0x000e20 0x0000000000001e20 0x0000000000001e20 0x000250 0x000288 RW 0x10000
29+
// DYNAMIC 0x000e30 0x0000000000001e30 0x0000000000001e30 0x0001d0 0x0001d0 RW 0x8
30+
assert_eq!(
31+
loader.actions[0],
32+
LoaderAction::Allocate(VAddr::from(0x0u64), 0x780, Flags(1 | 4))
33+
);
34+
assert_eq!(
35+
loader.actions[1],
36+
LoaderAction::Allocate(VAddr::from(0x1e20u64), 0x288, Flags(0b110))
37+
);
38+
assert_eq!(
39+
loader.actions[2],
40+
LoaderAction::Load(VAddr::from(0x0u64), 0x780)
41+
);
42+
assert_eq!(
43+
loader.actions[3],
44+
LoaderAction::Load(VAddr::from(0x1e20u64), 0x250)
45+
);
46+
47+
// View relocation actions with readelf -r [binary]
48+
//
49+
// Relocation section '.rela.dyn' at offset 0x420 contains 11 entries:
50+
// Offset Info Type Sym. Value Sym. Name + Addend
51+
// 000000001e20 000000000003 R_RISCV_RELATIVE 6ac
52+
// 000000001e28 000000000003 R_RISCV_RELATIVE 644
53+
// 000000002000 000000000003 R_RISCV_RELATIVE 2000
54+
// 000000002058 000000000003 R_RISCV_RELATIVE 6e0
55+
// 000000002030 000300000002 R_RISCV_64 0000000000000000 __cxa_finalize + 0
56+
// 000000002038 000400000002 R_RISCV_64 0000000000000000 _init + 0
57+
// 000000002040 000500000002 R_RISCV_64 0000000000000000 __deregister_fram[...] + 0
58+
// 000000002048 000600000002 R_RISCV_64 0000000000000000 _ITM_registerTMCl[...] + 0
59+
// 000000002050 000700000002 R_RISCV_64 0000000000000000 _ITM_deregisterTM[...] + 0
60+
// 000000002060 000800000002 R_RISCV_64 0000000000000000 _fini + 0
61+
// 000000002068 000a00000002 R_RISCV_64 0000000000000000 __register_frame_info + 0
62+
//
63+
// Relocation section '.rela.plt' at offset 0x528 contains 2 entries:
64+
// Offset Info Type Sym. Value Sym. Name + Addend
65+
// 000000002018 000200000005 R_RISCV_JUMP_SLOT 0000000000000000 printf + 0
66+
// 000000002020 000900000005 R_RISCV_JUMP_SLOT 0000000000000000 __libc_start_main + 0
67+
assert_eq!(
68+
loader.actions[4],
69+
LoaderAction::Relocate(0x1000_0000 + 0x1e20, 0x1000_06ac)
70+
);
71+
assert_eq!(
72+
loader.actions[5],
73+
LoaderAction::Relocate(0x1000_0000 + 0x1e28, 0x1000_0644)
74+
);
75+
assert_eq!(
76+
loader.actions[6],
77+
LoaderAction::Relocate(0x1000_0000 + 0x2000, 0x1000_2000)
78+
);
79+
assert_eq!(
80+
loader.actions[7],
81+
LoaderAction::Relocate(0x1000_0000 + 0x2058, 0x1000_06e0)
82+
);
83+
84+
assert_eq!(loader.actions.len(), 8);
85+
}
86+
87+
#[test]
88+
fn check_nopie() {
89+
init();
90+
let binary_blob = fs::read("test/test_nopie.riscv64").expect("Can't read binary");
91+
let binary = ElfBinary::new(binary_blob.as_slice()).expect("Got proper ELF file");
92+
93+
assert!(!binary.is_pie());
94+
}
95+
96+
#[test]
97+
fn check_tls() {
98+
init();
99+
100+
let binary_blob = fs::read("test/tls.riscv64").expect("Can't read binary");
101+
let binary = ElfBinary::new(binary_blob.as_slice()).expect("Got proper ELF file");
102+
let mut loader = TestLoader::new(0x1000_0000);
103+
binary.load(&mut loader).expect("Can't load?");
104+
/*
105+
readelf -l test/tls.riscv64
106+
TLS produces entries of this form:
107+
pheader = Program header:
108+
type: Ok(Tls)
109+
flags: R
110+
offset: 0xe20
111+
virtual address: 0x1e0c
112+
physical address: 0x1e0c
113+
file size: 0x4
114+
memory size: 0x8
115+
align: 0x4
116+
117+
File size is 0x4 because we have one tdata entry; memory size
118+
is 8 because we also have one bss entry that needs to be written with zeroes.
119+
So to initialize TLS: we allocate zeroed memory of size `memory size`, then copy
120+
file size starting at virtual address in the beginning.
121+
*/
122+
assert!(loader
123+
.actions
124+
.iter()
125+
.find(|&&x| x == LoaderAction::Tls(VAddr::from(0x1e0cu64), 0x4, 0x8, 0x4))
126+
.is_some());
127+
}

src/arch/test.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ impl ElfLoader for TestLoader {
4444

4545
fn relocate(&mut self, entry: RelocationEntry) -> Result<(), ElfLoaderErr> {
4646
use crate::arch::aarch64::RelocationTypes::*;
47+
use crate::arch::riscv::RelocationTypes::*;
4748
use crate::arch::x86::RelocationTypes::*;
4849
use crate::arch::x86_64::RelocationTypes::*;
49-
use RelocationType::{x86, x86_64, AArch64};
50+
use RelocationType::{x86, x86_64, AArch64, RiscV};
5051

5152
// Get the pointer to where the relocation happens in the
5253
// memory where we loaded the headers
@@ -72,6 +73,22 @@ impl ElfLoader for TestLoader {
7273
Ok(())
7374
}
7475
x86(R_386_NONE) => Ok(()),
76+
// RISCV
77+
RiscV(R_RISCV_64) => Ok(()),
78+
RiscV(R_RISCV_NONE) => Ok(()),
79+
RiscV(R_RISCV_RELATIVE) => {
80+
// This type requires addend to be present
81+
let addend = entry
82+
.addend
83+
.ok_or(ElfLoaderErr::UnsupportedRelocationEntry)?;
84+
85+
// This is a relative relocation, add the offset (where we put our
86+
// binary in the vspace) to the addend and we're done.
87+
self.actions
88+
.push(LoaderAction::Relocate(addr as u64, self.vbase + addend));
89+
trace!("R_RELATIVE *{:p} = {:#x}", addr, self.vbase + addend);
90+
Ok(())
91+
}
7592

7693
// x86_64
7794
x86_64(R_AMD64_64) => {

test/test.riscv64

7.55 KB
Binary file not shown.

test/test_nopie.riscv64

108 KB
Binary file not shown.

test/tls.riscv64

7.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)