From 267e19b85405d263371341fd5690ef7398738fef Mon Sep 17 00:00:00 2001 From: Sajid Date: Mon, 9 Sep 2024 22:52:34 +0600 Subject: [PATCH] Handle branch fallthrough --- PowerAnalyse/function.cpp | 62 ++++++++++++++++++++++--------- PowerAnalyse/function.h | 15 +++++--- PowerAnalyse/main.cpp | 6 +-- tests/PowerAnalyse/cond-fall.cpp | 15 ++++++++ tests/PowerAnalyse/cond-fall.elf | Bin 0 -> 820 bytes 5 files changed, 71 insertions(+), 27 deletions(-) create mode 100644 tests/PowerAnalyse/cond-fall.cpp create mode 100644 tests/PowerAnalyse/cond-fall.elf diff --git a/PowerAnalyse/function.cpp b/PowerAnalyse/function.cpp index 81843cc..91d94c7 100644 --- a/PowerAnalyse/function.cpp +++ b/PowerAnalyse/function.cpp @@ -3,7 +3,7 @@ #include #include -size_t function::SearchBlock(size_t address) const +size_t Function::SearchBlock(size_t address) const { if (address < base) { @@ -25,18 +25,22 @@ size_t function::SearchBlock(size_t address) const return -1; } -function function::Analyze(const void* code, size_t size, size_t base) +Function Function::Analyze(const void* code, size_t size, size_t base) { - function fn{ base, 0 }; + Function fn{ base, 0 }; auto& blocks = fn.blocks; + blocks.reserve(8); blocks.emplace_back(); const auto* data = (uint32_t*)code; const auto* dataStart = data; const auto* dataEnd = (uint32_t*)((uint8_t*)code + size); std::vector blockStack{}; + blockStack.reserve(32); blockStack.emplace_back(); + #define RESTORE_DATA() if (!blockStack.empty()) data = (dataStart + (blocks[blockStack.back()].base / sizeof(*data))) - 1; // continue adds one + // TODO: Branch fallthrough for (; data <= dataEnd ; ++data) { @@ -46,6 +50,7 @@ function function::Analyze(const void* code, size_t size, size_t base) break; // it's hideover } + auto& curBlock = blocks[blockStack.back()]; const auto instruction = std::byteswap(*data); const auto op = PPC_OP(instruction); @@ -55,12 +60,28 @@ function function::Analyze(const void* code, size_t size, size_t base) ppc_insn insn; ppc::Disassemble(data, addr, insn); - blocks[blockStack.back()].size += 4; + if (curBlock.base == 0x28) + { + printf(""); + } + + if (curBlock.projectedSize != -1 && curBlock.size >= curBlock.projectedSize) // fallthrough + { + blockStack.pop_back(); + RESTORE_DATA(); + continue; + } + + curBlock.size += 4; if (op == PPC_OP_BC) // conditional branches all originate from one opcode, thanks RISC { - // this one ends here - blockStack.pop_back(); + if (isLink) // just a conditional call, nothing to see here + { + continue; + } + curBlock.projectedSize = -1; + blockStack.pop_back(); // true/false paths // left block: false case // right block: true case @@ -73,7 +94,7 @@ function function::Analyze(const void* code, size_t size, size_t base) if (lBlock == -1) { - blocks.emplace_back(lBase, 0); + blocks.emplace_back(lBase, 0).projectedSize = rBase - lBase; lBlock = blocks.size() - 1; } @@ -83,21 +104,18 @@ function function::Analyze(const void* code, size_t size, size_t base) blockStack.emplace_back(lBlock); } - if (!isLink) // not a call, scan this too + auto rBlock = fn.SearchBlock(base + rBase); + if (rBlock == -1) { - auto rBlock = fn.SearchBlock(base + rBase); - if (rBlock == -1) - { - blocks.emplace_back(insn.operands[1] - base, 0); - rBlock = blocks.size() - 1; + blocks.emplace_back(insn.operands[1] - base, 0); + rBlock = blocks.size() - 1; - blockStack.emplace_back(rBlock); - } + blockStack.emplace_back(rBlock); } if (!blockStack.empty()) { - data = (dataStart + (blocks[blockStack.back()].base / sizeof(*data))) - 1; // loop will add one + RESTORE_DATA(); } } else if (op == PPC_OP_B || (op == PPC_OP_CTR && xop == 16) || instruction == 0) // b, blr, end padding @@ -113,16 +131,24 @@ function function::Analyze(const void* code, size_t size, size_t base) const auto branchBase = insn.operands[0] - base; const auto branchBlock = fn.SearchBlock(insn.operands[0]); + const auto isContinious = branchBase == curBlock.base + curBlock.size; + auto sizeProjection = (size_t)-1; + + if (isContinious && curBlock.projectedSize != -1) + { + sizeProjection = curBlock.projectedSize - curBlock.size; + } + if (branchBlock == -1) { - blocks.emplace_back(branchBase, 0); + blocks.emplace_back(branchBase, 0, sizeProjection); blockStack.emplace_back(blocks.size() - 1); } } if (!blockStack.empty()) { - data = (dataStart + (blocks[blockStack.back()].base / sizeof(*data))) - 1; + RESTORE_DATA(); } } } diff --git a/PowerAnalyse/function.h b/PowerAnalyse/function.h index 0044d19..917ab70 100644 --- a/PowerAnalyse/function.h +++ b/PowerAnalyse/function.h @@ -1,18 +1,21 @@ #pragma once #include -struct function +struct Function { - struct block + struct Block { - size_t base; - size_t size; + size_t base{}; + size_t size{}; + + // scratch + size_t projectedSize{ static_cast(-1) }; }; size_t base{}; size_t size{}; - std::vector blocks{}; + std::vector blocks{}; size_t SearchBlock(size_t address) const; - static function Analyze(const void* code, size_t size, size_t base); + static Function Analyze(const void* code, size_t size, size_t base); }; diff --git a/PowerAnalyse/main.cpp b/PowerAnalyse/main.cpp index bf1902b..88feef6 100644 --- a/PowerAnalyse/main.cpp +++ b/PowerAnalyse/main.cpp @@ -7,7 +7,7 @@ int main() { - const auto file = LoadFile("cond.elf"); + const auto file = LoadFile("cond-fall.elf"); auto image = Image::ParseImage(file.data(), file.size()).value(); for (const auto& section : image.sections) @@ -20,7 +20,7 @@ int main() //ppc::Disassemble(c, 0x831D6C64, insn); //std::println("{:20}{}", insn.opcode->name, insn.op_str); - std::vector functions; + std::vector functions; for (const auto& section : image.sections) { if (!(section.flags & SectionFlags_Code)) @@ -40,7 +40,7 @@ int main() continue; } - const auto& fn = functions.emplace_back(function::Analyze(data, dataEnd - data, base)); + const auto& fn = functions.emplace_back(Function::Analyze(data, dataEnd - data, base)); data += fn.size; base += fn.size; diff --git a/tests/PowerAnalyse/cond-fall.cpp b/tests/PowerAnalyse/cond-fall.cpp new file mode 100644 index 0000000..f2b439f --- /dev/null +++ b/tests/PowerAnalyse/cond-fall.cpp @@ -0,0 +1,15 @@ +int cond(int a) +{ + int v = 2; + if (a == 1) + { + v += 5; + } + + return v; +} + +extern "C" int _start() +{ + return cond(0); +} diff --git a/tests/PowerAnalyse/cond-fall.elf b/tests/PowerAnalyse/cond-fall.elf new file mode 100644 index 0000000000000000000000000000000000000000..637d89f531077d12061ae1a554e35273241ef2d3 GIT binary patch literal 820 zcmb7C!D`z;6nrb&X+l$CiVr>*BH!GQD01<^^pYIXV5lkNS_-x!E3K$38%YEQ3^D1Y z$3Xf4?Zw}c56B19klx#CF6zvBReH#!1G8`5&ePjn?Owj_9xF@9UszIsR%NAj5nCcw zO?xe|r6dh`f>C6RUfB@(n_&@=EP!|LHKCsw(&J)!LHI%fOT*&I(c^tti6*?MVTsN# z{dt1?F>qh99|ouU;m}FOPLui9diLXHDYe~561ky{=L7bxh|A2cX zE#5gI$ve-HpJf9R)NAG}JP+?S2j2&=1+va%0{I@p3oTazJ+cb&Ul^z_5QiY&0q5C| ePs|4SCJodr#LGNGWG`X|{I~7_`8Ev$UH1oxm}b}j literal 0 HcmV?d00001