diff --git a/core/relinker/CMakeLists.txt b/core/relinker/CMakeLists.txt index 48694b5ad6..67acbb953a 100644 --- a/core/relinker/CMakeLists.txt +++ b/core/relinker/CMakeLists.txt @@ -845,6 +845,8 @@ if(BUILD_TESTING) ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_guest_absolute_symbols.py $) add_test(NAME guest_module_identity COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_guest_module_identity.py $) + add_test(NAME guest_symbolic_modules COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_guest_symbolic_modules.py $) add_test(NAME linux_guest_zero_address_exports COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_linux_guest_zero_address_exports.py $ $) diff --git a/core/relinker/elfpatcher/src/windows/WindowsGuestModuleWriter.cpp b/core/relinker/elfpatcher/src/windows/WindowsGuestModuleWriter.cpp index 7a3794848e..ca987359d7 100644 --- a/core/relinker/elfpatcher/src/windows/WindowsGuestModuleWriter.cpp +++ b/core/relinker/elfpatcher/src/windows/WindowsGuestModuleWriter.cpp @@ -15,7 +15,6 @@ namespace Elfpatcher { std::vector GuestModuleWriter::WriteWindows(const Relinker::GuestImage& guest, Domain::GuestRuntime& runtime, const std::function& message) const { using namespace Windows; - if (guest.Symbolic) throw Domain::RelinkerException("DF_SYMBOLIC guest modules are not supported by the Windows writer"); WindowsLoadImage image(guest.Bytes, guest.Headers, false); std::vector relocations; std::vector> tlsModules; diff --git a/core/relinker/relinker/tests/WindowsExportAliasTests.cpp b/core/relinker/relinker/tests/WindowsExportAliasTests.cpp index a05a466e8a..e11b78f6bf 100644 --- a/core/relinker/relinker/tests/WindowsExportAliasTests.cpp +++ b/core/relinker/relinker/tests/WindowsExportAliasTests.cpp @@ -68,7 +68,7 @@ int main() { const std::array,7> changes={{{4,0x22},{4,0x11},{5,0},{6,2},{8,0x28},{16,2},{6,Relinker::AbsoluteSection}}}; for(const auto& [field,value]:changes){auto b=Fixture();auto off=0x2400+48+field;if(field<6)b[off]=value;else if(field==6)Io::WriteU16(b,off,value);else Io::WriteU64(b,off,value);Reject([&]{Relinker::GuestImageReader().Read("generic.prx",b,true);},"Duplicate or empty export");} auto good=Relinker::GuestImageReader().Read("generic.prx",Fixture(),true); - auto symbolic=good;symbolic.Symbolic=true;Domain::GuestRuntime symbolicRuntime;Reject([&]{Elfpatcher::GuestModuleWriter().WriteWindows(symbolic,symbolicRuntime);},"DF_SYMBOLIC"); + auto symbolic=good;symbolic.Symbolic=true;Domain::GuestRuntime symbolicRuntime,ordinaryRuntime;Check(Elfpatcher::GuestModuleWriter().WriteWindows(symbolic,symbolicRuntime)==Elfpatcher::GuestModuleWriter().WriteWindows(good,ordinaryRuntime)&&symbolicRuntime.Imports.size()==ordinaryRuntime.Imports.size(),"DF_SYMBOLIC changed Windows binding"); for(unsigned kind=0;kind<10;++kind){auto g=good;auto& s=g.Symbols[2];switch(kind){case 0:s.Value+=8;break;case 1:s.Size+=1;break;case 2:s.Info=0x22;break;case 3:s.Info=0x11;break;case 4:s.Visibility=0;break;case 5:s.Section=2;break;case 6:g.Symbols[1].Info=s.Info=0x11;break;case 7:g.Symbols[1].Section=s.Section=Relinker::AbsoluteSection;break;case 8:g.Symbols[1].Info=s.Info=0x16;g.Dynamic.RelaData.clear();break;case 9:g.Symbols[1].Info=s.Info=0x10;break;}Check(!Relinker::IdenticalOrdinaryFunctionExport(g.Symbols[1],s),"nonordinary/conflicting tuple accepted");Domain::GuestRuntime r;Reject([&]{Elfpatcher::GuestModuleWriter().WriteWindows(g,r);},kind==8?"TLS":"Duplicate guest export");} Check(Domain::DeclaredImportModule("same#A#B",{{1,"one"},{2,"two"}})=="one"&&Domain::DeclaredImportModule("same#A#C",{{1,"one"},{2,"two"}})=="two","module-qualified IDs merged"); auto zeroBucket=Fixture();Io::WriteU32(zeroBucket,0x2600,0); diff --git a/core/relinker/relinker/tests/test_guest_module_directories.py b/core/relinker/relinker/tests/test_guest_module_directories.py index 6ea29ae84f..8545709f0e 100644 --- a/core/relinker/relinker/tests/test_guest_module_directories.py +++ b/core/relinker/relinker/tests/test_guest_module_directories.py @@ -98,7 +98,7 @@ def main(): prx.mkdir(parents=True) provider = (case / standard) if standard else prx provider.mkdir(exist_ok=True) - (provider / "provider.prx").write_bytes(module_with_symbol(True, symbolic=not windows)) + (provider / "provider.prx").write_bytes(module_with_symbol(True, symbolic=True)) (prx / "consumer.prx").write_bytes(module_with_symbol(False)) (prx / "ignored.txt").write_text("not ELF") (prx / "old.prx.guest.prx").write_bytes(guest_fixture(PLAIN_SITE)) @@ -227,12 +227,6 @@ def main(): assert result.returncode == 2 and "Ambiguous guest import" in result.stderr and "shared" in result.stderr, result.stderr assert not output.exists() and not (case / "app0").exists(), output - case = work / "windows-symbolic" - (case / "prx").mkdir(parents=True) - (case / "prx" / "provider.prx").write_bytes(module_with_symbol(True, symbolic=True)) - result, output = convert(case, True) - assert result.returncode == 2 and "DF_SYMBOLIC" in result.stderr, result.stderr - assert not output.exists(), output print("Guest module directory integration tests passed") diff --git a/core/relinker/relinker/tests/test_guest_symbolic_modules.py b/core/relinker/relinker/tests/test_guest_symbolic_modules.py new file mode 100644 index 0000000000..708f0875c9 --- /dev/null +++ b/core/relinker/relinker/tests/test_guest_symbolic_modules.py @@ -0,0 +1,103 @@ +from pathlib import Path +import os +import struct +import subprocess +import sys + +from guest_import_fixtures import dynamic, fixture_directory +from test_guest_intel_trampolines import PLAIN_SITE, guest_fixture, main_fixture + +ENTRY = 0x1010 +SHARED = 0x1000 +CALL_SLOTS = (0x23a0, 0x23a8, 0x23b0) +TLS_SLOT = 0x23b8 + + +def module(value, tls_value, identity, entry_symbol, symbolic): + image = guest_fixture(PLAIN_SITE, symbolic=symbolic) + strings = b'\0shared#A#B\0' + entry_symbol.encode() + b'#A#B\0tls_value#A#B\0' + entry_name = strings.index(entry_symbol.encode()) + tls_name = strings.index(b'tls_value') + identity_offset = len(strings) + strings += identity.encode() + b'\0' + assert len(strings) <= 0x40 + image[0x800:0x800 + len(strings)] = strings + tags = [(5, 0x2200), (10, len(strings)), (6, 0x2280), (11, 24), + (4, 0x2240), (7, 0x2300), (8, 24 * (len(CALL_SLOTS) + 1)), (9, 24), + (0x61000043, (1 << 48) | (0x101 << 32) | identity_offset)] + if symbolic: + tags.append((30, 2)) + dynamic(image, 0x600, 176, tags) + struct.pack_into('