Skip to content
Snippets Groups Projects
Commit 271ae947 authored by Jason Hiser's avatar Jason Hiser :tractor:
Browse files

added vldr patching support

parent 9e6286e1
No related branches found
No related tags found
No related merge requests found
......@@ -119,6 +119,7 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
// so far, only handling ldr and ldrb
const auto is_ldr_type = mnemonic.substr(0,3)=="ldr"; // ldr, ldrb, ldreq, ldrbeq, etc.
const auto is_vldr_type = mnemonic.substr(0,4)=="vldr"; // vldr <double>, vldr <single>
const auto is_add_type = mnemonic.substr(0,3)=="add"; // add, addne, etc.
const auto is_addne_type = mnemonic == "addne"; // exactly addne
const auto is_addls_type = mnemonic == "addls"; // exactly addls
......@@ -137,7 +138,93 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
assert(tmp_reg < 15); // sanity check 4 bits
if(is_ldr_type && !is_rd_pc)
if(is_vldr_type)
{
/*
* We need to patch an vldr[b][cond] fp_reg, [pc + constant]
* to be at a new location.
*
* The plan :
* FA: b<cond> L0
* FT:
* ..
* L0 str rd, [sp,#-fc]
* L1 ldr rd, [L6]
* L2 add rd, pc, rd
* L3 vldr rd, [rd, <imm>] # orig insn
* L4 ldr rd, [sp,#-fc]
* L5: b FT
* L6: .word <constant>
*/
const auto tramp_size = 6*4 + 4 ; // 6 insns, 4 bytes each, plus one word of read-only data
const auto tramp_range = ms.getFreeRange(tramp_size);
const auto tramp_start = tramp_range.getStart();
// don't be too fancy, just reserve 16 bytes.
ms.splitFreeRange({tramp_start,tramp_start+tramp_size});
// and give the bytes some names
const auto FA=from_insn_location;
const auto FT=from_insn_location+4;
const auto L0 = tramp_start;
const auto L1 = L0 + 4;
const auto L2 = L1 + 4;
const auto L3 = L2 + 4;
const auto L4 = L3 + 4;
const auto L5 = L4 + 4;
const auto L6 = L5 + 4;
// Create a branch to put over the original ldr
// and set the conditional bits equal to
// the original instruction conditional bits
auto my_branch_bytes = branch_bytes;
my_branch_bytes[3] &= 0x0f; // clear always condition bits
my_branch_bytes[3] |= (insn_bytes[3] & 0xf0); // add the vldr cond bits.
ms.plopBytes(FA,my_branch_bytes.c_str(),4);
// and make it point at L0
zo->applyPatch(FA,L0);
// spill tmp_reg at L0, e50d00fc
auto spill_insn = string("\xfc\x00\x0d\xe5",4);
spill_insn[1] |= (tmp_reg<<4);
ms.plopBytes(L0,spill_insn.c_str(),4);
// ldr dest_reg, [pc+k] (where pc+8+k == L6)
auto ldr_imm_insn = string("\x0c\x00\x9f\xe5",4);
ldr_imm_insn[1] |= (tmp_reg << 4); // set this instruction's dest reg to the ldr's dest reg.
ms.plopBytes(L1,ldr_imm_insn.c_str(),4);
// put down add tmp_reg,pc, temp_reg
auto new_add_word = string("\x00\x00\x8f\xe0",4); // e08f0000 add r0, pc, r0
new_add_word[1] |= (tmp_reg<<4);
new_add_word[0] |= (tmp_reg<<0);
ms.plopBytes(L2,new_add_word.c_str(),4);
// put down orig vldr insn, with 1) cond field removed, and 2) Rn set to -> tmp_reg
auto vldr_insn_bytes = from_insn->getDataBits();
vldr_insn_bytes[2] &= 0xf0; // remove Rn bits.
vldr_insn_bytes[2] |= (tmp_reg << 0); // set Rn to tmp-reg
ms.plopBytes(L3,vldr_insn_bytes.c_str(),4);
// put down L5, restore of scratch reg r0
auto restore_insn = string("\xfc\x00\x1d\xe5",4);
restore_insn[1] |= (tmp_reg<<4); // set Rd field
ms.plopBytes(L4,restore_insn.c_str(),4);
// put an uncond branch the end of the trampoline
// and make it jump at FT
ms.plopBytes(L5,branch_bytes.c_str(),4);
zo->applyPatch(L5,FT);
// put the calculated pc-rel offset at L3
const auto new_offset = int32_t(orig_insn_addr - L2);
ms.plopBytes(L6,reinterpret_cast<const char*>(&new_offset),4); // endianness of host must match target
// should be few enough of these to always print
cout<< "Had to trampoline " << disasm->getDisassembly() << " @"<<FA<<" to "
<< hex << L0 << "-" << L0+tramp_size-1 << endl;
}
else if( is_ldr_type && !is_rd_pc)
{
/*
* We need to patch an ldr[b][cond] reg, [pc + constant]
......@@ -257,7 +344,7 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
// and make it point at L0
zo->applyPatch(FA,L0);
// spill reg at L0, e50d00fc
// spill tmp_reg at L0, e50d00fc
auto spill_insn = string("\xfc\x00\x0d\xe5",4);
spill_insn[1] |= (tmp_reg<<4);
ms.plopBytes(L0,spill_insn.c_str(),4);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment