Repository navigation
Write every byte of a section: fix the stub's zero-fill and the trimmed size - #46
Merged
Merged
Conversation
…ed size remove_section_zeroes() moves a section's trailing zero bytes from the compressed stream into zeroByteSize, but originalSize was recorded before the trim, so the stub's zero-fill started at va + filesz and the trimmed bytes were written by nothing. The zero-fill itself did nothing either: fast_memzero's inline asm modified ptr and size while declaring them input-only, so GCC gave the output and ptr the same register and the loop compiled to a single store one byte past the range. Even as written, the compare before the increment stored one byte past the end. ptr is now a read-write operand, the loop flag an early-clobber output, and the loop writes exactly [ptr, ptr + size). The three nops stay, so the loop body is still eight instructions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdURrNBJ6MvWbY6gZ2VYrz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A packed program never gets the bytes
remove_section_zeroes()trims off the end of a section: two defects combine so nothing writes them, and they keep whatever the previous program left in RAM.1.
originalSizeis recorded before the trim.psh.originalSize = section_sizeruns beforeremove_section_zeroes()shortenssection_sizeand adds the trimmed count tozeroByteSize. The stub decompresses the shorter stream to[va, va + filesz - trimmed)and starts the zero-fill atva + originalSize=va + filesz, so[va + filesz - trimmed, va + filesz)is written by nothing. (The fill also runstrimmedbytes past the end of the segment.) It is now set after the trim.2. The stub's zero-fill does nothing.
fast_memzero()writes toptrandsizeinside its inline asm while declaring them input-only, so GCC may give the output andptrone register. In thelzma-1d00-stubbuilt by the current toolchain (GCC 15.2.0,ps2max/dev:v20260228, ps2-packer at9afec04) the loop is:One byte stored past the range, then out. Even as written, the compare came before the increment, so the loop stored one byte past the end.
ptris now a read-write operand and the loop flag an early-clobber output, the loop writes exactly[ptr, ptr + size), and the threenops stay so the body is still eight instructions. Same change inmain-kmode.c(it shares the code; only the LZMA user-mode stub was exercised below). The patched stub's loop:Why it matters. Programs mostly survive because ps2sdk's
crt0clears.bssfrom_fbss, but the trimmed bytes sit below_fbss. In a ps2sdk program the last word of the data segment is newlib's_impure_ptr, whose top byte is0x00for anything linked below0x01000000, so it is exactly that byte that is lost. A program started withExecPS2over another one's memory inherits it, and current libcglue writes through_impure_ptrbeforemainon every boot:_libcglue_timezone_update→IsT10K()→open()returnsENOSYS, because the path ops are installed by a constructorcrt0runs after_libcglue_init, and_open_rstoreserrno. With a non-zero leftover byte that is a TLB store miss beforemain. On hardware it is a black screen; PCSX2 logsTLB Miss ... [store]and carries on, so it does not show in the emulator.Released software has it. The current Open PS2 Loader beta (
OPNPS2LD.ELFfrom v1.2.0-Beta-2245-3e3f34e, itself ps2-packer output) has one section at0x00100000whose stream ends a byte short oforiginalSize: the last word of its image is_impure_ptrat0x42bf00(0x0024b8e8, its_impure_data), and the shipped stub never writes its top byte at0x42bf03. Whether that bites depends on what the launcher left at that address.Tested
0x685b07and0x686187); the patched packer leaves none. Repacking with the unpatched packer reproduces the original images byte for byte, so the inputs are the same programs.ExecPS2over another: 9TLB Miss [store]with the shipped packer, 0 with the patched one, same input, same chainer, same point reached afterwards.ExecPS2over another whose byte at its tail address is0x54died at the handover with the shipped packer (black screen, no network), and the same input repacked with the patched packer came up 2 of 2, by the same chain.Until a fixed stub is installed, ending the segment in a non-zero byte (a
LONGat the end of.sdatain the linker script) keeps the packer from trimming anything.🤖 Generated with Claude Code
https://claude.ai/code/session_01VdURrNBJ6MvWbY6gZ2VYrz