fix(relinker): ignore no-op executable relocations
This commit is contained in:
parent
a11c8f7f70
commit
cb9932007a
|
|
@ -245,6 +245,8 @@ if(BUILD_TESTING)
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_dynamic_segment.py $<TARGET_FILE:relinker>)
|
||||
add_test(NAME rela_size COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_rela_size.py $<TARGET_FILE:relinker>)
|
||||
add_test(NAME none_relocations COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_none_relocations.py $<TARGET_FILE:relinker>)
|
||||
add_test(NAME optional_plt COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_optional_plt.py $<TARGET_FILE:relinker>)
|
||||
add_test(NAME empty_tls COMMAND ${Python3_EXECUTABLE}
|
||||
|
|
|
|||
|
|
@ -231,6 +231,9 @@ RelinkResult RelinkerPipeline::Relink(const std::vector<std::uint8_t>& sourceElf
|
|||
const std::uint32_t symIdx = static_cast<std::uint32_t>(rInfo >> 32);
|
||||
const std::uint32_t relType = static_cast<std::uint32_t>(rInfo & 0xffffffff);
|
||||
|
||||
if (relType == R_X86_64_NONE)
|
||||
continue;
|
||||
|
||||
if (relType == 8) {
|
||||
if (symIdx != 0)
|
||||
throw RelinkerException("RELATIVE relocation has a nonzero symbol index", pos);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from test_dynamic_segment import fixture
|
||||
from test_linux_dynamic_strings import dynamic_strings, file_offset
|
||||
from test_linux_load_alignment import loads
|
||||
|
||||
|
||||
def image_with_relocations(relocations, sce, imported):
|
||||
image = fixture()
|
||||
struct.pack_into("<Q", image, 0x458, len(relocations) * 24)
|
||||
for index, relocation in enumerate(relocations):
|
||||
struct.pack_into("<QQq", image, 0x700 + index * 24, *relocation)
|
||||
if not any(info & 0xffffffff == 8 for _, info, _ in relocations):
|
||||
image[0x200:0x206] = bytes.fromhex("b82a000000c3")
|
||||
if imported:
|
||||
strings = b"\0symbol\0libc.prx\0"
|
||||
image[0x600:0x600 + len(strings)] = strings
|
||||
struct.pack_into("<Q", image, 0x418, len(strings))
|
||||
struct.pack_into("<IBBHQQ", image, 0x638, 1, 0x12, 0, 0, 0, 0)
|
||||
image[0x200:0x20d] = bytes.fromhex("488b0501010000ff25f3000000")
|
||||
struct.pack_into("<qQ", image, 0x470, 0x6100003f, 48)
|
||||
struct.pack_into("<qQ", image, 0x480, 1, 8)
|
||||
struct.pack_into("<QQ", image, 152, 0xa0, 0xa0)
|
||||
if sce:
|
||||
struct.pack_into("<IIQQQQQQ", image, 176, 0x61000000, 0, 0x500, 0, 0, 0xb00, 0xb00, 1)
|
||||
variants = {5: 0x61000035, 10: 0x61000037, 6: 0x61000039, 11: 0x6100003b,
|
||||
7: 0x6100002f, 8: 0x61000031, 9: 0x61000033}
|
||||
for offset in range(0x400, 0x470, 16):
|
||||
tag, value = struct.unpack_from("<qQ", image, offset)
|
||||
struct.pack_into("<qQ", image, offset, variants[tag], value - 0x500 if tag in (5, 6, 7) else value)
|
||||
return image
|
||||
|
||||
|
||||
def main():
|
||||
relinker = Path(sys.argv[1]).resolve()
|
||||
relative = (0x300, 8, 0x210)
|
||||
noop = (0, 0, 0)
|
||||
ignored_fields = (0xffffffffffffffff, 0xffffffff00000000, -1)
|
||||
imported = (0x308, (1 << 32) | 6, 0)
|
||||
cases = (("baseline", [relative]), ("before", [noop, relative]), ("after", [relative, noop]),
|
||||
("ignored-fields", [ignored_fields, relative, noop]),
|
||||
("only-none", [noop, ignored_fields]),
|
||||
("with-import", [noop, imported, ignored_fields, relative]))
|
||||
with tempfile.TemporaryDirectory(prefix="anyps5-none-relocations-") as directory:
|
||||
work = Path(directory)
|
||||
for sce in (False, True):
|
||||
for name, relocations in cases:
|
||||
has_import = imported in relocations
|
||||
image = image_with_relocations(relocations, sce, has_import)
|
||||
source = work / f"{sce}-{name}.elf"
|
||||
source.write_bytes(image)
|
||||
for target, options, magic in (("linux", [], b"\x7fELF"), ("windows", ["--windows"], b"MZ"),
|
||||
("macos", ["--macos"], b"\xcf\xfa\xed\xfe")):
|
||||
for level in (0, 1):
|
||||
output = work / f"{sce}-{name}-{target}-{level}.out"
|
||||
result = subprocess.run([str(relinker), "--skip-sce-module", "--registry",
|
||||
f"unused-filter={level}", *options, str(source), str(output)],
|
||||
capture_output=True, text=True, timeout=20)
|
||||
assert result.returncode == 0, (sce, name, target, level, result.stdout, result.stderr)
|
||||
data = output.read_bytes()
|
||||
assert data.startswith(magic), (name, target)
|
||||
registry = json.loads(output.with_suffix(".registry.json").read_text(encoding="utf-8"))
|
||||
assert [(entry["nid"], entry["relocationType"], entry["targetOffset"]) for entry in registry] == (
|
||||
[("symbol", "R_X86_64_GLOB_DAT", "0x308")] if has_import else [])
|
||||
assert source.read_bytes() == image
|
||||
if target == "linux":
|
||||
tags, _ = dynamic_strings(data)
|
||||
actual = []
|
||||
if tags.get(8, 0):
|
||||
start = file_offset(data, loads(data), tags[7])
|
||||
actual = [struct.unpack_from("<QQq", data, offset) for offset in range(start, start + tags[8], 24)]
|
||||
assert actual == [relocation for relocation in relocations if relocation in (imported, relative)]
|
||||
if target == "windows" and os.name == "nt" and not has_import:
|
||||
run = subprocess.run([str(output)], capture_output=True, timeout=20)
|
||||
assert run.returncode == 42, (name, level, run.returncode, run.stderr)
|
||||
source = work / "invalid-relative.elf"
|
||||
source.write_bytes(image_with_relocations([noop, (0x300, (1 << 32) | 8, 0x210)], False, False))
|
||||
output = work / "invalid-relative.exe"
|
||||
result = subprocess.run([str(relinker), "--skip-sce-module", "--windows", str(source), str(output)],
|
||||
capture_output=True, text=True, timeout=20)
|
||||
assert result.returncode == 2 and "RELATIVE relocation has a nonzero symbol index" in result.stderr
|
||||
assert not output.exists()
|
||||
print("No-op executable relocation tests passed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue