Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • opensrc/zipr_unpin_plugin
1 result
Show changes
Commits on Source (2)
......@@ -36,6 +36,7 @@
#include <inttypes.h>
#include <stdint.h>
#include <limits.h>
#include <irdb-util>
using namespace IRDB_SDK;
......@@ -87,34 +88,23 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
assert(0);
};
// get the new insn addr
const auto from_insn_location=(VirtualOffset_t)locMap[from_insn];
const auto from_insn_location = VirtualOffset_t(locMap[from_insn]);
// get WRT info
auto to_addr=VirtualOffset_t(0xdeadbeef); // noteable value that shouldn't be used.
auto convert_string=string();
const auto to_addr =
(scoop_wrt != nullptr) ? scoop_wrt->getStart()->getVirtualOffset() : // is scoop
(insn_wrt != nullptr) ? locMap[insn_wrt] : // is instruction
(bo_wrt == nullptr) ? VirtualOffset_t(0u) : // no WRT obj
throw invalid_argument("Cannot map pcrel relocation WRT object to address");
const auto addend = reloc -> getAddend();
const auto reloc_offset = to_addr + addend;
if(scoop_wrt)
{
to_addr=scoop_wrt->getStart()->getVirtualOffset();
convert_string=string("scoop ")+scoop_wrt->getName();
}
else if(insn_wrt)
{
to_addr=locMap[insn_wrt];
convert_string=string("insn ")+to_string(insn_wrt->getBaseID())+
":"+insn_wrt->getDisassembly();
}
else
{
assert(bo_wrt==nullptr);
to_addr=0; /* no WRT obj */
convert_string=string("no-object");
}
assert(bo_wrt==nullptr); // not yet imp'd WRT offsetting.
assert(to_addr==0); // not yet imp'd WRT offsetting.
const auto to_object_id =
(scoop_wrt != nullptr) ? scoop_wrt->getName() +"@"+to_hex_string(scoop_wrt->getStart() ->getVirtualOffset()) : // scoop
(insn_wrt != nullptr) ? insn_wrt ->getDisassembly()+"@"+to_hex_string(insn_wrt ->getAddress()->getVirtualOffset()) : // instruction
(bo_wrt == nullptr) ? string("No-object") :
throw invalid_argument("Cannot map pcrel relocation WRT object to address");
// so far, only handling ldr and ldrb
......@@ -216,15 +206,15 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
zo->applyPatch(L5,FT);
// put the calculated pc-rel offset at L3
const auto new_offset = int32_t(orig_insn_addr - L2);
const auto new_offset = int32_t(orig_insn_addr - L2 + reloc_offset);
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;
<< hex << L0 << "-" << L0+tramp_size-1 << " WRT=" << to_object_id << endl;
}
else if( is_ldr_type && !is_rd_pc)
else if( is_ldr_type && !is_rd_pc && !I_bit_set) /* ldr <not pc>, [pc, imm] */
{
/*
* We need to patch an ldr[b][cond] reg, [pc + constant]
......@@ -289,13 +279,103 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
// put the calculated pc-rel offset at L3
const auto ldr_imm_field = int32_t(full_insn & mask12);
const auto ldr_imm = is_pos_imm ? ldr_imm_field : - ldr_imm_field;
const auto orig_target = orig_insn_addr + 8 + to_addr + ldr_imm;
const auto new_offset = int32_t(orig_target - (L1+8));
const auto new_addend = bo_wrt == nullptr ? 8 + ldr_imm : reloc_offset;
const auto new_offset = int32_t(orig_insn_addr - L3 + new_addend);
ms.plopBytes(L3,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 << " ldr_imm = " << ldr_imm << endl;
<< hex << L0 << "-" << L0+tramp_size-1 << " ldr_imm = " << ldr_imm << " WRT=" << to_object_id << endl;
}
else if( is_ldr_type && !is_rd_pc && I_bit_set) /* ldr <not pc>, [pc, reg/shift] */
{
/*
* We need to patch a ldr Rd [pc, Rm <shift type> <shift amt>]@FA
* to be at a new location.
*
* The plan:
* FA: bne L0
* FT:
* ..
* L0: str Rt, [sp, # - fc] # spill tmp reg (Rt), use tmp_reg instead of r0
* L1: ldr Rt, [pc, #k] # where L1+8+k == L6 or k = L6-L1-8
* L2: add Rt, pc, Rt # add in pc
* L3: ldr Rd, [Rt, Rm <shift type> <shift smt> ]
* # copy of orig insn with pc (Rn field) replaced with Rt.
* L4: ldr Rt, [sp, # - fc] # spill tmp reg (Rt), use tmp_reg instead of r0
* L5: b FT
* L6: .word L2 - orig_insn_addr
*/
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 tramp_size bytes.
ms.splitFreeRange({tramp_start,tramp_start+tramp_size});
// and give the bytes some names
const auto FA = from_insn_location;
const auto FT = FA + 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);
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);
ms.plopBytes(L1,ldr_imm_insn.c_str(),4);
// put down L2
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 L3 (orig insn with pc fields set to r0)
auto orig_ldr = from_insn->getDataBits();
orig_ldr[3] &= 0b00001111; // clear the cond bits.
orig_ldr[3] |= 0b11100000; // set the cond bits to "always".
orig_ldr[2] &= ~(mask4 << 0); // clear this instruction's Rn field (i.e., set to r0)
orig_ldr[2] |= (tmp_reg<<0); // set Rn fields o tmp_reg
ms.plopBytes(L3,orig_ldr.c_str(),4);
// put down L4, 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 L6
const auto new_offset = int32_t(orig_insn_addr - L2 + reloc_offset);
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() << " @" << hex << FA
<< " to " << L0 << "-" << L0+tramp_size-1 << " WRT=" << to_object_id << endl;
}
else if((is_ldrls_type || is_addne_type || is_addls_type) && is_rd_pc && is_rn_pc)
{
......@@ -366,8 +446,8 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
orig_add[3] |= 0b11100000; // set the cond bits to "always".
orig_add[1] &= ~(mask4 << 4); // clear this instruction's Rd field (i.e., set to r0)
orig_add[2] &= ~(mask4 << 0); // clear this instruction's Rn field (i.e., set to r0)
orig_add[1] |= (tmp_reg<<4); // set Rd and Rn fields to tmp_reg
orig_add[2] |= (tmp_reg<<0);
orig_add[1] |= (tmp_reg<<4); // set Rd and Rn fields to tmp_reg
orig_add[2] |= (tmp_reg<<0);
ms.plopBytes(L3,orig_add.c_str(),4);
// put down L4, store of calc'd pc.
......@@ -386,13 +466,12 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
ms.plopBytes(L6,xfer_insn.c_str(),4);
// put the calculated pc-rel offset at L7
const auto new_offset = orig_insn_addr - L2;
const auto new_offset = int32_t(orig_insn_addr - L2 + reloc_offset);
ms.plopBytes(L7,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;
<< hex << L0 << "-" << L0+tramp_size-1 << " WRT=" << to_object_id << endl;
}
else if(is_add_type && I_bit_set)
{
......@@ -458,13 +537,13 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
const auto add_imm_field = int32_t(full_insn & mask8);
const auto add_ror_field = int32_t((full_insn>>8) & mask4);
const auto add_imm = rotr32(add_imm_field,add_ror_field*2);
const auto orig_target = orig_insn_addr + 8 + to_addr + add_imm;
const auto new_offset = int32_t(orig_target - (L1+8));
const auto orig_target = orig_insn_addr + 8 + add_imm;
const auto new_offset = int32_t(orig_target - L3 + reloc_offset);
ms.plopBytes(L3,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 << " add_imm = " << add_imm << endl;
<< hex << L0 << "-" << L0+tramp_size-1 << " add_imm = " << add_imm << " WRT=" << to_object_id << endl;
}
else if(is_add_type && !I_bit_set)
{
......@@ -564,12 +643,12 @@ void UnpinArm32_t::HandlePcrelReloc(Instruction_t* from_insn, Relocation_t* relo
zo->applyPatch(L5,FT);
// put the calculated pc-rel offset at L3
const auto new_offset = int32_t(orig_insn_addr - L1);
const auto new_offset = int32_t(orig_insn_addr - L1 + reloc_offset);
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;
<< hex << L0 << "-" << L0+tramp_size-1 << " WRT=" << to_object_id << endl;
}
else
{
......