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:
Dean 2026-10-10 17:45:39 +13:00 committed by GitHub
commit ae3574bb0d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 23 additions and 3 deletions

View File

@ -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
);
}

View File

@ -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));
}
}

View File

@ -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:

View File

@ -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")