From 271ae947c0df9fa94a2ee4d2648aeed5fcbfbd05 Mon Sep 17 00:00:00 2001 From: Jason Hiser <jdhiser@gmail.com> Date: Thu, 9 May 2019 14:16:17 -0400 Subject: [PATCH] added vldr patching support --- unpin_arm32.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/unpin_arm32.cpp b/unpin_arm32.cpp index 03c7980..2fe029a 100644 --- a/unpin_arm32.cpp +++ b/unpin_arm32.cpp @@ -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); -- GitLab