diff --git a/include/sizer/sizer_arm64.hpp b/include/sizer/sizer_arm64.hpp index 8d2f5d53f18ce62e3c4f81c65af01f8a422f5039..0fdc6dce732112a6c14f7b12d7d1be8e0371d302 100644 --- a/include/sizer/sizer_arm64.hpp +++ b/include/sizer/sizer_arm64.hpp @@ -3,9 +3,15 @@ class ZiprSizerARM64_t : public ZiprSizerBase_t { + private: + RangeAddress_t TBZPlopDollopEntryWithTarget (DollopEntry_t *entry, RangeAddress_t override_place, RangeAddress_t override_target) const; + RangeAddress_t DefaultPlopDollopEntryWithTarget(DollopEntry_t *entry, RangeAddress_t override_place, RangeAddress_t override_target) const; + public: - ZiprSizerARM64_t(Zipr_SDK::Zipr_t* p_zipr_obj); - size_t DetermineInsnSize(libIRDB::Instruction_t*, bool account_for_jump = true) const override; + ZiprSizerARM64_t(Zipr_SDK::Zipr_t* p_zipr_obj); + size_t DetermineInsnSize(libIRDB::Instruction_t*, bool account_for_jump = true) const override; + virtual RangeAddress_t PlopDollopEntryWithTarget(DollopEntry_t *entry, RangeAddress_t override_place, RangeAddress_t override_target) const override; + }; #endif diff --git a/include/sizer/sizer_base.hpp b/include/sizer/sizer_base.hpp index cadfab3cc8f73a078b2933f413bc1e1bc84fe967..02176b994f6404d1a0b6ee64f5cde0c052213010 100644 --- a/include/sizer/sizer_base.hpp +++ b/include/sizer/sizer_base.hpp @@ -1,6 +1,7 @@ #ifndef SIZERBASE_HPP #define SIZERBASE_HPP +class ZiprImpl_t; class ZiprSizerBase_t { @@ -8,19 +9,12 @@ class ZiprSizerBase_t ZiprSizerBase_t(Zipr_SDK::Zipr_t* p_zipr_obj, const size_t p_CALLBACK_TRAMPOLINE_SIZE, const size_t p_TRAMPOLINE_SIZE, - const size_t p_LONG_PIN_SIZE, + const size_t p_LONG_PIN_SIZE, const size_t p_SHORT_PIN_SIZE, const size_t p_ALIGNMENT - ) : - memory_space(*dynamic_cast<zipr::ZiprMemorySpace_t*>(p_zipr_obj->GetMemorySpace())), - CALLBACK_TRAMPOLINE_SIZE(p_CALLBACK_TRAMPOLINE_SIZE), - TRAMPOLINE_SIZE (p_TRAMPOLINE_SIZE ), - LONG_PIN_SIZE (p_LONG_PIN_SIZE ), - SHORT_PIN_SIZE (p_SHORT_PIN_SIZE ), - ALIGNMENT (p_ALIGNMENT ) - { - } - zipr::ZiprMemorySpace_t &memory_space; + ) ; + ZiprMemorySpace_t &memory_space; + ZiprImpl_t &m_zipr_obj; public: // methods /** Calculate entire size of a dollop and it's fallthroughs. @@ -33,7 +27,7 @@ class ZiprSizerBase_t virtual size_t DetermineDollopSizeInclFallthrough(Dollop_t *dollop) const; virtual size_t DetermineInsnSize(libIRDB::Instruction_t*, bool account_for_jump = true) const =0; virtual Range_t DoPlacement(size_t pminimum_valid_req_size) const; - + virtual RangeAddress_t PlopDollopEntryWithTarget( DollopEntry_t *entry, RangeAddress_t override_place, RangeAddress_t override_target) const =0; // maybe try to make these private/protected and provide getters eventually. const size_t CALLBACK_TRAMPOLINE_SIZE; diff --git a/include/sizer/sizer_x86.hpp b/include/sizer/sizer_x86.hpp index 418f5aeced1903cacdefc85ed54e31b4372d9d7d..260672a6813e8fc00df7ca2cc33db2e86df639a8 100644 --- a/include/sizer/sizer_x86.hpp +++ b/include/sizer/sizer_x86.hpp @@ -7,6 +7,8 @@ class ZiprSizerX86_t : public ZiprSizerBase_t public: ZiprSizerX86_t(Zipr_SDK::Zipr_t* p_zipr_obj); size_t DetermineInsnSize(libIRDB::Instruction_t*, bool account_for_jump = true) const override; + virtual RangeAddress_t PlopDollopEntryWithTarget( DollopEntry_t *entry, RangeAddress_t override_place, RangeAddress_t override_target) const override; + }; #endif diff --git a/include/zipr_impl.h b/include/zipr_impl.h index 77c6707e44c851b041a33b97ec1c6cd7d8c68727..b7b4981a0721a877a925977c322fc5654660996f 100644 --- a/include/zipr_impl.h +++ b/include/zipr_impl.h @@ -158,6 +158,8 @@ class ZiprImpl_t : public Zipr_t virtual Zipr_SDK::RangeAddress_t PlaceUnplacedScoops(Zipr_SDK::RangeAddress_t max); Stats_t* GetStats() { return m_stats; } ZiprSizerBase_t* GetSizer() { return sizer; } + ZiprPatcherBase_t* GetPatcher() { return patcher; } + ZiprPinnerBase_t* GetPinner() { return pinner; } private: diff --git a/src/sizer_arm64.cpp b/src/sizer_arm64.cpp index 8753185924ff9b714584d392e69f8960c3ec7688..47e567ea2429cbe58f5d538c738420360b79ee72 100644 --- a/src/sizer_arm64.cpp +++ b/src/sizer_arm64.cpp @@ -8,6 +8,12 @@ namespace zipr using namespace zipr ; +static bool is_tbz_type(Instruction_t* insn) +{ + const auto d=DecodedInstruction_t(insn); + return d.getMnemonic()=="tbz" || d.getMnemonic()=="tbnz"; + +} ZiprSizerARM64_t::ZiprSizerARM64_t(Zipr_SDK::Zipr_t* p_zipr_obj) : ZiprSizerBase_t(p_zipr_obj,4,4,4,4,4) { @@ -15,5 +21,70 @@ ZiprSizerARM64_t::ZiprSizerARM64_t(Zipr_SDK::Zipr_t* p_zipr_obj) : ZiprSizerBase size_t ZiprSizerARM64_t::DetermineInsnSize(Instruction_t* insn, bool account_for_jump) const { - return account_for_jump ? 8 : 4; + // tbz plan needs 12 bytes. other plans need 4 + const auto size = is_tbz_type(insn) ? 12 : 4; + const auto jmp_size= account_for_jump ? 4 : 0; + return size + jmp_size; +} + +RangeAddress_t ZiprSizerARM64_t::PlopDollopEntryWithTarget( + DollopEntry_t *entry, + RangeAddress_t override_place, + RangeAddress_t override_target) const +{ + assert(entry->TargetDollop()); + if(is_tbz_type(entry->Instruction())) + return TBZPlopDollopEntryWithTarget(entry,override_place,override_target); + return DefaultPlopDollopEntryWithTarget(entry,override_place,override_target); } + +RangeAddress_t ZiprSizerARM64_t::TBZPlopDollopEntryWithTarget( + DollopEntry_t *entry, + RangeAddress_t override_place, + RangeAddress_t override_target) const +{ +/* tbz plan: + * L0 tbz <args>, L2 + * L1 b L3 + * L2: b <target> + * L3: # fallthrough + */ + const auto addr = (override_place == 0) ? entry->Place() : override_place; + const auto target_addr = (override_target == 0) ? entry->TargetDollop()->Place() : override_target; + const auto insn = entry->Instruction(); + const auto branch_bytes=string("\x00\x00\x00\x014",4); + + // put the tbz first. + memory_space.PlopBytes(addr, insn->GetDataBits().c_str(), 4); + m_zipr_obj.GetPatcher()->ApplyPatch(addr,addr+8);// make it jump to L2 + + // now drop down a uncond jump for L1, and make it go to L3 + // (i.e., jump around the jump to the target) + memory_space.PlopBytes(addr+4, branch_bytes.c_str(), 4); + m_zipr_obj.GetPatcher()->ApplyPatch(addr+4,addr+12);// make it jump to +8 + + // lastly, put down the uncond jump at L2, and make it go to the target + memory_space.PlopBytes(addr+8, branch_bytes.c_str(), 4); + m_zipr_obj.GetPatcher()->ApplyPatch(addr+8,target_addr);// make it jump to +8 + + return addr+12; /* address of fallthrough, L3 */ + +} + + +RangeAddress_t ZiprSizerARM64_t::DefaultPlopDollopEntryWithTarget( + DollopEntry_t *entry, + RangeAddress_t override_place, + RangeAddress_t override_target) const +{ + const auto addr = (override_place == 0) ? entry->Place() : override_place; + const auto target_addr = (override_target == 0) ? entry->TargetDollop()->Place() : override_target; + const auto insn = entry->Instruction(); + + // plop instruction an d make it target the right address. + memory_space.PlopBytes(addr, insn->GetDataBits().c_str(), 4); + m_zipr_obj.GetPatcher()->ApplyPatch(addr, target_addr); + + return addr+4; +} + diff --git a/src/sizer_base.cpp b/src/sizer_base.cpp index 7e5b6fc2a2043bc92c2e3e22379c48ee03a2ffd2..1b19d866ee3cb2b5ef755936a3ecc79a0cba7cb1 100644 --- a/src/sizer_base.cpp +++ b/src/sizer_base.cpp @@ -26,6 +26,24 @@ unique_ptr<ZiprSizerBase_t> ZiprSizerBase_t::factory(Zipr_SDK::Zipr_t* p_zipr_ob return unique_ptr<ZiprSizerBase_t>(ret); } +ZiprSizerBase_t::ZiprSizerBase_t(Zipr_SDK::Zipr_t* p_zipr_obj, + const size_t p_CALLBACK_TRAMPOLINE_SIZE, + const size_t p_TRAMPOLINE_SIZE, + const size_t p_LONG_PIN_SIZE, + const size_t p_SHORT_PIN_SIZE, + const size_t p_ALIGNMENT + ) : + memory_space(*dynamic_cast<zipr::ZiprMemorySpace_t*>(p_zipr_obj->GetMemorySpace())), + m_zipr_obj(*dynamic_cast<zipr::ZiprImpl_t*>(p_zipr_obj)), + CALLBACK_TRAMPOLINE_SIZE(p_CALLBACK_TRAMPOLINE_SIZE), + TRAMPOLINE_SIZE (p_TRAMPOLINE_SIZE ), + LONG_PIN_SIZE (p_LONG_PIN_SIZE ), + SHORT_PIN_SIZE (p_SHORT_PIN_SIZE ), + ALIGNMENT (p_ALIGNMENT ) +{ +} + + Range_t ZiprSizerBase_t::DoPlacement(const size_t size) const { auto new_place=memory_space.GetFreeRange(size+ALIGNMENT-1); diff --git a/src/sizer_x86.cpp b/src/sizer_x86.cpp index 686733297f592f6475dc902b880f91cb98d69bea..756505c4e333aa49428c4b06e955c9516b0668ee 100644 --- a/src/sizer_x86.cpp +++ b/src/sizer_x86.cpp @@ -78,3 +78,131 @@ size_t ZiprSizerX86_t::DetermineInsnSize(Instruction_t* insn, bool account_for_j else return required_size; } + +RangeAddress_t ZiprSizerX86_t::PlopDollopEntryWithTarget( + DollopEntry_t *entry, + RangeAddress_t override_place, + RangeAddress_t override_target) const +{ + auto insn = entry->Instruction(); + + assert(entry->TargetDollop()); + + auto addr = entry->Place(); + auto target_addr = entry->TargetDollop()->Place(); + auto ret = addr; + + if (override_place != 0) + addr = ret = override_place; + + if (override_target != 0) + target_addr = override_target; + + if(insn->GetDataBits().length() >2) + { + memory_space.PlopBytes(ret, + insn->GetDataBits().c_str(), + insn->GetDataBits().length() + ); + m_zipr_obj.GetPatcher()->ApplyPatch(ret, target_addr); + ret+=insn->GetDataBits().length(); + return ret; + } + + // call, jmp, jcc of length 2. + char b=insn->GetDataBits()[0]; + switch(b) + { + case (char)0x70: + case (char)0x71: + case (char)0x72: + case (char)0x73: + case (char)0x74: + case (char)0x75: + case (char)0x76: + case (char)0x77: + case (char)0x78: + case (char)0x79: + case (char)0x7a: + case (char)0x7b: + case (char)0x7c: + case (char)0x7d: + case (char)0x7e: + case (char)0x7f: + { + // two byte JCC + char bytes[]={(char)0x0f,(char)0xc0,(char)0x0,(char)0x0,(char)0x0,(char)0x0 }; // 0xc0 is a placeholder, overwritten next statement + bytes[1]=insn->GetDataBits()[0]+0x10; // convert to jcc with 4-byte offset. + memory_space.PlopBytes(ret,bytes, sizeof(bytes)); + m_zipr_obj.GetPatcher()->ApplyPatch(ret, target_addr); + ret+=sizeof(bytes); + return ret; + } + case (char)0xeb: + { + // two byte JMP + char bytes[]={(char)0xe9,(char)0x0,(char)0x0,(char)0x0,(char)0x0 }; + bytes[1]=insn->GetDataBits()[0]+0x10; // convert to jcc with 4-byte offset. + memory_space.PlopBytes(ret,bytes, sizeof(bytes)); + m_zipr_obj.GetPatcher()->ApplyPatch(ret, target_addr); + ret+=sizeof(bytes); + return ret; + } + case (char)0xe0: + case (char)0xe1: + case (char)0xe2: + case (char)0xe3: + { + // loop, loopne, loopeq, jecxz + // convert to: + // <op> +5: + // jmp fallthrough + // +5: jmp target + char bytes[]={0,0x5}; + DollopEntry_t *fallthrough_de = NULL; + + fallthrough_de = entry->MemberOfDollop()->FallthroughDollopEntry(entry); + + /* + * This means that we have a fallthrough for this dollop entry + * that is actually the fallthrough of the dollop! Wowser. + * TODO: Before doing this, check to make sure that _entry_ + * is the last of the dollop. + */ + if (!fallthrough_de) + { + if(entry->MemberOfDollop()->FallthroughDollop()) + fallthrough_de = entry->MemberOfDollop()->FallthroughDollop()->front(); + else + // even a cond branch may have a null fallthrough, account for that here + // by plopping nothing + return ret; + } + + assert(fallthrough_de && fallthrough_de->IsPlaced()); + + bytes[0]=insn->GetDataBits()[0]; + memory_space.PlopBytes(ret,bytes, sizeof(bytes)); + memory_space.PlopBytes(ret,bytes, sizeof(bytes)); + ret+=sizeof(bytes); + + memory_space.PlopJump(ret); + m_zipr_obj.GetPatcher()->ApplyPatch(ret, fallthrough_de->Place()); + ret+=5; + + memory_space.PlopJump(ret); + m_zipr_obj.GetPatcher()->ApplyPatch(ret, target_addr); + ret+=5; + + return ret; + + } + + default: + assert(0); + } +} + + + + diff --git a/src/zipr.cpp b/src/zipr.cpp index 9dd854e3b0ea6c948b294685ed67a332dafcaef5..8b9bddc763a02edb157133c0bd7dcc321f591f6e 100644 --- a/src/zipr.cpp +++ b/src/zipr.cpp @@ -1949,6 +1949,9 @@ RangeAddress_t ZiprImpl_t::PlopDollopEntryWithTarget( RangeAddress_t override_place, RangeAddress_t override_target) { + return sizer->PlopDollopEntryWithTarget(entry,override_place,override_target); +#if 0 + auto insn = entry->Instruction(); assert(entry->TargetDollop()); @@ -2067,6 +2070,7 @@ RangeAddress_t ZiprImpl_t::PlopDollopEntryWithTarget( default: assert(0); } +#endif } RangeAddress_t ZiprImpl_t::PlopDollopEntryWithCallback(