Skip to content

Commit 6579bf4

Browse files
committed
Misc
1 parent 7140d54 commit 6579bf4

2 files changed

Lines changed: 48 additions & 101 deletions

File tree

harm/src/reloc.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
1-
/* Copyright (C) 2025 Ivan Boldyrev
1+
/* Copyright (C) 2026 Ivan Boldyrev
22
*
33
* This document is licensed under the BSD 3-clause license.
44
*/
55

6+
//! AArch64 instruction relocations.
7+
//!
8+
//! This module defines relocation types used by the `harm` project, and code to apply them to instructions.
9+
//!
10+
//! There relocations follow the static AArch64 ELF relocation types. It is important to note that while the spec
11+
//! uses `S+A` for destination address, this module assumes that `A` is already added to the symbol address.
12+
//!
13+
//! The functions do not require the memory to be in place. The functions' parameters are:
14+
//! - `base`: the base (starting) address of the memory. This can be different from the real memory location for
15+
//! flexibility: the memory can be moved to final location later, even to another host.
16+
//! - `value`: the real target address ('S+A').
17+
//! - `memory`: the memory mutable slice to apply the relocation to.
18+
//! - `offset`: the offset in the memory to apply the relocation at.
19+
//!
20+
//! So, `P` in the spec is `base + offset`, and the memory to be modified starts from `&memory[offset]`.
21+
622
mod addr;
723
mod control;
824
mod data;
@@ -28,7 +44,6 @@ pub type Offset = i64;
2844

2945
pub type Addr = u64;
3046

31-
// b_cond(Cond, LabelRef)
3247
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3348
pub struct LabelRef {
3449
pub id: LabelId,
@@ -250,7 +265,7 @@ impl From<BitError> for Rel64Error {
250265
}
251266
}
252267

253-
#[derive(Debug, Clone, PartialEq, Eq)]
268+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
254269
pub enum Rel64Tag {
255270
None,
256271
// Static data relocations
@@ -279,9 +294,8 @@ pub enum Rel64Tag {
279294
TstBr14,
280295
CondBr19,
281296
Jump26,
282-
Call26, // same as Jump26 actually?
297+
Call26, // same as Jump26 actually
283298

284-
// TODO `MOVW` and some `add`/`ldst`-related relocations
285299
MovWAbsG0,
286300
MovWAbsG0Nc,
287301
MovWAbsG0S,
@@ -297,7 +311,7 @@ pub enum Rel64Tag {
297311
impl Rel64Tag {
298312
/// Applies the relocation in the `memory` at the `offset`, presuming the real target address ('S+A') is `value`,
299313
/// presuming that base (starting) address of the `memory` is `base` (the can be different from real `memory`
300-
/// location for flexibility: the memory can be translated on another host).
314+
/// location for flexibility: the memory can be moved to real destination later).
301315
pub fn apply(
302316
self,
303317
base: Addr,
@@ -454,7 +468,6 @@ mod tests {
454468
Rel64Tag::PRel64
455469
.apply(0x1000, 0x123456789abcdef0, &mut mem, 0)
456470
.unwrap();
457-
// TODO is it correct?
458471
assert_eq!(
459472
mem,
460473
0x123456789abcdef0u64.wrapping_sub(0x1000).to_le_bytes()

harm/src/reloc/movs.rs

Lines changed: 28 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -17,138 +17,88 @@ const MOV_IMM16_OFFSET: u32 = 5;
1717
const MOV_IMM16_WIDTH: u32 = 16;
1818

1919
pub fn mov_w_abs_g0_reloc(value: u64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
20-
const INST_MASK: u32 = ((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET;
21-
2220
let target: u16 = value.try_into()?;
2321
let bytes = get_bytes_mut(mem, offset)?;
24-
25-
let mut inst_code = InstructionCode(*bytes).unpack();
26-
inst_code &= !INST_MASK;
27-
inst_code |= (target as u32) << MOV_IMM16_OFFSET;
28-
*bytes = InstructionCode::from_u32(inst_code).0;
29-
22+
patch_mov(target, bytes);
3023
Ok(())
3124
}
3225

3326
pub fn mov_w_abs_g0nc_reloc(value: u64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
34-
const INST_MASK: u32 = ((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET;
35-
3627
let target = value as u16;
3728
let bytes = get_bytes_mut(mem, offset)?;
38-
39-
let mut inst_code = InstructionCode(*bytes).unpack();
40-
inst_code &= !INST_MASK;
41-
inst_code |= (target as u32) << MOV_IMM16_OFFSET;
42-
*bytes = InstructionCode::from_u32(inst_code).0;
43-
29+
patch_mov(target, bytes);
4430
Ok(())
4531
}
4632

4733
pub fn mov_w_abs_g0s_reloc(value: i64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
48-
const INST_MASK: u32 = (((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET)
49-
| (((1 << MOV_OPCODE_WIDTH) - 1) << MOV_OPCODE_OFFSET);
50-
5134
let target: i16 = value.try_into()?;
5235
let bytes = get_bytes_mut(mem, offset)?;
53-
54-
let mut inst_code = InstructionCode(*bytes).unpack();
55-
inst_code &= !INST_MASK;
56-
if target < 0 {
57-
inst_code |= ((!target as u16) as u32) << MOV_IMM16_OFFSET;
58-
inst_code |= MOV_OPCODE_MOVN << MOV_OPCODE_OFFSET;
59-
} else {
60-
inst_code |= ((target as u16) as u32) << MOV_IMM16_OFFSET;
61-
inst_code |= MOV_OPCODE_MOVZ << MOV_OPCODE_OFFSET;
62-
}
63-
*bytes = InstructionCode::from_u32(inst_code).0;
64-
36+
patch_mov_signed(target, bytes);
6537
Ok(())
6638
}
6739

6840
pub fn mov_w_abs_g1_reloc(value: u64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
69-
const INST_MASK: u32 = ((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET;
70-
7141
let target: u16 = (value >> 16).try_into()?;
7242
let bytes = get_bytes_mut(mem, offset)?;
73-
74-
let mut inst_code = InstructionCode(*bytes).unpack();
75-
inst_code &= !INST_MASK;
76-
inst_code |= (target as u32) << MOV_IMM16_OFFSET;
77-
*bytes = InstructionCode::from_u32(inst_code).0;
78-
43+
patch_mov(target, bytes);
7944
Ok(())
8045
}
8146

8247
pub fn mov_w_abs_g1nc_reloc(value: u64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
83-
const INST_MASK: u32 = ((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET;
84-
8548
let target = (value >> 16) as u16;
8649
let bytes = get_bytes_mut(mem, offset)?;
87-
88-
let mut inst_code = InstructionCode(*bytes).unpack();
89-
inst_code &= !INST_MASK;
90-
inst_code |= (target as u32) << MOV_IMM16_OFFSET;
91-
*bytes = InstructionCode::from_u32(inst_code).0;
92-
50+
patch_mov(target, bytes);
9351
Ok(())
9452
}
9553

9654
pub fn mov_w_abs_g1s_reloc(value: i64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
97-
const INST_MASK: u32 = (((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET)
98-
| (((1 << MOV_OPCODE_WIDTH) - 1) << MOV_OPCODE_OFFSET);
99-
10055
let target: i16 = (value >> 16).try_into()?;
10156
let bytes = get_bytes_mut(mem, offset)?;
102-
103-
let mut inst_code = InstructionCode(*bytes).unpack();
104-
inst_code &= !INST_MASK;
105-
if target < 0 {
106-
inst_code |= ((!target as u16) as u32) << MOV_IMM16_OFFSET;
107-
inst_code |= MOV_OPCODE_MOVN << MOV_OPCODE_OFFSET;
108-
} else {
109-
inst_code |= ((target as u16) as u32) << MOV_IMM16_OFFSET;
110-
inst_code |= MOV_OPCODE_MOVZ << MOV_OPCODE_OFFSET;
111-
}
112-
*bytes = InstructionCode::from_u32(inst_code).0;
113-
57+
patch_mov_signed(target, bytes);
11458
Ok(())
11559
}
11660

11761
pub fn mov_w_abs_g2_reloc(value: u64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
118-
const INST_MASK: u32 = ((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET;
119-
12062
let target: u16 = (value >> 32).try_into()?;
12163
let bytes = get_bytes_mut(mem, offset)?;
122-
123-
let mut inst_code = InstructionCode(*bytes).unpack();
124-
inst_code &= !INST_MASK;
125-
inst_code |= (target as u32) << MOV_IMM16_OFFSET;
126-
*bytes = InstructionCode::from_u32(inst_code).0;
127-
64+
patch_mov(target, bytes);
12865
Ok(())
12966
}
13067

13168
pub fn mov_w_abs_g2nc_reloc(value: u64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
132-
const INST_MASK: u32 = ((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET;
133-
13469
let target = (value >> 32) as u16;
13570
let bytes = get_bytes_mut(mem, offset)?;
71+
patch_mov(target, bytes);
72+
Ok(())
73+
}
74+
75+
pub fn mov_w_abs_g2s_reloc(value: i64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
76+
let target: i16 = (value >> 32).try_into()?;
77+
let bytes = get_bytes_mut(mem, offset)?;
78+
patch_mov_signed(target, bytes);
79+
Ok(())
80+
}
81+
82+
pub fn mov_w_abs_g3_reloc(value: u64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
83+
let target = (value >> 48) as u16;
84+
let bytes = get_bytes_mut(mem, offset)?;
85+
patch_mov(target, bytes);
86+
Ok(())
87+
}
88+
89+
fn patch_mov(target: u16, bytes: &mut [u8; 4]) {
90+
const INST_MASK: u32 = ((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET;
13691

13792
let mut inst_code = InstructionCode(*bytes).unpack();
13893
inst_code &= !INST_MASK;
13994
inst_code |= (target as u32) << MOV_IMM16_OFFSET;
14095
*bytes = InstructionCode::from_u32(inst_code).0;
141-
142-
Ok(())
14396
}
14497

145-
pub fn mov_w_abs_g2s_reloc(value: i64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
98+
fn patch_mov_signed(target: i16, bytes: &mut [u8; 4]) {
14699
const INST_MASK: u32 = (((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET)
147100
| (((1 << MOV_OPCODE_WIDTH) - 1) << MOV_OPCODE_OFFSET);
148101

149-
let target: i16 = (value >> 32).try_into()?;
150-
let bytes = get_bytes_mut(mem, offset)?;
151-
152102
let mut inst_code = InstructionCode(*bytes).unpack();
153103
inst_code &= !INST_MASK;
154104
if target < 0 {
@@ -159,20 +109,4 @@ pub fn mov_w_abs_g2s_reloc(value: i64, mem: &mut [u8], offset: usize) -> Result<
159109
inst_code |= MOV_OPCODE_MOVZ << MOV_OPCODE_OFFSET;
160110
}
161111
*bytes = InstructionCode::from_u32(inst_code).0;
162-
163-
Ok(())
164-
}
165-
166-
pub fn mov_w_abs_g3_reloc(value: u64, mem: &mut [u8], offset: usize) -> Result<(), Rel64Error> {
167-
const INST_MASK: u32 = ((1 << MOV_IMM16_WIDTH) - 1) << MOV_IMM16_OFFSET;
168-
169-
let target = (value >> 48) as u32;
170-
let bytes = get_bytes_mut(mem, offset)?;
171-
172-
let mut inst_code = InstructionCode(*bytes).unpack();
173-
inst_code &= !INST_MASK;
174-
inst_code |= target << MOV_IMM16_OFFSET;
175-
*bytes = InstructionCode::from_u32(inst_code).0;
176-
177-
Ok(())
178112
}

0 commit comments

Comments
 (0)