The patcher rewrites .dynstr in place and reorders .dynsym for
.gnu.hash, but .gnu.version_d kept pointing at name offsets that the
rewrite had recycled: a library carrying symbol version definitions
came out with renamed or blanked version names while its symbols
still advertised a version.
No library in the build defines symbol versions, so fail on
.gnu.version_d during the section scan and leave the input untouched
instead of carrying version remapping that nothing exercises. The
test covers the rejection and that a library without version
definitions is still patched.
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
The NID patcher rebuilds .dynstr keeping only the DT_NEEDED and
DT_SONAME strings, so DT_RUNPATH kept a stale offset and the patched
libraries shipped with an empty runpath. A library could then load only
those sibling prx that the executable already loads itself:
libSceVideoOut.prx needs libSceKeyboard.prx, which a title that does
not import libSceKeyboard never loads, so it fails at startup.
The patcher now keeps DT_RPATH and DT_RUNPATH strings, and the prx
libraries are linked with a $ORIGIN runpath instead of the build
directory, so they find each other wherever they are copied.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The linker stores a dynamic string that is the suffix of another once
(for example "cos" inside "acos"). The patcher wrote every string
separately, so a library whose renamed exports do not shrink the table
enough failed with "rebuilt .dynstr exceeds original section size".
Strings are now sorted by their reversed text and a string that ends
another one points into it.
Co-Authored-By: Claude <noreply@anthropic.com>