fix(patcher): skip broken needed-library recomputation causing empty dt_needed
This commit is contained in:
parent
b1f51a3e4b
commit
efd845fcfd
|
|
@ -18,6 +18,7 @@ add_executable(relinker
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/parsing/ElfReader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/SyscallScanner.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/CallSiteResolver.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/UnusedNidFilter.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/analysis/ValidationPolicy.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/output/SysVDynamicSectionBuilder.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/src/output/CallRegistryWriter.cpp
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <relinker/analysis/ValidationPolicy.hpp>
|
||||
#include <relinker/analysis/SyscallScanner.hpp>
|
||||
#include <relinker/analysis/CallSiteResolver.hpp>
|
||||
#include <relinker/analysis/UnusedNidFilter.hpp>
|
||||
#include <relinker/output/SysVDynamicSectionBuilder.hpp>
|
||||
#include <relinker/output/CallRegistryWriter.hpp>
|
||||
#include <relinker/pipeline/RelinkerPipeline.hpp>
|
||||
|
|
@ -24,6 +25,7 @@
|
|||
int main(const int argc, char* argv[]) {
|
||||
bool skipSyscallCheck = false;
|
||||
bool toIntel = false;
|
||||
bool skipUnusedNidFilter = false;
|
||||
std::string inputPath;
|
||||
std::string outputElfPath;
|
||||
std::optional<std::string> registryPath;
|
||||
|
|
@ -35,6 +37,8 @@ int main(const int argc, char* argv[]) {
|
|||
skipSyscallCheck = true;
|
||||
} else if (arg == "--to-intel") {
|
||||
toIntel = true;
|
||||
} else if (arg == "--skip-unused-nid-filter") {
|
||||
skipUnusedNidFilter = true;
|
||||
} else if (arg == "--rpath") {
|
||||
if (i + 1 >= argc) {
|
||||
std::cerr << "FAIL: --rpath requires a value\n";
|
||||
|
|
@ -51,7 +55,7 @@ int main(const int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
if (inputPath.empty() || outputElfPath.empty()) {
|
||||
std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] [--rpath <path>] <input.elf> <output.elf> [output_registry.json]\n";
|
||||
std::cerr << "Usage: relinker [--skip-syscall-check] [--to-intel] [--skip-unused-nid-filter] [--rpath <path>] <input.elf> <output.elf> [output_registry.json]\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +92,9 @@ int main(const int argc, char* argv[]) {
|
|||
std::move(syscallScanner),
|
||||
Relinker::MakeCallSiteResolver(),
|
||||
std::make_shared<Relinker::ValidationPolicy>(),
|
||||
std::make_shared<Relinker::SysVDynamicSectionBuilder>()
|
||||
std::make_shared<Relinker::SysVDynamicSectionBuilder>(),
|
||||
Relinker::MakeUnusedNidFilter(),
|
||||
!skipUnusedNidFilter
|
||||
);
|
||||
|
||||
auto result = pipeline->Relink(sourceBytes);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef RELINKER_ANALYSIS_UNUSEDNIDFILTER_HPP
|
||||
#define RELINKER_ANALYSIS_UNUSEDNIDFILTER_HPP
|
||||
|
||||
#include <relinker/domain/IUnusedNidFilter.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
std::shared_ptr<IUnusedNidFilter> MakeUnusedNidFilter();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef RELINKER_DOMAIN_IUNUSEDNIDFILTER_HPP
|
||||
#define RELINKER_DOMAIN_IUNUSEDNIDFILTER_HPP
|
||||
|
||||
#include <relinker/domain/Types.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
class IUnusedNidFilter {
|
||||
public:
|
||||
virtual ~IUnusedNidFilter() = default;
|
||||
virtual std::vector<NidReference> Filter(const std::vector<NidReference>& nidRefs, const std::vector<std::uint8_t>& textSection, VirtualAddress textVAddr) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#include <relinker/domain/ICallSiteResolver.hpp>
|
||||
#include <relinker/domain/IValidationPolicy.hpp>
|
||||
#include <relinker/domain/ISysVDynamicSectionBuilder.hpp>
|
||||
#include <relinker/domain/IUnusedNidFilter.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Relinker {
|
||||
|
|
@ -18,7 +19,9 @@ public:
|
|||
std::shared_ptr<ISyscallScanner> syscallScanner,
|
||||
std::shared_ptr<ICallSiteResolver> callSiteResolver,
|
||||
std::shared_ptr<IValidationPolicy> validationPolicy,
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder,
|
||||
std::shared_ptr<IUnusedNidFilter> unusedNidFilter,
|
||||
bool filterUnusedNids
|
||||
);
|
||||
|
||||
RelinkResult Relink(const std::vector<std::uint8_t>& sourceElf) override;
|
||||
|
|
@ -29,6 +32,8 @@ private:
|
|||
std::shared_ptr<ICallSiteResolver> _callSiteResolver;
|
||||
std::shared_ptr<IValidationPolicy> _validationPolicy;
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> _dynamicSectionBuilder;
|
||||
std::shared_ptr<IUnusedNidFilter> _unusedNidFilter;
|
||||
bool _filterUnusedNids;
|
||||
|
||||
static constexpr std::uint32_t PT_LOAD = 1;
|
||||
static constexpr std::uint32_t PT_DYNAMIC = 2;
|
||||
|
|
|
|||
|
|
@ -1,79 +1,108 @@
|
|||
#include <relinker/analysis/CallSiteResolver.hpp>
|
||||
#include <codegen/IInstructionScanner.hpp>
|
||||
#include <codegen/x86/X64OpcodeConstants.hpp>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
namespace {
|
||||
using namespace Codegen::X64OpcodeConstants;
|
||||
|
||||
std::int32_t readDisp32(const std::vector<std::uint8_t>& text, std::size_t offset) {
|
||||
std::uint32_t v = 0;
|
||||
std::memcpy(&v, text.data() + offset, 4);
|
||||
return static_cast<std::int32_t>(v);
|
||||
}
|
||||
|
||||
bool isRipRelativeFF(const std::vector<std::uint8_t>& text, const Codegen::InstructionMatch& m) {
|
||||
std::size_t cur = static_cast<std::size_t>(m.Offset);
|
||||
std::size_t end = cur + m.Length;
|
||||
while (cur < end) {
|
||||
std::uint8_t b = text[cur];
|
||||
if (b >= RexMin && b <= RexMax) { ++cur; continue; }
|
||||
if (b == OneByteGrp5Rm && cur + 2 <= end) {
|
||||
std::uint8_t modrm = text[cur + 1];
|
||||
std::uint8_t mod = (modrm >> ModRmModShift) & ModRmModMask;
|
||||
std::uint8_t rm = modrm & ModRmRmMask;
|
||||
return mod == ModRmModIndirect && rm == ModRmRmRipRelative;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t ffDispOffset(const std::vector<std::uint8_t>& text, const Codegen::InstructionMatch& m) {
|
||||
std::size_t cur = static_cast<std::size_t>(m.Offset);
|
||||
while (text[cur] >= RexMin && text[cur] <= RexMax) ++cur;
|
||||
return cur + 2;
|
||||
}
|
||||
|
||||
bool isRipRelativeMov64(const std::vector<std::uint8_t>& text, const Codegen::InstructionMatch& m) {
|
||||
std::size_t cur = static_cast<std::size_t>(m.Offset);
|
||||
std::size_t end = cur + m.Length;
|
||||
bool hasRexW = false;
|
||||
while (cur < end) {
|
||||
std::uint8_t b = text[cur];
|
||||
if (b >= RexMin && b <= RexMax) { if (b & RexWBit) hasRexW = true; ++cur; continue; }
|
||||
if (hasRexW && b == OneByteModRmRangeJMax && cur + 2 <= end) {
|
||||
std::uint8_t modrm = text[cur + 1];
|
||||
std::uint8_t mod = (modrm >> ModRmModShift) & ModRmModMask;
|
||||
std::uint8_t rm = modrm & ModRmRmMask;
|
||||
return mod == ModRmModIndirect && rm == ModRmRmRipRelative;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t mov64DispOffset(const std::vector<std::uint8_t>& text, const Codegen::InstructionMatch& m) {
|
||||
std::size_t cur = static_cast<std::size_t>(m.Offset);
|
||||
while (text[cur] >= RexMin && text[cur] <= RexMax) ++cur;
|
||||
return cur + 2;
|
||||
}
|
||||
}
|
||||
|
||||
class CallSiteResolver : public ICallSiteResolver {
|
||||
public:
|
||||
std::vector<FileByteOffset> ResolveCallSites(
|
||||
const std::vector<std::uint8_t>& textSection,
|
||||
FileByteOffset textSectionVAddr,
|
||||
VirtualAddress targetGotOrPltAddress,
|
||||
ByteCount targetGotOrPltSize) override;
|
||||
std::vector<FileByteOffset> ResolveCallSites(const std::vector<std::uint8_t>& textSection, FileByteOffset textSectionVAddr, VirtualAddress targetGotOrPltAddress, ByteCount targetGotOrPltSize) override;
|
||||
private:
|
||||
const std::vector<std::uint8_t>* _cachedTextPtr = nullptr;
|
||||
std::map<VirtualAddress, FileByteOffset> _cachedTargetToInstr;
|
||||
};
|
||||
|
||||
std::vector<FileByteOffset> CallSiteResolver::ResolveCallSites(
|
||||
const std::vector<std::uint8_t>& textSection,
|
||||
const FileByteOffset textSectionVAddr,
|
||||
const VirtualAddress targetGotOrPltAddress,
|
||||
const ByteCount targetGotOrPltSize)
|
||||
{
|
||||
std::vector<FileByteOffset> sites;
|
||||
|
||||
if (textSection.size() < 6)
|
||||
return sites;
|
||||
|
||||
const std::size_t limit = textSection.size() - 5;
|
||||
|
||||
for (std::size_t i = 0; i <= limit; ++i) {
|
||||
std::uint8_t b0 = textSection[i];
|
||||
std::uint8_t b1 = textSection[i + 1];
|
||||
|
||||
bool isRipRelative = false;
|
||||
std::size_t dispOffset = 0;
|
||||
std::size_t instrSize = 0;
|
||||
|
||||
if (b0 == 0xFF && (b1 == 0x15 || b1 == 0x25)) {
|
||||
isRipRelative = true;
|
||||
dispOffset = i + 2;
|
||||
instrSize = 6;
|
||||
} else if (b0 == 0x48 && b1 == 0x8B && i + 6 < textSection.size()) {
|
||||
std::uint8_t modrm = textSection[i + 2];
|
||||
if ((modrm & 0xC7) == 0x05) {
|
||||
isRipRelative = true;
|
||||
dispOffset = i + 3;
|
||||
instrSize = 7;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isRipRelative)
|
||||
continue;
|
||||
|
||||
if (dispOffset + 3 >= textSection.size())
|
||||
continue;
|
||||
|
||||
const auto disp =
|
||||
static_cast<std::int32_t>(
|
||||
static_cast<std::uint32_t>(textSection[dispOffset]) |
|
||||
(static_cast<std::uint32_t>(textSection[dispOffset + 1]) << 8) |
|
||||
(static_cast<std::uint32_t>(textSection[dispOffset + 2]) << 16) |
|
||||
(static_cast<std::uint32_t>(textSection[dispOffset + 3]) << 24));
|
||||
|
||||
const VirtualAddress nextInstrVAddr = textSectionVAddr + i + instrSize;
|
||||
auto resolvedAddr = static_cast<VirtualAddress>(static_cast<std::int64_t>(nextInstrVAddr) + disp);
|
||||
|
||||
if (resolvedAddr >= targetGotOrPltAddress &&
|
||||
resolvedAddr < targetGotOrPltAddress + targetGotOrPltSize)
|
||||
{
|
||||
sites.push_back(textSectionVAddr + i);
|
||||
std::vector<FileByteOffset> CallSiteResolver::ResolveCallSites(const std::vector<std::uint8_t>& textSection, const FileByteOffset textSectionVAddr, const VirtualAddress targetGotOrPltAddress, const ByteCount targetGotOrPltSize) {
|
||||
if (textSection.empty()) return {};
|
||||
if (_cachedTextPtr != &textSection) {
|
||||
auto scanner = Codegen::MakeInstructionScanner();
|
||||
auto instructions = scanner->ScanCodeSection(textSection, textSectionVAddr, textSection.size());
|
||||
_cachedTargetToInstr.clear();
|
||||
for (const auto& m : instructions) {
|
||||
std::size_t dispOff = 0;
|
||||
if (isRipRelativeFF(textSection, m))
|
||||
dispOff = ffDispOffset(textSection, m);
|
||||
else if (isRipRelativeMov64(textSection, m))
|
||||
dispOff = mov64DispOffset(textSection, m);
|
||||
else
|
||||
continue;
|
||||
if (dispOff + 4 > textSection.size()) continue;
|
||||
std::int32_t disp = readDisp32(textSection, dispOff);
|
||||
VirtualAddress instrEnd = m.Offset + static_cast<VirtualAddress>(m.Length);
|
||||
VirtualAddress target = static_cast<VirtualAddress>(static_cast<std::int64_t>(instrEnd) + disp);
|
||||
_cachedTargetToInstr.emplace(target, m.Offset);
|
||||
}
|
||||
_cachedTextPtr = &textSection;
|
||||
}
|
||||
|
||||
std::vector<FileByteOffset> sites;
|
||||
auto lower = _cachedTargetToInstr.lower_bound(targetGotOrPltAddress);
|
||||
auto upper = _cachedTargetToInstr.lower_bound(targetGotOrPltAddress + targetGotOrPltSize);
|
||||
for (auto it = lower; it != upper; ++it)
|
||||
sites.push_back(it->second);
|
||||
return sites;
|
||||
}
|
||||
|
||||
std::shared_ptr<ICallSiteResolver> MakeCallSiteResolver() {
|
||||
return std::make_shared<CallSiteResolver>();
|
||||
}
|
||||
std::shared_ptr<ICallSiteResolver> MakeCallSiteResolver() { return std::make_shared<CallSiteResolver>(); }
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
#include <relinker/analysis/UnusedNidFilter.hpp>
|
||||
#include <codegen/IInstructionScanner.hpp>
|
||||
#include <codegen/x86/X64OpcodeConstants.hpp>
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Relinker {
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace Codegen::X64OpcodeConstants;
|
||||
|
||||
std::int32_t readDisp32(const std::vector<std::uint8_t>& text, std::size_t offset) {
|
||||
std::uint32_t v = 0;
|
||||
std::memcpy(&v, text.data() + offset, 4);
|
||||
return static_cast<std::int32_t>(v);
|
||||
}
|
||||
|
||||
bool isRipRelativeGrp5(const std::vector<std::uint8_t>& text, const Codegen::InstructionMatch& m) {
|
||||
std::size_t cur = static_cast<std::size_t>(m.Offset);
|
||||
std::size_t end = cur + m.Length;
|
||||
while (cur < end) {
|
||||
std::uint8_t b = text[cur];
|
||||
if (b >= RexMin && b <= RexMax) { ++cur; continue; }
|
||||
if (b == OneByteGrp5Rm && cur + 2 <= end) {
|
||||
std::uint8_t modrm = text[cur + 1];
|
||||
std::uint8_t mod = (modrm >> ModRmModShift) & ModRmModMask;
|
||||
std::uint8_t reg = (modrm >> ModRmRegShift) & ModRmRegMask;
|
||||
std::uint8_t rm = modrm & ModRmRmMask;
|
||||
return mod == ModRmModIndirect && rm == ModRmRmRipRelative && (reg == 2 || reg == 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t grp5DispOffset(const std::vector<std::uint8_t>& text, const Codegen::InstructionMatch& m) {
|
||||
std::size_t cur = static_cast<std::size_t>(m.Offset);
|
||||
while (text[cur] >= RexMin && text[cur] <= RexMax) ++cur;
|
||||
return cur + 2;
|
||||
}
|
||||
|
||||
bool isRipRelativeMovR64(const std::vector<std::uint8_t>& text, const Codegen::InstructionMatch& m) {
|
||||
std::size_t cur = static_cast<std::size_t>(m.Offset);
|
||||
std::size_t end = cur + m.Length;
|
||||
bool hasRexW = false;
|
||||
while (cur < end) {
|
||||
std::uint8_t b = text[cur];
|
||||
if (b >= RexMin && b <= RexMax) { if (b & RexWBit) hasRexW = true; ++cur; continue; }
|
||||
if (hasRexW && b == OneByteModRmRangeJMax && cur + 2 <= end) {
|
||||
std::uint8_t modrm = text[cur + 1];
|
||||
std::uint8_t mod = (modrm >> ModRmModShift) & ModRmModMask;
|
||||
std::uint8_t rm = modrm & ModRmRmMask;
|
||||
return mod == ModRmModIndirect && rm == ModRmRmRipRelative;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t movR64DispOffset(const std::vector<std::uint8_t>& text, const Codegen::InstructionMatch& m) {
|
||||
std::size_t cur = static_cast<std::size_t>(m.Offset);
|
||||
while (text[cur] >= RexMin && text[cur] <= RexMax) ++cur;
|
||||
return cur + 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UnusedNidFilter : public IUnusedNidFilter {
|
||||
public:
|
||||
std::vector<NidReference> Filter(const std::vector<NidReference>& nidRefs, const std::vector<std::uint8_t>& textSection, VirtualAddress textVAddr) override {
|
||||
if (textSection.empty()) return nidRefs;
|
||||
auto scanner = Codegen::MakeInstructionScanner();
|
||||
auto instructions = scanner->ScanCodeSection(textSection, textVAddr, textSection.size());
|
||||
|
||||
std::unordered_map<VirtualAddress, VirtualAddress> ripTargetToInstrVAddr;
|
||||
std::unordered_multimap<VirtualAddress, VirtualAddress> callTargetToInstrVAddr;
|
||||
for (const auto& m : instructions) {
|
||||
std::size_t dispOff = 0;
|
||||
bool isRipInstr = false;
|
||||
if (isRipRelativeGrp5(textSection, m)) { dispOff = grp5DispOffset(textSection, m); isRipInstr = true; }
|
||||
else if (isRipRelativeMovR64(textSection, m)) { dispOff = movR64DispOffset(textSection, m); isRipInstr = true; }
|
||||
if (isRipInstr && dispOff + 4 <= textSection.size()) {
|
||||
std::int32_t disp = readDisp32(textSection, dispOff);
|
||||
VirtualAddress instrEnd = m.Offset + static_cast<VirtualAddress>(m.Length);
|
||||
VirtualAddress target = static_cast<VirtualAddress>(static_cast<std::int64_t>(instrEnd) + disp);
|
||||
ripTargetToInstrVAddr.emplace(target, m.Offset);
|
||||
}
|
||||
if (m.Length >= 5) {
|
||||
std::size_t off = static_cast<std::size_t>(m.Offset);
|
||||
if (textSection[off] == OneByteCallRel32 && off + 5 <= textSection.size()) {
|
||||
std::int32_t disp = readDisp32(textSection, off + 1);
|
||||
VirtualAddress instrEnd = m.Offset + static_cast<VirtualAddress>(m.Length);
|
||||
VirtualAddress target = static_cast<VirtualAddress>(static_cast<std::int64_t>(instrEnd) + disp);
|
||||
callTargetToInstrVAddr.emplace(target, m.Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<NidReference> result;
|
||||
for (const auto& ref : nidRefs) {
|
||||
if (ref.RelocationTypeValue == 7) {
|
||||
auto stubIt = ripTargetToInstrVAddr.find(ref.RelocationAddress);
|
||||
if (stubIt == ripTargetToInstrVAddr.end()) continue;
|
||||
if (callTargetToInstrVAddr.count(stubIt->second) > 0)
|
||||
result.push_back(ref);
|
||||
} else {
|
||||
if (ripTargetToInstrVAddr.count(ref.RelocationAddress) > 0)
|
||||
result.push_back(ref);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<IUnusedNidFilter> MakeUnusedNidFilter() { return std::make_shared<UnusedNidFilter>(); }
|
||||
|
||||
}
|
||||
|
|
@ -11,12 +11,16 @@ RelinkerPipeline::RelinkerPipeline(
|
|||
std::shared_ptr<ISyscallScanner> syscallScanner,
|
||||
std::shared_ptr<ICallSiteResolver> callSiteResolver,
|
||||
std::shared_ptr<IValidationPolicy> validationPolicy,
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder)
|
||||
std::shared_ptr<ISysVDynamicSectionBuilder> dynamicSectionBuilder,
|
||||
std::shared_ptr<IUnusedNidFilter> unusedNidFilter,
|
||||
bool filterUnusedNids)
|
||||
: _elfReader(std::move(elfReader))
|
||||
, _syscallScanner(std::move(syscallScanner))
|
||||
, _callSiteResolver(std::move(callSiteResolver))
|
||||
, _validationPolicy(std::move(validationPolicy))
|
||||
, _dynamicSectionBuilder(std::move(dynamicSectionBuilder))
|
||||
, _unusedNidFilter(std::move(unusedNidFilter))
|
||||
, _filterUnusedNids(filterUnusedNids)
|
||||
{}
|
||||
|
||||
std::string RelinkerPipeline::_relocationTypeName(std::uint32_t type) {
|
||||
|
|
@ -189,18 +193,20 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf
|
|||
|
||||
_validationPolicy->ValidateSyscallAbsence();
|
||||
|
||||
auto dynSection = _dynamicSectionBuilder->BuildDynamicSection(nidRefs, neededLibraries);
|
||||
if (_filterUnusedNids)
|
||||
nidRefs = _unusedNidFilter->Filter(nidRefs, textSection, textVAddr);
|
||||
|
||||
std::vector<FileByteOffset> callSites;
|
||||
bool callSitesResolved = false;
|
||||
if (!textSection.empty() && gotSize > 0) {
|
||||
callSites = _callSiteResolver->ResolveCallSites(textSection, textVAddr, gotVAddr, gotSize);
|
||||
callSitesResolved = !callSites.empty();
|
||||
}
|
||||
auto dynSection = _dynamicSectionBuilder->BuildDynamicSection(nidRefs, neededLibraries);
|
||||
|
||||
std::vector<CallRegistryEntry> entries;
|
||||
entries.reserve(nidRefs.size());
|
||||
for (const auto& ref : nidRefs) {
|
||||
std::vector<FileByteOffset> callSites;
|
||||
bool callSitesResolved = false;
|
||||
if (!textSection.empty() && gotSize > 0) {
|
||||
callSites = _callSiteResolver->ResolveCallSites(textSection, textVAddr, ref.RelocationAddress, 8);
|
||||
callSitesResolved = !callSites.empty();
|
||||
}
|
||||
CallRegistryEntry entry;
|
||||
entry.Nid = ref.Nid;
|
||||
entry.Library = ref.Library;
|
||||
|
|
|
|||
Loading…
Reference in New Issue