Moving a PT_LOAD to the end of the file sets its p_align to
min(p_align, 0x1000), since the copy honours only the page. When that
segment carried the largest p_align, the output's largest PT_LOAD
alignment, which Linux uses to align the ET_DYN load bias, fell with
it. SeparateSharedLoadPages now returns the largest power-of-two
p_align above the page that it lowered, and WriteLayout aligns the
header block PT_LOAD to at least that value, as it already does for
the largest kept p_align.
Review feedback: the three mount-family patterns now carry their exact numbers (21, 378, 22) like the mman patterns, so a stub with another number is not matched. The fixture check that changed only the masked bytes could not fail for the unmount fixture, whose number is also 22; it now rewrites the number field to 0, 1, 21, 22 and 378 and requires every other number to be rejected. Technical debt says the numbers are pinned.
Recognize the inlined __syscall6 wrappers of ps5-payload-dev SDK libc/mount.c (mount, nmount, unmount) under --trap-sdk-syscall-stubs, with the four-byte syscall number immediate masked so an SDK build that renumbers the call still matches. The three wrappers differ in argument preparation, so each sequence is matched separately.
Observed in ftpsrv v0.21.1 (0x709a, 0x70ec, 0x713c) and websrv v0.35 (0xae6a, 0xaebc, 0xaf0c). Related: issue #8624, open draft PR #8729 covers mount only.
RELA entries are applied in order, and an R_X86_64_RELATIVE entry writes
relocbase + addend to its target (FreeBSD rtld's reloc_non_plt). Two
symbol-less RELATIVE entries for one target therefore leave the later
addend in place. Guest-module parsing and code analysis refused the pair
as overlapping; now the later entry replaces the earlier one.
PS5MC's sce_module/libc.prx (PPSA99420), the loader companion its build
generates, relocates 0x8058 twice: to 0x80e0, then to 0x82a0. It could
not be converted. Any other overlap, including a RELATIVE entry over a
symbol relocation, is still refused.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A DTPMOD64, DTPOFF64 or TPOFF64 against an STT_TLS symbol defined in the
module itself names the module's own TLS block as much as symbol 0
does, and #10730 rejects both forms for executables. Fail them as well
when the module's PT_TLS has p_memsz 0.
Standalone eh_frame_hdr row after the existing table overflow case:
encoding 0x31 (uleb128 | datarel) with a ten-byte ULEB128 whose last
byte overflows 64 bits, on segments at 0xFFFFFFFFFFFFF000. The reader
must throw "overflowing LEB128 value" from EhFrameReader::leb.
Co-Authored-By: Claude Haiku 5.5 <[email protected]>
CodeInstructionCollector took code pointers from DT_RELA and DT_JMPREL
but not from DT_RELR, which the pipeline has applied since #11463. A
function reachable only through a RELR pointer was therefore no entry
root, and a Windows TLS rewrite or GS trap could overwrite it without
the "would overwrite an executable entry point" refusal that the same
pointer as a RELA R_X86_64_RELATIVE triggers. Read the RELR table with
ReadRelrRelocations and record its slots like relative relocations.
The guest image reader accepted a module's TLS relocations against its
own block, by symbol 0 or by an unnamed zero-value section symbol,
whenever a PT_TLS header existed, also one with p_memsz 0. Linux output
kept such relocations, while Windows and macOS output rejected only
some of them later with different messages. Require a PT_TLS with a
nonzero p_memsz, as #10730 did for executables, so every target fails
these modules with "Invalid guest TLS relocation".
An executable or guest module with two PT_GNU_EH_FRAME headers converted
on every target: Linux output kept both headers and Windows output wrote
one .ehmeta section per header, while the unwinders at run time use a
single table per object. Reject the second header like a second
PT_DYNAMIC, in the pipeline for the executable and in the guest image
reader for modules.
The set-based control-flow walk inserted the addresses it found into the
caller's set from a destructor. Destructors are noexcept, so a failed
allocation there called std::terminate instead of reaching the
conversion's error handling as std::bad_alloc. The addresses are now
inserted after the walk returns, and before an exception from the walk
is rethrown, as the walk did before.
The new test arms a failing operator new from the progress callback
during a walk of 8,192 instructions and requires std::bad_alloc to reach
the caller; with the destructor it terminated.
Co-Authored-By: Claude Opus 5.5 <[email protected]>