--help printed three syntax lines with no explanation, so the only
discovery surface was the 67 KB USAGE.md. List every option with a
one-line description, grouped by purpose, plus the exit codes. The first
line keeps the "Usage: relinker" prefix the CLI tests match.
masked_store_lowering failed twice under Rosetta on GitHub's macOS x86_64
runner (runs 40216485859 and 40438653738) with only "Masked store stub
changed the flags", while the stored bytes, faults, vector and general
registers, red zone and RSP all matched. The message now names the form,
width, addressing mode, offset, mask pattern, fault count and the flags
before and after, so the next occurrence shows which flags change and
whether the probe faulted.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Windows writer accepted any image up to the 2 GiB RVA bound, so an
image with a SizeOfImage above 0x77000000 converted with exit 0 and then
failed to start with ERROR_BAD_EXE_FORMAT (193). WindowsPeWriter::Write
now refuses such an image, matching the loader's SizeOfImage >
MM_SIZE_OF_LARGEST_IMAGE (0x77000000) test, which applies to executables
and to bundled modules alike. Images with a SizeOfImage of at most
0x77000000 are written unchanged.
LinuxElfPatcher::Patch zeroed only e_ident bytes 7 and 8 of the output
executable, and ElfReader checks only bytes 0 to 6, so nonzero EI_PAD
bytes 9 to 15 of the input reached the output in every Linux mode. The
gABI reserves EI_PAD as zero, and glibc's open_verify refuses an object
with nonzero padding when ld.so maps the program itself, as under ldd
or an explicit ld-linux-x86-64.so.2 invocation. The patcher now zeroes
bytes 7 to 15, the rule that #11582 applies to guest modules. Only
reserved bytes change, and a direct exec is unaffected either way.
A RELA entry repeated with the same target, type and addend writes the
same value twice, so applying it once is equivalent. 9673868d5f made the
Windows relocation builder and the code analysis accept such duplicates,
but the strict unused-NID filter still refused one as overlapping, so
the same ELF converted with unused-filter=0 or 1 and failed with
unused-filter=2. The strict filter now records a pointer relocation
only when its slot is new or its target is identical, and still refuses
a distinct entry at one slot and a slot that an import relocation
already owns.
AI-assisted: yes
RelinkerPipeline::Relink accepted ET_EXEC input, and every Linux mode
placed it at base + p_vaddr: at 0x400000 by default, at the
--linux-fixed-base address, or at a load bias as ET_DYN with
--lazy-binding, so its absolute references that carry no relocation
kept pointing at the link addresses. The gABI chapter on program
loading says the segments of an executable file must reside at the
virtual addresses used to build it. ET_DYN and the SCE dynamic types
0xfe10 and 0xfe18, the types WindowsLoadImage already accepts as
position independent, may be placed at a base. Relink now rejects
ET_EXEC on every target before the allowlist, which accepts ET_DYN,
0xfe10 and 0xfe18. ET_EXEC input now exits 2 without writing output;
outputs for the other accepted types are unchanged.
An executable relocation of type R_X86_64_64, PC32, 32, GLOB_DAT or
JUMP_SLOT against an STT_TLS symbol, defined or undefined, became a
named import, and the Linux output kept it typed STT_TLS. The gABI
allows STT_TLS symbols only in TLS relocations, since their value is
an offset in the TLS block and not an address, and GuestImageReader
already rejects such relocations in guest modules. The pipeline now
fails on them in extractRela for every target and writes no output.
ANYPS5_BUILD_FUZZERS builds relinker_conversion_fuzzer with AddressSanitizer
and UndefinedBehaviorSanitizer in relinker-only Clang builds on Linux. The
first input byte selects the target system, --to-intel and the unused-filter
level; the rest is the executable passed to Conversion::Convert, the path the
web converter takes. tools/relinker_fuzz_seeds.py writes the relinker test
fixtures as seeds, and CTest runs a short smoke run.