diff --git a/core/relinker/relinker/include/relinker/analysis/UnusedNidFilter/IControlFlowGraph.hpp b/core/relinker/relinker/include/relinker/analysis/UnusedNidFilter/IControlFlowGraph.hpp index cc59ed520..a4290599b 100644 --- a/core/relinker/relinker/include/relinker/analysis/UnusedNidFilter/IControlFlowGraph.hpp +++ b/core/relinker/relinker/include/relinker/analysis/UnusedNidFilter/IControlFlowGraph.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace Relinker::UnusedNidFilter { @@ -16,6 +17,25 @@ public: virtual bool IsReachable(VirtualAddress vaddr) const = 0; }; +std::unique_ptr BuildControlFlowGraph( + std::span text, + VirtualAddress textVaddr, + VirtualAddress entryVaddr, + const std::vector& extraEntries, + const IRelativeRelocationIndex& relativeRelocations, + bool followCodeAddresses = false +); + +std::unique_ptr BuildControlFlowGraph( + std::span text, + VirtualAddress textVaddr, + VirtualAddress entryVaddr, + const std::vector& extraEntries, + const IRelativeRelocationIndex& relativeRelocations, + bool followCodeAddresses, + std::unordered_set& reachable +); + std::unique_ptr BuildControlFlowGraph( const std::vector& text, VirtualAddress textVaddr, diff --git a/core/relinker/relinker/src/analysis/CodeInstructionCollector.cpp b/core/relinker/relinker/src/analysis/CodeInstructionCollector.cpp index 2d2a2f3b6..e3a6f2201 100644 --- a/core/relinker/relinker/src/analysis/CodeInstructionCollector.cpp +++ b/core/relinker/relinker/src/analysis/CodeInstructionCollector.cpp @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include namespace Relinker { @@ -273,17 +275,21 @@ std::set CodeInstructionCollector::Collect(const std::ve } } std::size_t previousRoots = 0; + std::unordered_set decodedInstructions; + std::vector> sectionReachable(headers.size()); do { previousRoots = roots.size(); - for (const auto& header : headers) { + for (std::size_t i = 0; i < headers.size(); ++i) { + const auto& header = headers[i]; if (header.Type != 1 || (header.Flags & 1) == 0 || header.FileSize == 0) continue; range(header.Offset, header.FileSize); std::vector entries; 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, true); + const std::span text(bytes.data() + header.Offset, header.FileSize); + const auto graph = UnusedNidFilter::BuildControlFlowGraph(text, header.MappedAddress, entries.front(), entries, pointers, true, sectionReachable[i]); for (const auto address : graph->ReachableVaddrs()) { + if (!decodedInstructions.insert(address).second) continue; instructions.insert(address); const auto offset = address - header.MappedAddress; const auto info = decoder.DecodeInstruction(text.data() + offset, text.size() - offset); diff --git a/core/relinker/relinker/src/analysis/UnusedNidFilter/ControlFlowGraph.cpp b/core/relinker/relinker/src/analysis/UnusedNidFilter/ControlFlowGraph.cpp index b0a99c102..203ae2b08 100644 --- a/core/relinker/relinker/src/analysis/UnusedNidFilter/ControlFlowGraph.cpp +++ b/core/relinker/relinker/src/analysis/UnusedNidFilter/ControlFlowGraph.cpp @@ -9,25 +9,33 @@ namespace Relinker::UnusedNidFilter { class ControlFlowGraph : public IControlFlowGraph { public: explicit ControlFlowGraph(std::unordered_set reachable) - : _reachable(std::move(reachable)) {} + : _owned(std::move(reachable)), _borrowed(nullptr) {} - const std::unordered_set& ReachableVaddrs() const override { return _reachable; } - bool IsReachable(VirtualAddress vaddr) const override { return _reachable.count(vaddr) > 0; } + explicit ControlFlowGraph(const std::unordered_set* reachable) + : _borrowed(reachable) {} + + const std::unordered_set& ReachableVaddrs() const override { + return _borrowed ? *_borrowed : _owned; + } + bool IsReachable(VirtualAddress vaddr) const override { + return (_borrowed ? *_borrowed : _owned).count(vaddr) > 0; + } private: - std::unordered_set _reachable; + std::unordered_set _owned; + const std::unordered_set* _borrowed = nullptr; }; std::unique_ptr BuildControlFlowGraph( - const std::vector& text, + std::span text, VirtualAddress textVaddr, VirtualAddress entryVaddr, const std::vector& extraEntries, const IRelativeRelocationIndex& relativeRelocations, - bool followCodeAddresses + bool followCodeAddresses, + std::unordered_set& reachable ) { const Codegen::X64InstructionDecoder decoder; - std::unordered_set reachable; std::queue worklist; auto enqueue = [&](VirtualAddress va) { @@ -110,7 +118,31 @@ std::unique_ptr BuildControlFlowGraph( } } + return std::make_unique(&reachable); +} + +std::unique_ptr BuildControlFlowGraph( + std::span text, + VirtualAddress textVaddr, + VirtualAddress entryVaddr, + const std::vector& extraEntries, + const IRelativeRelocationIndex& relativeRelocations, + bool followCodeAddresses +) { + std::unordered_set reachable; + BuildControlFlowGraph(text, textVaddr, entryVaddr, extraEntries, relativeRelocations, followCodeAddresses, reachable); return std::make_unique(std::move(reachable)); } +std::unique_ptr BuildControlFlowGraph( + const std::vector& text, + VirtualAddress textVaddr, + VirtualAddress entryVaddr, + const std::vector& extraEntries, + const IRelativeRelocationIndex& relativeRelocations, + bool followCodeAddresses +) { + return BuildControlFlowGraph(std::span(text.data(), text.size()), textVaddr, entryVaddr, extraEntries, relativeRelocations, followCodeAddresses); +} + } diff --git a/core/relinker/relinker/src/analysis/UnusedNidFilter/PltCompactor.cpp b/core/relinker/relinker/src/analysis/UnusedNidFilter/PltCompactor.cpp index 832de8d4f..c21acd03b 100644 --- a/core/relinker/relinker/src/analysis/UnusedNidFilter/PltCompactor.cpp +++ b/core/relinker/relinker/src/analysis/UnusedNidFilter/PltCompactor.cpp @@ -1,15 +1,15 @@ #include #include #include -#include -#include +#include +#include namespace Relinker::UnusedNidFilter { CompactedPlt CompactPlt(const std::vector& originalReferences, const std::vector& keptReferences, const std::vector& text, VirtualAddress textVaddr, FileByteOffset textOffset, FileByteOffset tableOffset) { CompactedPlt result; result.References = keptReferences; - std::map originalSlots; + std::unordered_map originalSlots; for (const auto& reference : originalReferences) { if (reference.RelocationTypeValue != 7) continue; if (reference.RelocationTableOffset < tableOffset || (reference.RelocationTableOffset - tableOffset) % 24 != 0 || (reference.RelocationTableOffset - tableOffset) / 24 > std::numeric_limits::max()) @@ -17,22 +17,21 @@ CompactedPlt CompactPlt(const std::vector& originalReferences, con if (!originalSlots.emplace(reference.RelocationAddress, static_cast((reference.RelocationTableOffset - tableOffset) / 24)).second) throw RelinkerException("Strict filter: duplicate original PLT slot", reference.RelocationAddress); } - std::map newSlots; + std::unordered_map newSlots; for (auto& reference : result.References) { if (reference.RelocationTypeValue != 7) continue; if (!originalSlots.contains(reference.RelocationAddress) || !newSlots.emplace(reference.RelocationAddress, result.SlotCount).second) throw RelinkerException("Strict filter: invalid retained PLT slot", reference.RelocationAddress); reference.RelocationTableOffset = tableOffset + static_cast(result.SlotCount++) * 24; } - std::set found; + std::unordered_set found; for (std::size_t offset = 0; offset + 16 <= text.size(); ++offset) { - if (text[offset] != 0xFF || text[offset + 1] != 0x25) continue; + if (text[offset] != 0xFF || text[offset + 1] != 0x25 || text[offset + 6] != 0x68 || text[offset + 11] != 0xE9) continue; std::int32_t displacement; std::memcpy(&displacement, text.data() + offset + 2, sizeof(displacement)); const auto slot = textVaddr + offset + 6 + static_cast(static_cast(displacement)); const auto original = originalSlots.find(slot); if (original == originalSlots.end()) continue; - if (text[offset + 6] != 0x68 || text[offset + 11] != 0xE9) continue; std::uint32_t index; std::memcpy(&index, text.data() + offset + 7, sizeof(index)); if (index != original->second) throw RelinkerException("Strict filter: PLT thunk index disagrees with its relocation", textVaddr + offset);