Merge pull request #1529 from johnmaia/fix/relinker-declared-host-imports
fix(relinker): keep Linux imports declared from host modules off guest exports
This commit is contained in:
commit
496536cb9f
|
|
@ -206,7 +206,17 @@ std::vector<GuestArtifact> GuestModuleBuilder::Build(const std::filesystem::path
|
|||
Io::WriteU32(symbols, index * 24, static_cast<std::uint32_t>(strings.size()));
|
||||
Io::AppendString(strings, name + GuestSymbolSuffix);
|
||||
};
|
||||
const auto declaresHost = [&](const std::string& library) { return !windows && !library.empty() && findGuest(library) == guestNames.end(); };
|
||||
if (dynamic.DynSymData.size() % 24 != 0) throw Domain::RelinkerException("Invalid executable symbol table");
|
||||
std::vector<std::string> executableModules(dynamic.DynSymData.size() / 24);
|
||||
for (const auto* table : {&dynamic.RelaData, &dynamic.RelaPltData}) {
|
||||
if (table->size() % 24 != 0) throw Domain::RelinkerException("Invalid executable relocation table");
|
||||
for (std::size_t offset = 0; offset < table->size(); offset += 24) {
|
||||
const auto symbol = Io::ReadU64(*table, offset + 8) >> 32;
|
||||
const auto module = dynamic.ImportModules.find(Io::ReadU64(*table, offset));
|
||||
if (symbol != 0 && symbol < executableModules.size() && module != dynamic.ImportModules.end()) executableModules[symbol] = module->second;
|
||||
}
|
||||
}
|
||||
for (std::size_t offset = 0; offset < dynamic.DynSymData.size(); offset += 24) {
|
||||
if (Io::ReadU16(dynamic.DynSymData, offset + 6) != 0) continue;
|
||||
const auto nameOffset = Io::ReadU32(dynamic.DynSymData, offset);
|
||||
|
|
@ -215,6 +225,7 @@ std::vector<GuestArtifact> GuestModuleBuilder::Build(const std::filesystem::path
|
|||
const auto end = std::find(start, dynamic.DynStrData.end(), 0);
|
||||
if (end == dynamic.DynStrData.end()) throw Domain::RelinkerException("Unterminated executable symbol name");
|
||||
const std::string name(start, end);
|
||||
if (declaresHost(executableModules[offset / 24])) continue;
|
||||
rejectSharedImport(name.substr(0, name.find('#')), Io::Utf8Path(inputPath));
|
||||
if (!windows && exports.contains(name)) rename(dynamic.DynSymData, dynamic.DynStrData, offset / 24, name);
|
||||
}
|
||||
|
|
@ -232,7 +243,7 @@ std::vector<GuestArtifact> GuestModuleBuilder::Build(const std::filesystem::path
|
|||
}
|
||||
for (std::size_t symbolIndex = 0; symbolIndex < images[index].Symbols.size(); ++symbolIndex) {
|
||||
const auto& symbol = images[index].Symbols[symbolIndex];
|
||||
if (symbol.Section != 0 || symbol.Name.empty()) continue;
|
||||
if (symbol.Section != 0 || symbol.Name.empty() || declaresHost(symbol.Library)) continue;
|
||||
rejectSharedImport(symbol.Name, Io::Utf8Path(images[index].SourcePath));
|
||||
const auto found = exports.find(symbol.Name);
|
||||
std::vector<std::size_t> providers;
|
||||
|
|
@ -257,7 +268,7 @@ std::vector<GuestArtifact> GuestModuleBuilder::Build(const std::filesystem::path
|
|||
for (std::size_t index = 1; index < image.Symbols.size(); ++index) {
|
||||
const auto& symbol = image.Symbols[index];
|
||||
const bool exported = symbol.Section != 0 && (symbol.Info >> 4) != 0 && symbol.Visibility != 1 && symbol.Visibility != 2;
|
||||
if ((symbol.Section == 0 || exported) && exports.contains(symbol.Name)) rename(image.Dynamic.DynSymData, image.Dynamic.DynStrData, index, symbol.Name);
|
||||
if (((symbol.Section == 0 && !declaresHost(symbol.Library)) || exported) && exports.contains(symbol.Name)) rename(image.Dynamic.DynSymData, image.Dynamic.DynStrData, index, symbol.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import sys
|
|||
import tempfile
|
||||
|
||||
from test_guest_intel_trampolines import PLAIN_SITE, elf_loads, guest_fixture, main_fixture
|
||||
from test_windows_import_modules import consumer, provider
|
||||
|
||||
DYNAMIC = 0x4800
|
||||
STRINGS = 0x4A00
|
||||
|
|
@ -36,15 +37,18 @@ def guest_module(symbols):
|
|||
return image
|
||||
|
||||
|
||||
def importing_executable(names):
|
||||
def importing_executable(names, modules=()):
|
||||
image = main_fixture()
|
||||
strings, offsets = string_table(names)
|
||||
needed = [module + ".prx" for module in modules]
|
||||
strings, offsets = string_table([*names, *needed, *modules])
|
||||
image[STRINGS:STRINGS + len(strings)] = strings
|
||||
for index, offset in enumerate(offsets, 1):
|
||||
for index, offset in enumerate(offsets[:len(names)], 1):
|
||||
struct.pack_into("<IBBHQQ", image, SYMBOLS + index * 24, offset, 0x12, 0, 0, 0, 0)
|
||||
struct.pack_into("<QQq", image, RELOCATIONS + (index - 1) * 24, GOT + (index - 1) * 8, (index << 32) | 6, 0)
|
||||
tags = [(5, STRINGS), (10, len(strings)), (6, SYMBOLS), (11, 24),
|
||||
(7, RELOCATIONS), (8, len(names) * 24), (9, 24), (0, 0)]
|
||||
tags = [(1, offset) for offset in offsets[len(names):len(names) + len(needed)]]
|
||||
tags += [(0x61000045, (index << 48) | offset) for index, offset in enumerate(offsets[len(names) + len(needed):], 1)]
|
||||
tags += [(5, STRINGS), (10, len(strings)), (6, SYMBOLS), (11, 24),
|
||||
(7, RELOCATIONS), (8, len(names) * 24), (9, 24), (0, 0)]
|
||||
for index, tag in enumerate(tags):
|
||||
struct.pack_into("<qQ", image, DYNAMIC + index * 16, *tag)
|
||||
struct.pack_into("<QQQQQ", image, 120 + 8, DYNAMIC, DYNAMIC, DYNAMIC, len(tags) * 16, len(tags) * 16)
|
||||
|
|
@ -120,19 +124,25 @@ def imported_symbols(image):
|
|||
return names
|
||||
|
||||
|
||||
def convert(relinker, case):
|
||||
def relink(relinker, case, executable, modules):
|
||||
(case / "sce_module").mkdir(parents=True)
|
||||
source = case / "input.elf"
|
||||
source.write_bytes(importing_executable(["AAAAAAAAAAA#A#A", "DDDDDDDDDDD#D#D"]))
|
||||
(case / "sce_module" / "libc.prx").write_bytes(
|
||||
guest_module([("AAAAAAAAAAA#A#A", True), ("BBBBBBBBBBB#B#B", False), ("CCCCCCCCCCC#C#C", False), ("EEEEEEEEEEE", True)]))
|
||||
(case / "sce_module" / "other.prx").write_bytes(guest_module([("BBBBBBBBBBB#B#B", True), ("EEEEEEEEEEE", True)]))
|
||||
source.write_bytes(executable)
|
||||
for name, image in modules.items():
|
||||
(case / "sce_module" / name).write_bytes(image)
|
||||
output = case / "output.elf"
|
||||
result = subprocess.run([str(relinker), str(source), str(output)], capture_output=True, text=True, timeout=30)
|
||||
assert result.returncode == 0, (result.stdout, result.stderr)
|
||||
return output
|
||||
|
||||
|
||||
def convert(relinker, case):
|
||||
return relink(relinker, case, importing_executable(["AAAAAAAAAAA#A#A", "DDDDDDDDDDD#D#D"]), {
|
||||
"libc.prx": guest_module([("AAAAAAAAAAA#A#A", True), ("BBBBBBBBBBB#B#B", False), ("CCCCCCCCCCC#C#C", False), ("EEEEEEEEEEE", True)]),
|
||||
"other.prx": guest_module([("BBBBBBBBBBB#B#B", True), ("EEEEEEEEEEE", True)]),
|
||||
})
|
||||
|
||||
|
||||
def main():
|
||||
relinker = Path(sys.argv[1]).resolve()
|
||||
with tempfile.TemporaryDirectory(prefix="anyps5-guest-symbol-names-") as directory:
|
||||
|
|
@ -148,6 +158,21 @@ def main():
|
|||
check_hash_table((modules / "other.prx.guest.prx").read_bytes())
|
||||
imports = imported_symbols(output.read_bytes())
|
||||
assert imports == {"AAAAAAAAAAA#guest", "DDDDDDDDDDD"}, imports
|
||||
|
||||
declared = relink(relinker, work / "declared",
|
||||
importing_executable(["AAAAAAAAAAA#B#B", "EEEEEEEEEEE#C#C"], ["libc", "libSceLibcInternal"]),
|
||||
{"libc.prx": guest_module([("AAAAAAAAAAA", True), ("EEEEEEEEEEE", True)])})
|
||||
imports = imported_symbols(declared.read_bytes())
|
||||
assert imports == {"AAAAAAAAAAA#guest", "EEEEEEEEEEE"}, imports
|
||||
|
||||
guests = relink(relinker, work / "guest-declared", importing_executable([]), {
|
||||
"b.prx": provider(7),
|
||||
"c.prx": consumer("libSceLibcInternal.prx", module_name="libSceLibcInternal"),
|
||||
}).parent / "app0" / "sce_module"
|
||||
exporter = module_symbols((guests / "b.prx.guest.prx").read_bytes())
|
||||
assert exporter == ["shared#guest"], exporter
|
||||
importer = module_symbols((guests / "c.prx.guest.prx").read_bytes())
|
||||
assert "shared" in importer and "shared#guest" not in importer, importer
|
||||
print("Guest symbol name tests passed")
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue