1use crate::Register;
26use crate::relocations::{ArchitectureRelocationEncoding, Relocation, RelocationType, RelocationSize, RelocationKind, RelocationEncoding, ImpossibleRelocation, fits_signed_bitfield};
27use byteorder::{ByteOrder, LittleEndian};
28use std::convert::TryFrom;
29
30#[derive(Debug, Clone, Copy)]
31enum Aarch64RelocationEncoding {
32 B,
34 BCOND,
36 ADR,
38 ADRP,
40 TBZ,
42}
43
44impl ArchitectureRelocationEncoding for Aarch64RelocationEncoding {
45 fn decode(code: u8) -> Self {
46 match code {
47 0 => Self::B,
48 1 => Self::BCOND,
49 2 => Self::ADR,
50 3 => Self::ADRP,
51 4 => Self::TBZ,
52 n => panic!("Invalid complex relocation code {n} given for the current architecture")
53 }
54 }
55}
56
57impl Aarch64RelocationEncoding {
58 fn op_mask(&self) -> u32 {
59 match self {
60 Self::B => 0xFC00_0000,
61 Self::BCOND => 0xFF00_001F,
62 Self::ADR => 0x9F00_001F,
63 Self::ADRP => 0x9F00_001F,
64 Self::TBZ => 0xFFF8_001F
65 }
66 }
67
68 fn encode(&self, value: isize) -> Result<u32, ImpossibleRelocation> {
69 let value = i64::try_from(value).map_err(|_| ImpossibleRelocation { } )?;
70 Ok(match self {
71 Self::B => {
72 if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 26) {
73 return Err(ImpossibleRelocation { } );
74 }
75 let value = (value >> 2) as u32;
76 value & 0x3FF_FFFF
77 },
78 Self::BCOND => {
79 if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 19) {
80 return Err(ImpossibleRelocation { } );
81 }
82 let value = (value >> 2) as u32;
83 (value & 0x7FFFF) << 5
84 },
85 Self::ADR => {
86 if !fits_signed_bitfield(value, 21) {
87 return Err(ImpossibleRelocation { } );
88 }
89 let low = (value) as u32;
90 let high = (value >> 2) as u32;
91 ((high & 0x7FFFF) << 5) | ((low & 3) << 29)
92 },
93 Self::ADRP => {
94 let value = value + 0xFFF;
95 if !fits_signed_bitfield(value >> 12, 21) {
96 return Err(ImpossibleRelocation { } );
97 }
98 let low = (value >> 12) as u32;
99 let high = (value >> 14) as u32;
100 ((high & 0x7FFFF) << 5) | ((low & 3) << 29)
101 },
102 Self::TBZ => {
103 if value & 3 != 0 || !fits_signed_bitfield(value >> 2, 14) {
104 return Err(ImpossibleRelocation { } );
105 }
106 let value = (value >> 2) as u32;
107 (value & 0x3FFF) << 5
108 }
109 })
110 }
111}
112
113#[derive(Debug, Clone, Copy)]
115pub struct Aarch64Relocation(RelocationType<Aarch64RelocationEncoding>);
116
117impl Relocation for Aarch64Relocation {
118 fn from_encoding(encoding: u8) -> Self {
119 Aarch64Relocation(RelocationType::decode(encoding))
120 }
121 fn from_size(kind: RelocationKind, size: RelocationSize) -> Self {
122 Aarch64Relocation(RelocationType::from_size(kind, size))
123 }
124 fn size(&self) -> usize {
125 match self.0.encoding {
126 RelocationEncoding::Simple(s) => s.size(),
127 RelocationEncoding::ArchSpecific(_) => 4
128 }
129 }
130 fn write_value(&self, buf: &mut [u8], value: isize) -> Result<(), ImpossibleRelocation> {
131 match self.0.encoding {
132 RelocationEncoding::Simple(s) => s.write_value(buf, value),
133 RelocationEncoding::ArchSpecific(c) => {
134 let mask = c.op_mask();
135 let template = LittleEndian::read_u32(buf) & mask;
136 let packed = c.encode(value)?;
137 LittleEndian::write_u32(buf, template | packed);
138 Ok(())
139 }
140 }
141 }
142 fn read_value(&self, buf: &[u8]) -> isize {
143 match self.0.encoding {
144 RelocationEncoding::Simple(s) => s.read_value(buf),
145 RelocationEncoding::ArchSpecific(c) => {
146 let mask = !c.op_mask();
147 let value = LittleEndian::read_u32(buf);
148 let unpacked = match c {
149 Aarch64RelocationEncoding::B => u64::from(
150 value & mask
151 ) << 2,
152 Aarch64RelocationEncoding::BCOND => u64::from(
153 (value & mask) >> 5
154 ) << 2,
155 Aarch64RelocationEncoding::ADR => u64::from(
156 (((value >> 5 ) & 0x7FFFF) << 2) |
157 ((value >> 29) & 3 )
158 ),
159 Aarch64RelocationEncoding::ADRP => u64::from(
160 (((value >> 5 ) & 0x7FFFF) << 2) |
161 ((value >> 29) & 3 )
162 ) << 12,
163 Aarch64RelocationEncoding::TBZ => u64::from(
164 (value & mask) >> 5
165 ) << 2
166 };
167
168 let bits = match c {
170 Aarch64RelocationEncoding::B => 26,
171 Aarch64RelocationEncoding::BCOND => 19,
172 Aarch64RelocationEncoding::ADR => 21,
173 Aarch64RelocationEncoding::ADRP => 33,
174 Aarch64RelocationEncoding::TBZ => 14
175 };
176 let offset = 1u64 << (bits - 1);
177 let value: u64 = (unpacked ^ offset).wrapping_sub(offset);
178
179 value as i64 as isize
180 }
181 }
182 }
183 fn kind(&self) -> RelocationKind {
184 self.0.kind
185 }
186 fn page_size() -> usize {
187 4096
188 }
189}
190
191pub type Assembler = crate::Assembler<Aarch64Relocation>;
193pub type AssemblyModifier<'a> = crate::Modifier<'a, Aarch64Relocation>;
195pub type UncommittedModifier<'a> = crate::UncommittedModifier<'a>;
197
198
199#[inline(never)]
204pub fn immediate_out_of_range_unsigned_f32(immediate: f32) -> ! {
205 panic!("Cannot assemble this Aarch64 instruction. Immediate {immediate} is out of range.")
206}
207
208#[inline(never)]
210pub fn immediate_out_of_range_unsigned_64(immediate: u64) -> ! {
211 panic!("Cannot assemble this Aarch64 instruction. Immediate {immediate} is out of range.")
212}
213
214#[inline(never)]
216pub fn immediate_out_of_range_unsigned_32(immediate: u32) -> ! {
217 panic!("Cannot assemble this Aarch64 instruction. Immediate {immediate} is out of range.")
218}
219
220#[inline(never)]
222pub fn immediate_out_of_range_signed_32(immediate: i32) -> ! {
223 panic!("Cannot assemble this Aarch64 instruction. Immediate {immediate} is out of range.")
224}
225
226
227pub fn encode_logical_immediate_32bit(value: u32) -> Option<u16> {
229 let transitions = value ^ value.rotate_right(1);
230 let element_size = (64u32).checked_div(transitions.count_ones())?;
231
232 if value != value.rotate_left(element_size) {
234 return None;
235 }
236
237 let element = value & 1u32.checked_shl(element_size).unwrap_or(0).wrapping_sub(1);
238 let ones = element.count_ones();
239 let imms = (!((element_size << 1) - 1) & 0x3F) | (ones - 1);
240
241 let immr = if (element & 1) != 0 {
242 ones - (!element).trailing_zeros()
243 } else {
244 element_size - element.trailing_zeros()
245 };
246
247 Some(((immr as u16) << 6) | (imms as u16))
248}
249
250pub fn encode_logical_immediate_64bit(value: u64) -> Option<u16> {
252 let transitions = value ^ value.rotate_right(1);
253 let element_size = (128u32).checked_div(transitions.count_ones())?;
254
255 if value != value.rotate_left(element_size) {
257 return None;
258 }
259
260 let element = value & 1u64.checked_shl(element_size).unwrap_or(0).wrapping_sub(1);
261 let ones = element.count_ones();
262 let imms = (!((element_size << 1) - 1) & 0x7F) | (ones - 1);
263
264 let immr = if (element & 1) != 0 {
265 ones - (!element).trailing_zeros()
266 } else {
267 element_size - element.trailing_zeros()
268 };
269
270 let n = imms & 0x40 == 0;
271 let imms = imms & 0x3F;
272
273 Some(((n as u16) << 12) | ((immr as u16) << 6) | (imms as u16))
274}
275
276pub fn encode_floating_point_immediate(value: f32) -> Option<u8> {
278 let bits = value.to_bits();
284
285 let check = (bits >> 25) & 0x3F;
286 if (check == 0b10_0000 || check == 0b01_1111) && (bits & 0x7_FFFF) == 0 {
287 Some((((bits >> 24) & 0x80) | ((bits >> 19) & 0x7F)) as u8)
288 } else {
289 None
290 }
291}
292
293
294#[allow(missing_docs)]
296#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
297pub enum RX {
298 X0 = 0x00, X1 = 0x01, X2 = 0x02, X3 = 0x03,
299 X4 = 0x04, X5 = 0x05, X6 = 0x06, X7 = 0x07,
300 X8 = 0x08, X9 = 0x09, X10= 0x0A, X11= 0x0B,
301 X12= 0x0C, X13= 0x0D, X14= 0x0E, X15= 0x0F,
302 X16= 0x10, X17= 0x11, X18= 0x12, X19= 0x13,
303 X20= 0x14, X21= 0x15, X22= 0x16, X23= 0x17,
304 X24= 0x18, X25= 0x19, X26= 0x1A, X27= 0x1B,
305 X28= 0x1C, X29= 0x1D, X30= 0x1E, XZR= 0x1F,
306}
307reg_impls!(RX);
308
309#[allow(missing_docs)]
312#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
313pub enum RXSP {
314 X0 = 0x00, X1 = 0x01, X2 = 0x02, X3 = 0x03,
315 X4 = 0x04, X5 = 0x05, X6 = 0x06, X7 = 0x07,
316 X8 = 0x08, X9 = 0x09, X10= 0x0A, X11= 0x0B,
317 X12= 0x0C, X13= 0x0D, X14= 0x0E, X15= 0x0F,
318 X16= 0x10, X17= 0x11, X18= 0x12, X19= 0x13,
319 X20= 0x14, X21= 0x15, X22= 0x16, X23= 0x17,
320 X24= 0x18, X25= 0x19, X26= 0x1A, X27= 0x1B,
321 X28= 0x1C, X29= 0x1D, X30= 0x1E, SP = 0x1F,
322}
323reg_impls!(RXSP);
324
325#[allow(missing_docs)]
327#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
328pub enum RV {
329 V0 = 0x00, V1 = 0x01, V2 = 0x02, V3 = 0x03,
330 V4 = 0x04, V5 = 0x05, V6 = 0x06, V7 = 0x07,
331 V8 = 0x08, V9 = 0x09, V10= 0x0A, V11= 0x0B,
332 V12= 0x0C, V13= 0x0D, V14= 0x0E, V15= 0x0F,
333 V16= 0x10, V17= 0x11, V18= 0x12, V19= 0x13,
334 V20= 0x14, V21= 0x15, V22= 0x16, V23= 0x17,
335 V24= 0x18, V25= 0x19, V26= 0x1A, V27= 0x1B,
336 V28= 0x1C, V29= 0x1D, V30= 0x1E, V31= 0x1F,
337}
338reg_impls!(RV);
339
340#[cfg(test)]
341mod tests {
342 use super::RX::*;
343 use crate::Register;
344
345 #[test]
346 fn reg_code() {
347 assert_eq!(X2.code(), 2);
348 }
349
350 #[test]
351 fn reg_code_from() {
352 assert_eq!(u8::from(X24), 0x18);
353 }
354}