From dca7c50e0b3e81628fc706eafb51a5ae25c0f3b6 Mon Sep 17 00:00:00 2001 From: Jordan Hoff Date: Sat, 3 Oct 2026 10:33:06 -0600 Subject: [PATCH] Write every byte of a section: fix the stub's zero-fill and the trimmed 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 Claude-Session: https://claude.ai/code/session_01VdURrNBJ6MvWbY6gZ2VYrz --- ps2-packer.c | 4 +++- stub/main-kmode.c | 22 +++++++++++++++------- stub/main.c | 22 +++++++++++++++------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/ps2-packer.c b/ps2-packer.c index aab6b83..15d13fd 100644 --- a/ps2-packer.c +++ b/ps2-packer.c @@ -501,11 +501,13 @@ void packing(FILE * out, FILE * in, u32 base) { pdata = (loadbuf + eph[i].offset); section_size = eph[i].filesz; - psh.originalSize = section_size; psh.virtualAddr = eph[i].vaddr; psh.zeroByteSize = eph[i].memsz - eph[i].filesz; remove_section_zeroes(pdata, §ion_size, &psh.zeroByteSize); + /* The stub decompresses originalSize bytes and zero-fills from there, so it must be the + trimmed size: the bytes remove_section_zeroes() took off the end are now in zeroByteSize. */ + psh.originalSize = section_size; printv("Loaded section: %08X bytes (with %08X zeroes) based at %08X\n", psh.originalSize, psh.zeroByteSize, psh.virtualAddr); #ifndef PS2_PACKER_LITE diff --git a/stub/main-kmode.c b/stub/main-kmode.c index d5c4168..c5446a3 100644 --- a/stub/main-kmode.c +++ b/stub/main-kmode.c @@ -9,19 +9,27 @@ #include "packer-stub.h" +/* Zero exactly [ptr, ptr + size). ptr and the loop flag are written by the asm, so they are output + operands, and the flag is early-clobber so it cannot share a register with end. */ static void fast_memzero(u8 * ptr, u32 size) { - u32 t; + u8 * end = ptr + size; + u32 more; + if (!size) + return; __asm__ volatile ("\n" - "\taddu %0, %1, %2\n" + "\t.set push\n" + "\t.set noreorder\n" "1:\n" "\tnop\n" "\tnop\n" "\tnop\n" - "\tsb $0, 0(%1)\n" - "\tsltu %2, %1, %0\n" - "\taddiu %1, 1\n" - "\tbnez %2, 1b\n" - : "=r" (t) : "r" (ptr), "r" (size) + "\tsb $0, 0(%0)\n" + "\taddiu %0, %0, 1\n" + "\tsltu %1, %0, %2\n" + "\tbnez %1, 1b\n" + "\tnop\n" + "\t.set pop\n" + : "+r" (ptr), "=&r" (more) : "r" (end) : "memory" ); } diff --git a/stub/main.c b/stub/main.c index 52f25c3..f883003 100644 --- a/stub/main.c +++ b/stub/main.c @@ -10,19 +10,27 @@ #include "packer-stub.h" #if 1 +/* Zero exactly [ptr, ptr + size). ptr and the loop flag are written by the asm, so they are output + operands, and the flag is early-clobber so it cannot share a register with end. */ static void fast_memzero(u8 * ptr, u32 size) { - u32 t; + u8 * end = ptr + size; + u32 more; + if (!size) + return; __asm__ volatile ("\n" - "\taddu %0, %1, %2\n" + "\t.set push\n" + "\t.set noreorder\n" "1:\n" "\tnop\n" "\tnop\n" "\tnop\n" - "\tsb $0, 0(%1)\n" - "\tsltu %2, %1, %0\n" - "\taddiu %1, 1\n" - "\tbnez %2, 1b\n" - : "=r" (t) : "r" (ptr), "r" (size) + "\tsb $0, 0(%0)\n" + "\taddiu %0, %0, 1\n" + "\tsltu %1, %0, %2\n" + "\tbnez %1, 1b\n" + "\tnop\n" + "\t.set pop\n" + : "+r" (ptr), "=&r" (more) : "r" (end) : "memory" ); } #elif 1