Merge pull request #2238 from mrk1987/fix/relinker-address-taken-tls-roots
fix(relinker): root code addresses taken by RIP-relative LEA
This commit is contained in:
commit
ae3574bb0d
|
|
@ -21,7 +21,8 @@ std::unique_ptr<IControlFlowGraph> BuildControlFlowGraph(
|
|||
VirtualAddress textVaddr,
|
||||
VirtualAddress entryVaddr,
|
||||
const std::vector<VirtualAddress>& extraEntries,
|
||||
const IRelativeRelocationIndex& relativeRelocations
|
||||
const IRelativeRelocationIndex& relativeRelocations,
|
||||
bool followCodeAddresses = false
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <codegen/CodegenException.hpp>
|
||||
#include <io/BufferUtils.hpp>
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
|
|
@ -80,6 +81,11 @@ std::set<Domain::VirtualAddress> CodeInstructionCollector::Collect(const std::ve
|
|||
std::set<std::uint64_t> roots;
|
||||
std::map<std::uint64_t, std::uint64_t> 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<std::int32_t>(Io::ReadU32(bytes, fileOffset(address, info.Length) + info.RipRelativeDispOffset));
|
||||
addRoot(address + info.Length + static_cast<std::int64_t>(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<std::uint64_t>::max() - begin)
|
||||
|
|
@ -201,6 +207,7 @@ std::set<Domain::VirtualAddress> 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<std::uint64_t>(info.BranchDisp);
|
||||
staticTargets.insert(target);
|
||||
|
|
@ -275,11 +282,12 @@ std::set<Domain::VirtualAddress> 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<std::uint8_t> 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<std::uint64_t>(static_cast<std::int64_t>(address + info.Length) + info.BranchDisp));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ std::unique_ptr<IControlFlowGraph> BuildControlFlowGraph(
|
|||
VirtualAddress textVaddr,
|
||||
VirtualAddress entryVaddr,
|
||||
const std::vector<VirtualAddress>& extraEntries,
|
||||
const IRelativeRelocationIndex& relativeRelocations
|
||||
const IRelativeRelocationIndex& relativeRelocations,
|
||||
bool followCodeAddresses
|
||||
) {
|
||||
const Codegen::X64InstructionDecoder decoder;
|
||||
std::unordered_set<VirtualAddress> reachable;
|
||||
|
|
@ -54,6 +55,12 @@ std::unique_ptr<IControlFlowGraph> BuildControlFlowGraph(
|
|||
|
||||
VirtualAddress nextVaddr = va + static_cast<VirtualAddress>(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<VirtualAddress>(static_cast<std::int64_t>(nextVaddr) + displacement));
|
||||
}
|
||||
|
||||
switch (info.FlowKind) {
|
||||
using enum Codegen::ControlFlowKind;
|
||||
case Sequential:
|
||||
|
|
|
|||
|
|
@ -462,6 +462,10 @@ def main():
|
|||
external[0x1300:0x1310] = external[0x1240:0x1250]
|
||||
external[0x1240:0x1250] = b"\xe8" + struct.pack("<i", 0x1300 - 0x1245) + b"\xc3" + b"\x90" * 10
|
||||
convert("direct-call-from-indirect-block", external, tls_address=0x1300)
|
||||
address_taken = make_image("register", "unwind")
|
||||
address_taken[0x1300:0x1310] = address_taken[0x1240:0x1250]
|
||||
address_taken[0x1240:0x1250] = bytes.fromhex("48 8d 05") + struct.pack("<i", 0x1300 - 0x1247) + bytes.fromhex("ff d0 c3") + b"\x90" * 6
|
||||
convert("address-taken-tls-callback", address_taken, tls_address=0x1300)
|
||||
|
||||
def convert_padded(name, image):
|
||||
source = work / (name + ".elf")
|
||||
|
|
|
|||
Loading…
Reference in New Issue