const REG_T0: u32 = 5;
const REG_T1: u32 = 6;
const REG_T2: u32 = 7;
const REG_T3: u32 = 28;
pub(crate) fn generate_plt0_code() -> Vec<u8> {
let mut code = vec![0; 32];
let auipc = encode_utype(0x17, REG_T2, 0);
let sub = encode_rtype(0x33, REG_T1, REG_T1, REG_T3, 0, 0x20);
let ld_resolver = encode_itype(0x3003, REG_T3, REG_T2, 0);
let addi_adj = encode_itype(0x13, REG_T1, REG_T1, (-44i32) as u32);
let addi_got = encode_itype(0x13, REG_T0, REG_T2, 0);
let srli = 0x00135313u32;
let ld_linkmap = encode_itype(0x3003, REG_T0, REG_T0, 8);
let jr = encode_itype(0x67, 0, REG_T3, 0);
code[0..4].copy_from_slice(&auipc.to_le_bytes());
code[4..8].copy_from_slice(&sub.to_le_bytes());
code[8..12].copy_from_slice(&ld_resolver.to_le_bytes());
code[12..16].copy_from_slice(&addi_adj.to_le_bytes());
code[16..20].copy_from_slice(&addi_got.to_le_bytes());
code[20..24].copy_from_slice(&srli.to_le_bytes());
code[24..28].copy_from_slice(&ld_linkmap.to_le_bytes());
code[28..32].copy_from_slice(&jr.to_le_bytes());
code
}
pub(crate) fn patch_plt0(
plt_data: &mut [u8],
plt0_off: usize,
plt0_vaddr: u64,
got_plt_vaddr: u64,
) {
let pc = plt0_vaddr;
let (hi, lo) = split_addr(pc, got_plt_vaddr);
let auipc = encode_utype(0x17, REG_T2, hi);
let ld_resolver = encode_itype(0x00003003, REG_T3, REG_T2, lo);
let addi_got = encode_itype(0x13, REG_T0, REG_T2, lo);
plt_data[plt0_off..plt0_off + 4].copy_from_slice(&auipc.to_le_bytes());
plt_data[plt0_off + 8..plt0_off + 12].copy_from_slice(&ld_resolver.to_le_bytes());
plt_data[plt0_off + 16..plt0_off + 20].copy_from_slice(&addi_got.to_le_bytes());
}
pub(crate) fn generate_plt_entry_code() -> Vec<u8> {
let mut code = vec![0; 16];
let jalr = encode_itype(0x67, REG_T1, REG_T3, 0);
let nop = 0x00000013u32;
code[8..12].copy_from_slice(&jalr.to_le_bytes());
code[12..16].copy_from_slice(&nop.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 (hi, lo) = split_addr(pc, target_got_vaddr);
let auipc = encode_utype(0x17, REG_T3, hi);
let ld = encode_itype(0x00003003, REG_T3, REG_T3, lo);
plt_data[plt_entry_off..plt_entry_off + 4].copy_from_slice(&auipc.to_le_bytes());
plt_data[plt_entry_off + 4..plt_entry_off + 8].copy_from_slice(&ld.to_le_bytes());
}
fn split_addr(pc: u64, target: u64) -> (u32, u32) {
let offset = target as i64 - pc as i64;
let hi = (offset + 0x800) as u32 & 0xfffff000;
let lo = (offset as u32).wrapping_sub(hi) & 0xfff;
(hi, lo)
}
fn encode_utype(op: u32, rd: u32, imm: u32) -> u32 {
op | (rd << 7) | (imm & 0xfffff000)
}
fn encode_itype(op: u32, rd: u32, rs1: u32, imm: u32) -> u32 {
op | (rd << 7) | (rs1 << 15) | ((imm & 0xfff) << 20)
}
fn encode_rtype(op: u32, rd: u32, rs1: u32, rs2: u32, funct3: u32, funct7: u32) -> u32 {
op | (rd << 7) | (funct3 << 12) | (rs1 << 15) | (rs2 << 20) | (funct7 << 25)
}
pub(crate) fn generate_helper_code() -> Vec<u8> {
let mut code = vec![0; 8];
let auipc = encode_utype(0x17, REG_T0, 0);
let jr = encode_itype(0x67, 0, REG_T0, 0);
code[0..4].copy_from_slice(&auipc.to_le_bytes());
code[4..8].copy_from_slice(&jr.to_le_bytes());
code
}
pub(crate) fn patch_helper(
text_data: &mut [u8],
helper_text_off: usize,
helper_vaddr: u64,
target_plt_vaddr: u64,
) {
let pc = helper_vaddr;
let off = target_plt_vaddr as i64 - pc as i64;
let hi = (off + 0x800) as u32 & 0xfffff000;
let lo = (off as u32).wrapping_sub(hi) & 0xfff;
let auipc = encode_utype(0x17, REG_T0, hi);
let jr = encode_itype(0x67, 0, REG_T0, lo);
text_data[helper_text_off..helper_text_off + 4].copy_from_slice(&auipc.to_le_bytes());
text_data[helper_text_off + 4..helper_text_off + 8].copy_from_slice(&jr.to_le_bytes());
}
pub(crate) fn get_ifunc_resolver_code() -> Vec<u8> {
let mut code = vec![0; 24];
code[0..4].copy_from_slice(&[0x17, 0x05, 0x00, 0x00]);
code[4..8].copy_from_slice(&[0x83, 0x32, 0x05, 0x01]); code[8..12].copy_from_slice(&[0x33, 0x05, 0x55, 0x00]); code[12..16].copy_from_slice(&[0x67, 0x80, 0x00, 0x00]); code
}
pub(crate) fn patch_ifunc_resolver(
text_data: &mut [u8],
offset: usize,
resolver_vaddr: u64,
target_vaddr: u64,
) {
let rel_off = target_vaddr as i64 - resolver_vaddr as i64;
text_data[offset + 16..offset + 24].copy_from_slice(&rel_off.to_le_bytes());
}
const REG_RA: u32 = 1;
const REG_SP: u32 = 2;
const REG_A0: u32 = 10;
pub(crate) fn generate_tls_helper_code() -> Vec<u8> {
let mut code = vec![0; 36];
for i in (0..36).step_by(4) {
code[i..i + 4].copy_from_slice(&[0x13, 0x00, 0x00, 0x00]);
}
code[0..4].copy_from_slice(&encode_itype(0x13, REG_SP, REG_SP, (-16i32) as u32).to_le_bytes());
code[4..8].copy_from_slice(&[0x23, 0x34, 0x11, 0x00]);
code[24..28].copy_from_slice(&[0x83, 0x30, 0x81, 0x00]); code[28..32].copy_from_slice(&encode_itype(0x13, REG_SP, REG_SP, 16).to_le_bytes());
code[32..36].copy_from_slice(&[0x67, 0x80, 0x00, 0x00]);
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 (hi, lo) = split_addr(helper_vaddr + 8, reloc_vaddr);
let auipc_a0 = encode_utype(0x17, REG_A0, hi);
let addi_a0 = encode_itype(0x13, REG_A0, REG_A0, lo);
text_data[offset + 8..offset + 12].copy_from_slice(&auipc_a0.to_le_bytes());
text_data[offset + 12..offset + 16].copy_from_slice(&addi_a0.to_le_bytes());
let (hi_call, lo_call) = split_addr(helper_vaddr + 16, tls_get_addr_vaddr);
let auipc_call = encode_utype(0x17, REG_T0, hi_call);
let jalr_call = encode_itype(0x67, REG_RA, REG_T0, lo_call);
text_data[offset + 16..offset + 20].copy_from_slice(&auipc_call.to_le_bytes());
text_data[offset + 20..offset + 24].copy_from_slice(&jalr_call.to_le_bytes());
}