#![allow(clippy::identity_op)]
pub(crate) fn generate_plt0_code() -> Vec<u8> {
vec![0; 32]
}
fn encode_imm26(imm: i32) -> u32 {
let imm = imm as u32;
((imm & 0xffff) << 10) | ((imm >> 16) & 0x3ff)
}
pub(crate) fn patch_plt0(
plt_data: &mut [u8],
plt0_off: usize,
plt0_vaddr: u64,
got_plt_vaddr: u64,
) {
let pc = plt0_vaddr;
let target_got0 = got_plt_vaddr;
let off = target_got0 as i64 - pc as i64;
let imm20 = (off >> 2) as i32;
let pcaddi = 0x18000000u32 | (14 << 0) | ((imm20 as u32 & 0xfffff) << 5);
let ld_linkmap = 0x28c00000u32 | (12 << 0) | (14 << 5) | (8 << 10);
let ld_resolver = 0x28c00000u32 | (14 << 0) | (14 << 5) | (0 << 10);
let jr = 0x4c000000u32 | (0 << 0) | (14 << 5) | (0 << 10);
plt_data[plt0_off..plt0_off + 4].copy_from_slice(&pcaddi.to_le_bytes());
plt_data[plt0_off + 4..plt0_off + 8].copy_from_slice(&ld_linkmap.to_le_bytes());
plt_data[plt0_off + 8..plt0_off + 12].copy_from_slice(&ld_resolver.to_le_bytes());
plt_data[plt0_off + 12..plt0_off + 16].copy_from_slice(&jr.to_le_bytes());
}
pub(crate) fn generate_plt_entry_code(reloc_idx: u32, plt_entry_offset: u64) -> Vec<u8> {
let mut code = vec![0; 32];
let nop = 0x03400000u32;
code[12..16].copy_from_slice(&nop.to_le_bytes());
let reloc_val = reloc_idx * 8;
let li = 0x02800000 | (13 << 0) | ((reloc_val & 0xfff) << 10);
let plt0_off = -(plt_entry_offset as i32 + 20);
let b_imm = plt0_off >> 2;
let b = 0x50000000 | encode_imm26(b_imm);
code[16..20].copy_from_slice(&li.to_le_bytes());
code[20..24].copy_from_slice(&b.to_le_bytes());
code
}
pub(crate) fn patch_plt_entry(
plt_data: &mut [u8],
plt_entry_off: usize,
plt_entry_vaddr: u64,
target_got_vaddr: u64,
) {
let pc = plt_entry_vaddr;
let off = target_got_vaddr as i64 - pc as i64;
let imm20 = (off >> 2) as i32;
let pcaddi = 0x18000000u32 | (14 << 0) | ((imm20 as u32 & 0xfffff) << 5);
let ld = 0x28c00000u32 | (13 << 0) | (14 << 5) | (0 << 10);
let jirl = 0x4c000000u32 | (0 << 0) | (13 << 5) | (0 << 10);
plt_data[plt_entry_off..plt_entry_off + 4].copy_from_slice(&pcaddi.to_le_bytes());
plt_data[plt_entry_off + 4..plt_entry_off + 8].copy_from_slice(&ld.to_le_bytes());
plt_data[plt_entry_off + 8..plt_entry_off + 12].copy_from_slice(&jirl.to_le_bytes());
}
pub(crate) fn generate_helper_code() -> Vec<u8> {
vec![0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00]
}
pub(crate) fn patch_helper(
text_data: &mut [u8],
helper_text_off: usize,
helper_vaddr: u64,
target_plt_vaddr: u64,
) {
let off = (target_plt_vaddr as i64 - helper_vaddr as i64) / 4;
let insn = 0x50000000 | encode_imm26(off as i32);
text_data[helper_text_off..helper_text_off + 4].copy_from_slice(&insn.to_le_bytes());
}
pub(crate) fn get_ifunc_resolver_code() -> Vec<u8> {
let mut code = vec![0; 16];
code[0..4].copy_from_slice(&[0x04, 0x00, 0x00, 0x1a]);
code[4..8].copy_from_slice(&[0x84, 0x00, 0xc0, 0x02]);
code[8..12].copy_from_slice(&[0x20, 0x00, 0x00, 0x4c]);
code[12..16].copy_from_slice(&[0x00, 0x00, 0x40, 0x03]);
code
}
pub(crate) fn patch_ifunc_resolver(
text_data: &mut [u8],
offset: usize,
resolver_vaddr: u64,
target_vaddr: u64,
) {
let pc = resolver_vaddr;
let hi = (target_vaddr as i64 - (pc as i64 & !0xfff) + 0x800) >> 12;
let lo = target_vaddr as i64 & 0xfff;
let pcalau12i = 0x1a000000u32 | (4 << 0) | ((hi as u32 & 0xfffff) << 5);
let addi = 0x02c00000u32 | (4 << 0) | (4 << 5) | ((lo as u32 & 0xfff) << 10);
text_data[offset..offset + 4].copy_from_slice(&pcalau12i.to_le_bytes());
text_data[offset + 4..offset + 8].copy_from_slice(&addi.to_le_bytes());
}
pub(crate) fn generate_tls_helper_code() -> Vec<u8> {
let mut code = vec![0; 40];
for i in (0..40).step_by(4) {
code[i..i + 4].copy_from_slice(&[0x00, 0x00, 0x40, 0x03]);
}
let addi_sp_neg = 0x02c00000u32 | (3 << 0) | (3 << 5) | ((-16i32 as u32 & 0xfff) << 10);
code[0..4].copy_from_slice(&addi_sp_neg.to_le_bytes());
let st_ra = 0x29c00000u32 | (1 << 0) | (3 << 5) | (8 << 10);
code[4..8].copy_from_slice(&st_ra.to_le_bytes());
let ld_ra = 0x28c00000u32 | (1 << 0) | (3 << 5) | (8 << 10);
code[24..28].copy_from_slice(&ld_ra.to_le_bytes());
let addi_sp_pos = 0x02c00000u32 | (3 << 0) | (3 << 5) | (16 << 10);
code[28..32].copy_from_slice(&addi_sp_pos.to_le_bytes());
let ret = 0x4c000000u32 | (0 << 0) | (1 << 5) | (0 << 10);
code[32..36].copy_from_slice(&ret.to_le_bytes());
code
}
pub(crate) fn patch_tls_tester(
text_data: &mut [u8],
offset: usize,
helper_vaddr: u64,
reloc_vaddr: u64,
tls_get_addr_vaddr: u64,
) {
let pc = helper_vaddr + 8;
let hi = (reloc_vaddr as i64 - (pc as i64 & !0xfff) + 0x800) >> 12;
let lo = reloc_vaddr & 0xfff;
let pcalau12i_a0 = 0x1a000000u32 | (4 << 0) | ((hi as u32 & 0xfffff) << 5);
let addi_a0 = 0x02c00000u32 | (4 << 0) | (4 << 5) | ((lo as u32 & 0xfff) << 10);
text_data[offset + 8..offset + 12].copy_from_slice(&pcalau12i_a0.to_le_bytes());
text_data[offset + 12..offset + 16].copy_from_slice(&addi_a0.to_le_bytes());
let bl_off = (tls_get_addr_vaddr as i64 - (helper_vaddr as i64 + 16)) >> 2;
let bl = 0x54000000u32 | encode_imm26(bl_off as i32);
text_data[offset + 16..offset + 20].copy_from_slice(&bl.to_le_bytes());
}