A relocation or lea target outside the unwind functions of a PS4 image
is now decoded up to its first jump, return or trap, or to the start of
the next unwind function, which also bounds the transfer check of the
tail rule. A target whose run holds an fs:[disp32] access, the form the
linear TLS sweep roots, is followed as code. The other targets taken as
data are counted in one message and kept as entry points that the
Windows TLS rewrite may not overwrite. The analysis merges nested
unwind ranges like the scans.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
windows_dependency_diagnostics rewrites the fixture images right after the
diagnostic runner exits. The runner ends with an unhandled RaiseException of
STATUS_DLL_NOT_FOUND, and Windows fault handling keeps the exited process's
image files open for a short time after its handle is signaled: on Windows 11
22621 the Restart Manager names the exited runner as the holder and the file
opens 37 to 153 ms later. The rewrite then fails with ERROR_SHARING_VIOLATION,
and the final removal of the fixtures with access denied. Retry opening a
fixture while it fails with a sharing violation and the removal while it fails
with access denied, for at most 10 s each; every other failure still fails the
test at once.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Linux entry stub now passes each traced import through libc.prx's
TraceImport_nid_no_patch before it calls the guest entry, and stores the
returned thunk in the import's slot. The same imports are traced as on
Windows: functions bound through a PLT slot or a GOT slot, without an
addend, and not weak. TraceImport_nid_no_patch is bound eagerly through
an added GLOB_DAT relocation, so a libc.prx without it fails at load.
Each slot's page is made writable with mprotect first, so slots inside a
PT_GNU_RELRO range can be replaced.
--trace-imports now requires libc.prx among the libraries on Linux too,
and is refused with --macos.
The Linux executable sorts its PT_LOAD entries, but guest modules (*.guest.prx) kept them in the input table order. A module whose data segment comes before its text segment in the table was written with PT_LOAD entries out of address order, which the gABI forbids: glibc reserves the span from the first to the last entry, so with 0x2000, 0x1000, 0x4000 it reserved 0x2230 bytes instead of 0x3230 and mapped the text below the reservation. The PT_LOAD entries are now sorted in place, as for the executable.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ProgramLayoutRangeTests.cpp includes this header first, and libc++ does
not provide size_t through <cstdint>, so the macOS relinker jobs failed
to compile the test.
Ruffle (PPSA68091), VLC (PPSA85300) and XPSemu (PPSA97358) read
app0/imports.txt, whose import slot addresses assume the executable's
lowest ELF load page at 0x400000, and dereference them at once. macOS
output always placed that page at 0x140010000, so all three fault on
their first slot read. Linux and Windows have --linux-fixed-base and
--windows-fixed-base for this; macOS had no equivalent.
--macos-fixed-base <address> builds the load image so that the lowest
ELF load page is at the address, as --windows-fixed-base does. The
Mach-O header takes the 64 KiB below it and __PAGEZERO ends there. The
executable is MH_EXECUTE without MH_PIE, so dyld does not slide it. The
address must be 64 KiB aligned, from 0x20000 through 0x7fffffff0000,
and an image ending past the macOS user address space is refused.
WriteMacOsImage wrote the Windows ImageBase constant into the Mach-O
segment and section addresses, __PAGEZERO, the metadata load bias, the
TLS descriptors and the init pointer, while the relocations it rebases
were computed from the WindowsLoadImage base. Read the base from the
load image everywhere instead. Every caller still builds its image at
ImageBase, so the output is unchanged.
Outputs whose input carries no PT_GNU_STACK get one appended with
PF_R|PF_W and alignment 16 so the kernel does not fall back to an
executable stack marking.
RequiredProgramHeaderCount and WriteLayout now derive from one shared
header list, so the reserved slot and the written header cannot
disagree at any PhNum boundary, when a free input slot should be
reused, or when the RELRO coverage guard reduces the kept count.
Space exhaustion beyond the 16-bit header limit fails loudly instead
of silently skipping the header.
WindowsTlsBuilder allocated the whole TLS block and thread control block
for .gtls, so a large p_memsz cost that much memory even though only the
p_filesz template is written. Store the template and reserve the rest as
the section's virtual size; the TLS directory still covers the whole
block, which the loader copies from the zeroed image.
Backing only the pages a pointer touches splits a zero-filled run into
one section per backed block. Each becomes a Mach-O segment, and dyld's
bind and rebase opcodes address at most 16 segments, so a module with
pointer slots on many separate zero-filled pages converted on main but
failed with --macos. When the segments would pass that limit, adjacent
sections with the same protection are merged again, smallest gap first.
Reported by jotitadev in the review.