use crate::bit_misc::BitExtraction;
use crate::elf::AArch64Instruction;
use crate::elf::AllowedRange;
use crate::elf::PAGE_MASK_4KB;
use crate::elf::PageMask;
use crate::elf::RelocationKind;
use crate::elf::RelocationKindInfo;
use crate::elf::RelocationSize;
use crate::elf::Sign;
use crate::relaxation::RelocationModifier;
use crate::utils::and_from_slice;
use crate::utils::or_from_slice;
use crate::utils::u32_from_slice;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelaxationKind {
NoOp,
ReplaceWithNop,
MovzX0Lsl16,
MovkX0,
MovzXnLsl16,
MovkXn,
AdrpToAdr,
AdrpX0,
LdrX0,
AddToAdr,
LdrToAdr,
}
impl RelaxationKind {
pub fn apply(self, section_bytes: &mut [u8], offset_in_section: &mut u64, _addend: &mut i64) {
let offset = *offset_in_section as usize;
match self {
RelaxationKind::NoOp => {}
RelaxationKind::ReplaceWithNop => {
section_bytes[offset..offset + 4].copy_from_slice(&[
0x1f, 0x20, 0x03, 0xd5, ]);
}
RelaxationKind::MovzX0Lsl16 => {
section_bytes[offset..offset + 4].copy_from_slice(&[
0x0, 0x0, 0xa0, 0xd2, ]);
}
RelaxationKind::MovkX0 => {
section_bytes[offset..offset + 4].copy_from_slice(&[
0x0, 0x0, 0x80, 0xf2, ]);
}
RelaxationKind::MovzXnLsl16 => {
let reg = u64::from(u32_from_slice(§ion_bytes[offset..offset + 4]))
.extract_bit_range(0..5) as u8;
section_bytes[offset..offset + 4].copy_from_slice(&[
reg, 0x0, 0xa0, 0xd2, ]);
}
RelaxationKind::MovkXn => {
let raw = u64::from(u32_from_slice(§ion_bytes[offset..offset + 4]));
let dst_reg = raw.extract_bit_range(0..5) as u8;
let src_reg = raw.extract_bit_range(5..10) as u8;
debug_assert_eq!(
src_reg, dst_reg,
"Source and destination registers must be equal"
);
section_bytes[offset..offset + 4].copy_from_slice(&[
dst_reg, 0x0, 0x80, 0xf2, ]);
}
RelaxationKind::AdrpToAdr => {
section_bytes[offset + 3] &= !0x80;
}
RelaxationKind::AddToAdr => {
section_bytes[offset + 3] &= !0x89;
}
RelaxationKind::LdrToAdr => {
section_bytes[offset + 3] &= !0x89;
}
RelaxationKind::AdrpX0 => {
section_bytes[offset..offset + 4].copy_from_slice(&[
0x0, 0x0, 0x0, 0x90, ]);
}
RelaxationKind::LdrX0 => {
section_bytes[offset..offset + 4].copy_from_slice(&[
0x0, 0x0, 0x40, 0xf9, ]);
}
}
}
#[must_use]
pub fn next_modifier(&self) -> RelocationModifier {
RelocationModifier::Normal
}
}
#[must_use]
pub const fn relocation_type_from_raw(r_type: u32) -> Option<RelocationKindInfo> {
let (kind, size, mask, range, alignment) = match r_type {
object::elf::R_AARCH64_NONE => (
RelocationKind::None,
RelocationSize::ByteSize(0),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_ABS64 => (
RelocationKind::Absolute,
RelocationSize::ByteSize(8),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_ABS32 => (
RelocationKind::Absolute,
RelocationSize::ByteSize(4),
None,
AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
1,
),
object::elf::R_AARCH64_ABS16 => (
RelocationKind::Absolute,
RelocationSize::ByteSize(2),
None,
AllowedRange::new(-(2i64.pow(15)), 2i64.pow(16)),
1,
),
object::elf::R_AARCH64_PREL64 => (
RelocationKind::Relative,
RelocationSize::ByteSize(8),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_PREL32 => (
RelocationKind::Relative,
RelocationSize::ByteSize(4),
None,
AllowedRange::new(-(2i64.pow(31)), 2i64.pow(32)),
1,
),
object::elf::R_AARCH64_PREL16 => (
RelocationKind::Relative,
RelocationSize::ByteSize(2),
None,
AllowedRange::new(-(2i64.pow(15)), 2i64.pow(16)),
1,
),
object::elf::R_AARCH64_PLT32 => (
RelocationKind::PltRelative,
RelocationSize::ByteSize(4),
None,
AllowedRange::from_bit_size(32, Sign::Signed),
1,
),
object::elf::R_AARCH64_MOVW_UABS_G0 => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::from_bit_size(16, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_MOVW_UABS_G0_NC => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_UABS_G1 => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movkz),
None,
AllowedRange::from_bit_size(32, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_MOVW_UABS_G1_NC => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_UABS_G2 => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movkz),
None,
AllowedRange::from_bit_size(48, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_MOVW_UABS_G2_NC => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_UABS_G3 => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(48, 64, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_SABS_G0 => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movnz),
None,
AllowedRange::from_bit_size(17, Sign::Signed),
1,
),
object::elf::R_AARCH64_MOVW_SABS_G1 => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movnz),
None,
AllowedRange::from_bit_size(33, Sign::Signed),
1,
),
object::elf::R_AARCH64_MOVW_SABS_G2 => (
RelocationKind::Absolute,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movnz),
None,
AllowedRange::from_bit_size(49, Sign::Signed),
1,
),
object::elf::R_AARCH64_LD_PREL_LO19 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(2, 21, AArch64Instruction::Ldr),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
4,
),
object::elf::R_AARCH64_ADR_PREL_LO21 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(0, 21, AArch64Instruction::Adr),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
1,
),
object::elf::R_AARCH64_ADR_PREL_PG_HI21 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(12, 33, AArch64Instruction::Adr),
Some(PageMask::SymbolPlusAddendAndPosition(PAGE_MASK_4KB)),
AllowedRange::from_bit_size(33, Sign::Signed),
1,
),
object::elf::R_AARCH64_ADR_PREL_PG_HI21_NC => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(12, 33, AArch64Instruction::Adr),
Some(PageMask::SymbolPlusAddendAndPosition(PAGE_MASK_4KB)),
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_ADD_ABS_LO12_NC => (
RelocationKind::AbsoluteLowPart,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::Add),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_LDST8_ABS_LO12_NC => (
RelocationKind::AbsoluteLowPart,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_LDST16_ABS_LO12_NC => (
RelocationKind::AbsoluteLowPart,
RelocationSize::bit_mask_aarch64(1, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
2,
),
object::elf::R_AARCH64_LDST32_ABS_LO12_NC => (
RelocationKind::AbsoluteLowPart,
RelocationSize::bit_mask_aarch64(2, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
4,
),
object::elf::R_AARCH64_LDST64_ABS_LO12_NC => (
RelocationKind::AbsoluteLowPart,
RelocationSize::bit_mask_aarch64(3, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
8,
),
object::elf::R_AARCH64_LDST128_ABS_LO12_NC => (
RelocationKind::AbsoluteLowPart,
RelocationSize::bit_mask_aarch64(4, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
16,
),
object::elf::R_AARCH64_TSTBR14 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(2, 16, AArch64Instruction::TstBr),
None,
AllowedRange::from_bit_size(16, Sign::Signed),
4,
),
object::elf::R_AARCH64_CONDBR19 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(2, 21, AArch64Instruction::Bcond),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
4,
),
object::elf::R_AARCH64_JUMP26 => (
RelocationKind::PltRelative,
RelocationSize::bit_mask_aarch64(2, 28, AArch64Instruction::JumpCall),
None,
AllowedRange::from_bit_size(28, Sign::Signed),
4,
),
object::elf::R_AARCH64_CALL26 => (
RelocationKind::PltRelative,
RelocationSize::bit_mask_aarch64(2, 28, AArch64Instruction::JumpCall),
None,
AllowedRange::from_bit_size(28, Sign::Signed),
4,
),
object::elf::R_AARCH64_MOVW_PREL_G0 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_PREL_G0_NC => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_PREL_G1 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_PREL_G1_NC => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_PREL_G2 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_PREL_G2_NC => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_PREL_G3 => (
RelocationKind::Relative,
RelocationSize::bit_mask_aarch64(48, 64, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_GOTOFF_G0 => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_GOTOFF_G0_NC => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_GOTOFF_G1 => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_GOTOFF_G1_NC => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_GOTOFF_G2 => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_GOTOFF_G2_NC => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_MOVW_GOTOFF_G3 => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(48, 64, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_GOTREL64 => (
RelocationKind::SymRelGotBase,
RelocationSize::ByteSize(4),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_GOTREL32 => (
RelocationKind::SymRelGotBase,
RelocationSize::ByteSize(8),
None,
AllowedRange::from_bit_size(32, Sign::Signed),
1,
),
object::elf::R_AARCH64_GOTPCREL32 => (
RelocationKind::GotRelative,
RelocationSize::ByteSize(4),
None,
AllowedRange::from_bit_size(32, Sign::Signed),
1,
),
object::elf::R_AARCH64_GOT_LD_PREL19 => (
RelocationKind::GotRelative,
RelocationSize::bit_mask_aarch64(2, 21, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
4,
),
object::elf::R_AARCH64_LD64_GOTOFF_LO15 => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(3, 15, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(15, Sign::Unsigned),
8,
),
object::elf::R_AARCH64_ADR_GOT_PAGE => (
RelocationKind::GotRelative,
RelocationSize::bit_mask_aarch64(12, 33, AArch64Instruction::Adr),
Some(PageMask::GotEntryAndPosition(PAGE_MASK_4KB)),
AllowedRange::from_bit_size(33, Sign::Signed),
1,
),
object::elf::R_AARCH64_LD64_GOT_LO12_NC => (
RelocationKind::Got,
RelocationSize::bit_mask_aarch64(3, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
8,
),
object::elf::R_AARCH64_LD64_GOTPAGE_LO15 => (
RelocationKind::GotRelGotBase,
RelocationSize::bit_mask_aarch64(3, 15, AArch64Instruction::LdSt),
Some(PageMask::GotBase(PAGE_MASK_4KB)),
AllowedRange::from_bit_size(15, Sign::Unsigned),
8,
),
object::elf::R_AARCH64_TLSGD_ADR_PREL21 => (
RelocationKind::TlsGd,
RelocationSize::bit_mask_aarch64(0, 21, AArch64Instruction::Adr),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSGD_ADR_PAGE21 => (
RelocationKind::TlsGd,
RelocationSize::bit_mask_aarch64(12, 33, AArch64Instruction::Adr),
Some(PageMask::GotEntryAndPosition(PAGE_MASK_4KB)),
AllowedRange::from_bit_size(33, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSGD_ADD_LO12_NC => (
RelocationKind::TlsGdGot,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::Add),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSGD_MOVW_G1 => (
RelocationKind::TlsGdGotBase,
RelocationSize::bit_mask_aarch64(16, 33, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSGD_MOVW_G0_NC => (
RelocationKind::TlsGdGotBase,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_ADR_PREL21 => (
RelocationKind::TlsLd,
RelocationSize::bit_mask_aarch64(0, 21, AArch64Instruction::Adr),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSLD_ADR_PAGE21 => (
RelocationKind::TlsLd,
RelocationSize::bit_mask_aarch64(12, 33, AArch64Instruction::Adr),
Some(PageMask::GotEntryAndPosition(PAGE_MASK_4KB)),
AllowedRange::from_bit_size(33, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSLD_ADD_LO12_NC => (
RelocationKind::TlsLdGot,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::Add),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_MOVW_G1 => (
RelocationKind::TlsLdGotBase,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_MOVW_G0_NC => (
RelocationKind::TlsLdGotBase,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_LD_PREL19 => (
RelocationKind::TlsLd,
RelocationSize::bit_mask_aarch64(0, 21, AArch64Instruction::Ldr),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSLD_MOVW_DTPREL_G2 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_MOVW_DTPREL_G1 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_MOVW_DTPREL_G0 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_ADD_DTPREL_HI12 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(12, 24, AArch64Instruction::Add),
None,
AllowedRange::from_bit_size(24, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_TLSLD_ADD_DTPREL_LO12 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::Add),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::Add),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_LDST8_DTPREL_LO12 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLD_LDST16_DTPREL_LO12 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(1, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
2,
),
object::elf::R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(1, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
2,
),
object::elf::R_AARCH64_TLSLD_LDST32_DTPREL_LO12 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(2, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
4,
),
object::elf::R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(2, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
4,
),
object::elf::R_AARCH64_TLSLD_LDST64_DTPREL_LO12 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(3, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
8,
),
object::elf::R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(3, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
8,
),
object::elf::R_AARCH64_TLSLD_LDST128_DTPREL_LO12 => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(4, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
16,
),
object::elf::R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC => (
RelocationKind::DtpOff,
RelocationSize::bit_mask_aarch64(4, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
16,
),
object::elf::R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 => (
RelocationKind::GotTpOffGotBase,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC => (
RelocationKind::GotTpOffGotBase,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 => (
RelocationKind::GotTpOff,
RelocationSize::bit_mask_aarch64(12, 33, AArch64Instruction::Adr),
Some(PageMask::GotEntryAndPosition(PAGE_MASK_4KB)),
AllowedRange::from_bit_size(33, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC => (
RelocationKind::GotTpOffGot,
RelocationSize::bit_mask_aarch64(3, 12, AArch64Instruction::LdrRegister),
None,
AllowedRange::no_check(),
8,
),
object::elf::R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 => (
RelocationKind::GotTpOff,
RelocationSize::bit_mask_aarch64(2, 21, AArch64Instruction::Ldr),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
4,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G2 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(32, 48, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G1 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G0 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movnz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLE_ADD_TPREL_HI12 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(12, 24, AArch64Instruction::Add),
None,
AllowedRange::from_bit_size(24, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_TLSLE_ADD_TPREL_LO12 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::Add),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::Add),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLE_LDST8_TPREL_LO12 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
1,
),
object::elf::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSLE_LDST16_TPREL_LO12 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(1, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
2,
),
object::elf::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(1, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
2,
),
object::elf::R_AARCH64_TLSLE_LDST32_TPREL_LO12 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(2, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
4,
),
object::elf::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(2, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
4,
),
object::elf::R_AARCH64_TLSLE_LDST64_TPREL_LO12 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(3, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
8,
),
object::elf::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(3, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
8,
),
object::elf::R_AARCH64_TLSLE_LDST128_TPREL_LO12 => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(4, 12, AArch64Instruction::LdSt),
None,
AllowedRange::from_bit_size(12, Sign::Unsigned),
16,
),
object::elf::R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC => (
RelocationKind::TpOff,
RelocationSize::bit_mask_aarch64(4, 12, AArch64Instruction::LdSt),
None,
AllowedRange::no_check(),
16,
),
object::elf::R_AARCH64_TLSDESC_LD_PREL19 => (
RelocationKind::TlsDesc,
RelocationSize::bit_mask_aarch64(2, 21, AArch64Instruction::Ldr),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
4,
),
object::elf::R_AARCH64_TLSDESC_ADR_PREL21 => (
RelocationKind::TlsDesc,
RelocationSize::bit_mask_aarch64(0, 21, AArch64Instruction::Adr),
None,
AllowedRange::from_bit_size(21, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSDESC_ADR_PAGE21 => (
RelocationKind::TlsDesc,
RelocationSize::bit_mask_aarch64(12, 33, AArch64Instruction::Adr),
Some(PageMask::GotEntryAndPosition(PAGE_MASK_4KB)),
AllowedRange::from_bit_size(33, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSDESC_LD64_LO12 => (
RelocationKind::TlsDescGot,
RelocationSize::bit_mask_aarch64(3, 12, AArch64Instruction::LdrRegister),
None,
AllowedRange::no_check(),
8,
),
object::elf::R_AARCH64_TLSDESC_ADD_LO12 => (
RelocationKind::TlsDescGot,
RelocationSize::bit_mask_aarch64(0, 12, AArch64Instruction::Add),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSDESC_OFF_G1 => (
RelocationKind::TlsDescGotBase,
RelocationSize::bit_mask_aarch64(16, 32, AArch64Instruction::Movnz),
None,
AllowedRange::from_bit_size(33, Sign::Signed),
1,
),
object::elf::R_AARCH64_TLSDESC_OFF_G0_NC => (
RelocationKind::TlsDescGotBase,
RelocationSize::bit_mask_aarch64(0, 16, AArch64Instruction::Movkz),
None,
AllowedRange::no_check(),
1,
),
object::elf::R_AARCH64_TLSDESC_CALL => (
RelocationKind::TlsDescCall,
RelocationSize::ByteSize(0),
None,
AllowedRange::no_check(),
1,
),
_ => return None,
};
Some(RelocationKindInfo {
kind,
size,
mask,
range,
alignment,
bias: 0,
thunkable: matches!(
r_type,
object::elf::R_AARCH64_CALL26 | object::elf::R_AARCH64_JUMP26
),
})
}
impl AArch64Instruction {
pub fn write_to_value(self, extracted_value: u64, negative: bool, dest: &mut [u8]) {
let mut mask;
match self {
AArch64Instruction::Adr => {
mask = ((extracted_value.extract_bit_range(0..2) as u32) << 29)
| ((extracted_value.extract_bit_range(2..32) as u32) << 5);
}
AArch64Instruction::Movkz => {
mask = (extracted_value as u32) << 5;
}
AArch64Instruction::Movnz => {
and_from_slice(dest, &0x0060_001F_u32.to_le_bytes());
let mut value = extracted_value as i64;
mask = 0u32;
if negative {
value = !value;
mask |= 0x9280_0000;
} else {
mask |= 0xd280_0000;
}
mask |= ((value as u64).extract_bit_range(0..16) as u32) << 5;
}
AArch64Instruction::Ldr => {
mask = (extracted_value as u32) << 5;
}
AArch64Instruction::LdrRegister => {
mask = (extracted_value as u32) << 10;
}
AArch64Instruction::Add => {
mask = (extracted_value as u32) << 10;
}
AArch64Instruction::LdSt => {
mask = (extracted_value as u32) << 10;
}
AArch64Instruction::TstBr => {
mask = (extracted_value as u32) << 5;
}
AArch64Instruction::Bcond => {
mask = (extracted_value as u32) << 5;
}
AArch64Instruction::JumpCall => {
mask = extracted_value as u32;
}
AArch64Instruction::MachOLow12 => {
let insn = u32_from_slice(&dest[0..4]);
let mut scale = 0;
if (insn & 0x3b00_0000) == 0x3900_0000 {
scale = insn >> 30;
if scale == 0 && (insn & 0x0480_0000) == 0x0480_0000 {
scale = 4;
}
}
mask = (extracted_value as u32) >> scale;
}
}
or_from_slice(dest, &mask.to_le_bytes());
}
#[must_use]
pub fn read_value(self, bytes: &[u8]) -> (u64, bool) {
let mut negative = false;
let value = u64::from(u32_from_slice(bytes));
let extracted_value = match self {
AArch64Instruction::Adr => {
(value >> 29).low_bits(2) | (((value >> 5).low_bits_signed(19)) << 2)
}
AArch64Instruction::Movkz => (value >> 5).low_bits_signed(16),
AArch64Instruction::Movnz => {
negative = (value & (1 << 30)) == 0;
let v = (value >> 5).low_bits(16);
if negative { !v } else { v }
}
AArch64Instruction::Ldr => (value >> 5).low_bits_signed(19),
AArch64Instruction::LdrRegister => (value >> 10).low_bits(12),
AArch64Instruction::Add => (value >> 10).low_bits(12),
AArch64Instruction::LdSt => (value >> 10).low_bits_signed(12),
AArch64Instruction::TstBr => (value >> 5).low_bits_signed(14),
AArch64Instruction::Bcond => (value >> 5).low_bits_signed(19),
AArch64Instruction::JumpCall => value.low_bits_signed(26),
AArch64Instruction::MachOLow12 => todo!(),
};
(extracted_value, negative)
}
}