diff --git a/core/relinker/CMakeLists.txt b/core/relinker/CMakeLists.txt index 13912f3f4..9488c9070 100644 --- a/core/relinker/CMakeLists.txt +++ b/core/relinker/CMakeLists.txt @@ -206,6 +206,8 @@ if(BUILD_TESTING) ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_tls_diagnostics.py $) add_test(NAME linux_load_alignment COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_linux_load_alignment.py $) + add_test(NAME linux_eh_frame_header COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_linux_eh_frame_header.py $) add_test(NAME linux_dynamic_strings COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_linux_dynamic_strings.py $) add_test(NAME executable_segments COMMAND ${Python3_EXECUTABLE} diff --git a/core/relinker/elfpatcher/include/elfpatcher/general/ElfConstants.hpp b/core/relinker/elfpatcher/include/elfpatcher/general/ElfConstants.hpp index c67ededd1..51857f69b 100644 --- a/core/relinker/elfpatcher/include/elfpatcher/general/ElfConstants.hpp +++ b/core/relinker/elfpatcher/include/elfpatcher/general/ElfConstants.hpp @@ -62,6 +62,7 @@ inline constexpr std::uint32_t PT_DYNAMIC = 2; inline constexpr std::uint32_t PT_INTERP = 3; inline constexpr std::uint32_t PT_NOTE = 4; inline constexpr std::uint32_t PT_PHDR = 6; +inline constexpr std::uint32_t PT_GNU_EH_FRAME = 0x6474e550; inline constexpr std::uint32_t PT_GNU_RELRO = 0x6474e552; inline constexpr std::uint32_t PF_X = 0x1; inline constexpr std::uint32_t PF_W = 0x2; diff --git a/core/relinker/elfpatcher/src/general/ProgramHeaderLayoutBuilder.cpp b/core/relinker/elfpatcher/src/general/ProgramHeaderLayoutBuilder.cpp index b12f1ad90..d844e8176 100644 --- a/core/relinker/elfpatcher/src/general/ProgramHeaderLayoutBuilder.cpp +++ b/core/relinker/elfpatcher/src/general/ProgramHeaderLayoutBuilder.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include namespace Elfpatcher { @@ -131,10 +132,19 @@ std::uint16_t ProgramHeaderLayoutBuilder::WriteLayout( const ProgramHeaderLayoutRequest& request ) const { std::uint16_t keptCount = 0; + std::uint16_t frameCount = 0; for (const auto& ph : request.OriginalHeaders) { if (_segmentFilter->ShouldSkip(ph)) continue; keptCount++; + if (ph.Type == PT_GNU_EH_FRAME) + frameCount++; + } + + const bool keepFrames = keptCount + kSyntheticProgramHeaderCount < request.PhNum; + if (!keepFrames && frameCount > 0) { + keptCount -= frameCount; + std::cerr << "WARNING: No free program header slot for PT_GNU_EH_FRAME; C++ exceptions thrown in the executable cannot be caught.\n"; } const std::uint16_t neededPh = keptCount + kSyntheticProgramHeaderCount; @@ -175,7 +185,7 @@ std::uint16_t ProgramHeaderLayoutBuilder::WriteLayout( writtenPh++; for (const auto& ph : request.OriginalHeaders) { - if (_segmentFilter->ShouldSkip(ph)) + if (_segmentFilter->ShouldSkip(ph) || (!keepFrames && ph.Type == PT_GNU_EH_FRAME)) continue; const std::size_t phEntOff = static_cast(request.PhOff) + writtenPh * request.PhEntSize; if (ph.Type == PT_LOAD) { diff --git a/core/relinker/elfpatcher/src/general/SegmentFilter.cpp b/core/relinker/elfpatcher/src/general/SegmentFilter.cpp index 07425c37e..ff8f24e7f 100644 --- a/core/relinker/elfpatcher/src/general/SegmentFilter.cpp +++ b/core/relinker/elfpatcher/src/general/SegmentFilter.cpp @@ -12,6 +12,7 @@ bool SegmentFilter::_isSceSpecificSegment(const std::uint32_t type) const { bool SegmentFilter::ShouldSkip(const Domain::ProgramHeader& ph) const { if (ph.Type == PT_OS_PROCPARAM) return false; + if (ph.Type == PT_GNU_EH_FRAME) return false; if (_isSceSpecificSegment(ph.Type)) return true; if (ph.Type == PT_DYNAMIC) return true; if (ph.Type == PT_NOTE && ph.MappedAddress == 0 && ph.FileSize > 0) return true; diff --git a/core/relinker/relinker/tests/test_linux_eh_frame_header.py b/core/relinker/relinker/tests/test_linux_eh_frame_header.py new file mode 100644 index 000000000..047a3c56b --- /dev/null +++ b/core/relinker/relinker/tests/test_linux_eh_frame_header.py @@ -0,0 +1,72 @@ +from pathlib import Path +import struct +import subprocess +import sys +import tempfile + +PT_LOAD = 1 +PT_DYNAMIC = 2 +PT_GNU_EH_FRAME = 0x6474E550 +PT_SCE_VERSION = 0x6FFFFF01 +EH_FRAME_HEADER = (PT_GNU_EH_FRAME, 4, 0x4800, 0x800, 0x800, 16, 16, 4) + + +def fixture(header_count): + image = bytearray(0x8000) + image[:16] = b"\x7fELF\x02\x01\x01" + bytes(9) + struct.pack_into("