Merge pull request #6357 from MarcZX10/codex/relinker-relative-defined-symbol-3093

fix(relinker): accept matching defined relative symbols
This commit is contained in:
Adrià authored and GitHub committed 2026-10-19 02:56:49 +02:00
commit 7b12450b8f
3 files changed
+30 -8

No files matched your search

@@ -208,8 +208,13 @@ std::set<Domain::VirtualAddress> CodeInstructionCollector::Collect(const std::ve
const auto index = info >> 32;
const auto addend = Io::ReadU64(bytes, offset + 16);
if (type == 8) {
const auto zeroSectionSymbol = index != 0 && index < symbolCount && (bytes[symbols + index * 24 + 4] & 15) == 3 && Io::ReadU64(bytes, symbols + index * 24 + 8) == 0;
if ((index != 0 && !zeroSectionSymbol) || !pointers.Values.emplace(slot, addend).second) throw Domain::RelinkerException("Code analysis: invalid relative relocation", slot);
const auto hasSymbol = index != 0 && index < symbolCount;
const auto symbol = hasSymbol ? symbols + index * 24 : 0;
const auto zeroSectionSymbol = hasSymbol && (bytes[symbol + 4] & 15) == 3 && Io::ReadU64(bytes, symbol + 8) == 0;
const auto matchingDefinedSymbol = hasSymbol && Io::ReadU16(bytes, symbol + 6) != 0
&& addend <= static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max())
&& Io::ReadU64(bytes, symbol + 8) == addend;
if ((index != 0 && !zeroSectionSymbol && !matchingDefinedSymbol) || !pointers.Values.emplace(slot, addend).second) throw Domain::RelinkerException("Code analysis: invalid relative relocation", slot);
addRoot(addend);
} else if (type == 1 || type == 6 || type == 7) {
if (index == 0 || index >= symbolCount) throw Domain::RelinkerException("Code analysis: invalid relocation symbol", slot);
@@ -233,7 +233,16 @@ GuestImage GuestImageReader::Read(const std::filesystem::path& path, std::vector
if ((next != relocationTargets.end() && next->first < target + 8) || (next != relocationTargets.begin() && std::prev(next)->second > target)) fail("Overlapping guest relocations");
relocationTargets.emplace(target, target + 8);
if (relocation == 8) {
if ((info >> 32) != 0) fail("RELATIVE relocation has a symbol");
if ((info >> 32) != 0) {
const auto& symbol = image.Symbols[info >> 32];
if (symbol.Section == 0 || addend > static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max()) || symbol.Value != addend)
fail("RELATIVE relocation has a symbol");
mapped(addend, 0, 0);
Io::AppendU64(output, target);
Io::AppendU64(output, relocation);
Io::AppendU64(output, addend);
continue;
}
mapped(addend, 0, 0);
} else if (relocation == 1 || relocation == 6 || relocation == 7) {
const auto& symbol = image.Symbols[info >> 32];
@@ -18,11 +18,13 @@ NOOP = (0, 0, 0)
IGNORED = (0xffffffffffffffff, 0xffffffff00000000, -1)
OVERLAP = (TARGET + 1, 0xffffffff00000000, -1)
RELATIVE = (TARGET, 8, FUNCTION)
RELATIVE_DEFINED = (TARGET, (1 << 32) | 8, FUNCTION)
JUMP_SLOT = (TARGET, (1 << 32) | 7, 0)
def module(rela=(), plt=(), sce=False, lifecycle=False, initial=UNCHANGED):
image = module_with_symbol(True)
def module(rela=(), plt=(), sce=False, lifecycle=False, initial=UNCHANGED, exported=True, symbol_info=0x12):
image = module_with_symbol(exported)
image[0x89c] = symbol_info
image.extend(bytes(0xE00 - len(image)))
struct.pack_into("<QQ", image, 120 + 32, 0x800, 0x800)
image[0x400:0x406] = bytes.fromhex("b82a000000c3")
@@ -75,7 +77,9 @@ def change_tag(image, tag, value=None, replacement=None):
def check_output(data, system, rela, plt, initial):
expected_rela = [entry for entry in rela if entry[1] & 0xffffffff]
expected_rela = [(entry[0], entry[1] & 0xffffffff, entry[2])
if (entry[1] & 0xffffffff) == 8 and entry[1] >> 32 else entry
for entry in rela if entry[1] & 0xffffffff]
expected_plt = [entry for entry in plt if entry[1] & 0xffffffff]
relocated = bool(expected_rela or expected_plt)
if system == "linux":
@@ -108,7 +112,8 @@ def check_output(data, system, rela, plt, initial):
def invalid_cases(sce):
yield "relative-symbol", module([NOOP, (TARGET, (1 << 32) | 8, FUNCTION)], sce=sce), "RELATIVE relocation has a symbol"
yield "relative-symbol-mismatched-value", module([(TARGET, (1 << 32) | 8, FUNCTION + 8)], sce=sce), "RELATIVE relocation has a symbol"
yield "relative-symbol-undefined", module([(TARGET, (1 << 32) | 8, 0)], sce=sce, exported=False), "RELATIVE relocation has a symbol"
yield "invalid-symbol", module([NOOP, (TARGET, (99 << 32) | 6, 0)], sce=sce), "Unsupported relocation or symbol index"
yield "invalid-target", module([NOOP, (0xffffffffffffffff, 8, FUNCTION)], sce=sce), "Unmapped or inaccessible guest address"
yield "overlapping-real", module([NOOP, RELATIVE, RELATIVE], sce=sce), "Overlapping guest relocations"
@@ -142,6 +147,8 @@ def main():
return
relinker = Path(sys.argv[1]).resolve()
cases = (("baseline", [RELATIVE], [], False, UNCHANGED),
("relative-defined-symbol", [RELATIVE_DEFINED], [], False, UNCHANGED),
("relative-defined-object", [RELATIVE_DEFINED], [], False, UNCHANGED),
("mixed", [NOOP, OVERLAP, RELATIVE, IGNORED, (TARGET, 0, -1)], [], False, UNCHANGED),
("only-none", [NOOP, IGNORED, OVERLAP], [], False, UNCHANGED),
("plt-mixed", [], [NOOP, OVERLAP, JUMP_SLOT, IGNORED], False, UNCHANGED),
@@ -168,7 +175,8 @@ def main():
for sce in (False, True):
for name, rela, plt, lifecycle, initial in cases:
image = module(rela, plt, sce, lifecycle, initial)
symbol_info = 0x11 if name == "relative-defined-object" else 0x12
image = module(rela, plt, sce, lifecycle, initial, symbol_info=symbol_info)
for system in ("linux", "windows", "macos"):
result, artifact, output = convert(f"{sce}-{name}", system, image)
assert result.returncode == 0, (sce, name, system, result.stdout, result.stderr)