diff --git a/core/relinker/relinker/include/relinker/analysis/UnusedNidFilter/IControlFlowGraph.hpp b/core/relinker/relinker/include/relinker/analysis/UnusedNidFilter/IControlFlowGraph.hpp index 421029d69..cc59ed520 100644 --- a/core/relinker/relinker/include/relinker/analysis/UnusedNidFilter/IControlFlowGraph.hpp +++ b/core/relinker/relinker/include/relinker/analysis/UnusedNidFilter/IControlFlowGraph.hpp @@ -21,7 +21,8 @@ std::unique_ptr BuildControlFlowGraph( VirtualAddress textVaddr, VirtualAddress entryVaddr, const std::vector& extraEntries, - const IRelativeRelocationIndex& relativeRelocations + const IRelativeRelocationIndex& relativeRelocations, + bool followCodeAddresses = false ); } diff --git a/core/relinker/relinker/src/analysis/CodeInstructionCollector.cpp b/core/relinker/relinker/src/analysis/CodeInstructionCollector.cpp index b346b598c..2d2a2f3b6 100644 --- a/core/relinker/relinker/src/analysis/CodeInstructionCollector.cpp +++ b/core/relinker/relinker/src/analysis/CodeInstructionCollector.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,11 @@ std::set CodeInstructionCollector::Collect(const std::ve std::set roots; std::map functions; const auto addRoot = [&](std::uint64_t address) { if (isCode(address)) roots.insert(address); }; + const auto addAddressTakenRoot = [&](std::uint64_t address, const std::uint8_t* code, const Codegen::DecodedInstructionInfo& info) { + if (!info.HasRipRelativeDisp || code[info.OpcodeOffset] != 0x8d || !(info.RexPrefix & 8)) return; + const auto displacement = std::bit_cast(Io::ReadU32(bytes, fileOffset(address, info.Length) + info.RipRelativeDispOffset)); + addRoot(address + info.Length + static_cast(displacement)); + }; const auto addFunction = [&](std::uint64_t begin, std::uint64_t size, bool symbolAlias) { if (size == 0) return; if (!isCode(begin) || size > std::numeric_limits::max() - begin) @@ -201,6 +207,7 @@ std::set CodeInstructionCollector::Collect(const std::ve if (info.Length == 0 || info.Length > end - address) throw Domain::RelinkerException("Code analysis: instruction crosses function boundary", address); instructions.insert(address); + addAddressTakenRoot(address, bytes.data() + offset + address - begin, info); if (info.HasBranchTarget && !info.HasRipRelativeDisp) { const auto target = address + info.Length + static_cast(info.BranchDisp); staticTargets.insert(target); @@ -275,11 +282,12 @@ std::set CodeInstructionCollector::Collect(const std::ve for (const auto root : roots) if (root >= header.MappedAddress && root - header.MappedAddress < header.FileSize) entries.push_back(root); if (entries.empty()) continue; const std::vector text(bytes.begin() + header.Offset, bytes.begin() + header.Offset + header.FileSize); - const auto graph = UnusedNidFilter::BuildControlFlowGraph(text, header.MappedAddress, entries.front(), entries, pointers); + const auto graph = UnusedNidFilter::BuildControlFlowGraph(text, header.MappedAddress, entries.front(), entries, pointers, true); for (const auto address : graph->ReachableVaddrs()) { instructions.insert(address); const auto offset = address - header.MappedAddress; const auto info = decoder.DecodeInstruction(text.data() + offset, text.size() - offset); + addAddressTakenRoot(address, text.data() + offset, info); if (info.HasBranchTarget && !info.HasRipRelativeDisp) addRoot(static_cast(static_cast(address + info.Length) + info.BranchDisp)); } } diff --git a/core/relinker/relinker/src/analysis/UnusedNidFilter/ControlFlowGraph.cpp b/core/relinker/relinker/src/analysis/UnusedNidFilter/ControlFlowGraph.cpp index bb98c8277..b0a99c102 100644 --- a/core/relinker/relinker/src/analysis/UnusedNidFilter/ControlFlowGraph.cpp +++ b/core/relinker/relinker/src/analysis/UnusedNidFilter/ControlFlowGraph.cpp @@ -23,7 +23,8 @@ std::unique_ptr BuildControlFlowGraph( VirtualAddress textVaddr, VirtualAddress entryVaddr, const std::vector& extraEntries, - const IRelativeRelocationIndex& relativeRelocations + const IRelativeRelocationIndex& relativeRelocations, + bool followCodeAddresses ) { const Codegen::X64InstructionDecoder decoder; std::unordered_set reachable; @@ -54,6 +55,12 @@ std::unique_ptr BuildControlFlowGraph( VirtualAddress nextVaddr = va + static_cast(info.Length); + if (followCodeAddresses && info.HasRipRelativeDisp && text[bufOff + info.OpcodeOffset] == 0x8d && (info.RexPrefix & 8)) { + std::int32_t displacement = 0; + std::memcpy(&displacement, text.data() + bufOff + info.RipRelativeDispOffset, 4); + enqueue(static_cast(static_cast(nextVaddr) + displacement)); + } + switch (info.FlowKind) { using enum Codegen::ControlFlowKind; case Sequential: diff --git a/core/relinker/relinker/tests/test_tls_function_coverage.py b/core/relinker/relinker/tests/test_tls_function_coverage.py index 420fcc7fb..c675d2aa3 100644 --- a/core/relinker/relinker/tests/test_tls_function_coverage.py +++ b/core/relinker/relinker/tests/test_tls_function_coverage.py @@ -462,6 +462,10 @@ def main(): external[0x1300:0x1310] = external[0x1240:0x1250] external[0x1240:0x1250] = b"\xe8" + struct.pack("