Limbo's bundled libSceFios2.prx (CUSA01664) has DTPMOD64 relocations
against a local section symbol with section index 0 and value 0, in a
module without section headers. As for a TLS relocation without a
symbol, the module and offset are the module's own TLS block, so a
DTPMOD64 or DTPOFF64 against such a symbol is passed on without it. A
section symbol that names a section or has a value, a TPOFF64, a module
without PT_TLS and a DTPMOD64 with an addend still fail.
Guest module discovery skipped the input executable and the
--executable check rejected an executable converted twice through
std::filesystem::equivalent, which MinGW reports as false for hard links
whose names give different permissions, such as .bin and .exe. Move the
GetFileInformationByHandle comparison to Io::SameFile and use it for
these checks and for SameOutputFile.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Trimming the end of any PT_INTERP inside an executable segment dropped
the code in front of one that follows it, so an image without an SCE
block whose interpreter sits after its code lost its entry points. The
trim now applies to an interpreter that starts the segment, and the SCE
path keeps taking any interpreter inside the scanned range, as before.
The code analysis trims an interpreter path from the start of an
executable segment only for images that have a PT_SCE_DYNLIBDATA block.
An executable without one keeps that path in the scanned range, so
/libexec/ld-elf.so.1 is walked as code: a RELATIVE relocation with
addend 0 roots the control flow graph at the first byte of the segment,
and the 0x64 of "ld-elf" decodes as an FS-prefixed instruction that the
Windows and macOS TLS rewriters refuse. The trim now runs for both
layouts, ending at the segment for an image without the block.
The checks on a guest module's output name threw without an input
path, so the conversion's catch reported the main executable. They now
carry the module's path, as the guest image reader's errors do. The
loop's duplicate-export check gets the same change for consistency; it
cannot fire, because the reader rejects a duplicate first.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Windows gs_traps group grew to 21 relinker invocations and ran close to its 30 s CTest timeout on a loaded host. Split the implicit-memory cases into gs_traps_implicit so each group stays well under the limit, and share the per-case check between them.
The raw-byte check that runs before a syscall pattern between PS4 unwind
functions is skipped now also accepts mov rax, imm64, merges a following
mov al, imm8 or mov ax, imm16 into the earlier constant, and walks back
over any number of register moves or zeroings that leave rax alone
instead of at most seven. Visited states keep the walk linear in the
bytes it covers.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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]>