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