diff --git a/core/relinker/elfpatcher/src/macos/MacOsImage.cpp b/core/relinker/elfpatcher/src/macos/MacOsImage.cpp index 210858aa4e..ad8c61308a 100644 --- a/core/relinker/elfpatcher/src/macos/MacOsImage.cpp +++ b/core/relinker/elfpatcher/src/macos/MacOsImage.cpp @@ -154,6 +154,33 @@ void PadTo(std::vector& out, const std::size_t alignment) { while (out.size() % alignment != 0) out.push_back(0); } +void FitDyldSegmentLimit(std::vector& sections, const std::size_t limit) { + while (sections.size() > limit) { + auto best = sections.end(); + std::uint64_t bestGap = 0; + for (auto section = sections.begin(); std::next(section) != sections.end(); ++section) { + const auto next = std::next(section); + if (section->Name == ".amdstub" || next->Name == ".amdstub" || section->Characteristics != next->Characteristics || + section->Rva + section->MemorySize() != next->Rva) + continue; + const auto gap = next->Rva - section->Rva - section->Data.size(); + if (best == sections.end() || gap < bestGap) { + best = section; + bestGap = gap; + } + } + if (best == sections.end()) return; + const auto next = std::next(best); + const auto memorySize = next->Rva + next->MemorySize() - best->Rva; + if (!next->Data.empty()) { + best->Data.resize(next->Rva - best->Rva); + best->Data.insert(best->Data.end(), next->Data.begin(), next->Data.end()); + } + best->VirtualSize = static_cast(memorySize); + sections.erase(next); + } +} + std::pair Locate(const std::vector& segments, const std::uint64_t rva, const std::uint64_t size) { for (std::size_t index = 0; index < segments.size(); ++index) { const auto& segment = segments[index]; @@ -420,6 +447,7 @@ std::vector WriteMacOsImage(MacOsImageInput& input) { auto stubRva = Windows::AlignRva(image.GetEndRva()); Windows::WindowsTrampolineBuilder().Build(*input.Trampolines, image, sections, stubRva); } + FitDyldSegmentLimit(sections, 16 - guestSegments - 2); std::uint64_t guestEnd = image.GetEndRva(); for (auto& section : sections) { std::uint32_t protection = 0; diff --git a/core/relinker/relinker/tests/test_windows_bss.py b/core/relinker/relinker/tests/test_windows_bss.py index 6c0b149ae0..088ebc5a33 100644 --- a/core/relinker/relinker/tests/test_windows_bss.py +++ b/core/relinker/relinker/tests/test_windows_bss.py @@ -66,6 +66,7 @@ def main(): executed = subprocess.run([str(output)], capture_output=True, text=True, timeout=20) assert executed.returncode == 42, f"exit code {executed.returncode:#x}" check_relocated_zero_fill(relinker, work) + check_scattered_relocations_macos(relinker, work) print("Windows zero-filled memory tests passed") @@ -96,5 +97,33 @@ def check_relocated_zero_fill(relinker, work): assert executed.returncode == 42, f"exit code {executed.returncode:#x}" +def check_scattered_relocations_macos(relinker, work): + image = fixture() + file_size = struct.unpack_from("