Commit Graph

443 Commits

Author SHA1 Message Date
Adrià Franch ca330dfefb fix(relinker): validate the desktop entry before writing the executable
The icon, title and output path are checked before the ELF is written,
so a malformed icon0.png or param.json leaves no output behind. Paths
with control characters are refused instead of producing an invalid
entry.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 12:39:14 +02:00
Adrià Franch 1ff7b534fe feat(relinker): write a desktop entry with the game icon for Linux executables
ELF has no icon resource, so when sce_sys/icon0.png sits beside the input
the relinker copies it next to the output and writes <output>.desktop
(freedesktop Desktop Entry) with that icon. Name is the param.json title
without trademark signs or line breaks, or the output name without
param.json. Exec is quoted per the spec and the entry is marked executable
so file managers launch it. A malformed icon0.png or param.json fails the
relink; without icon0.png nothing extra is written.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-11 12:39:14 +02:00
fablevoid 3462427519 fix(relinker): accept absolute symbols in macOS guest modules
#698 taught the reader, the module builder and the Windows writer to
resolve relocations against SHN_ABS symbols and to leave them out of the
exports, but the macOS writer still threw "Unsupported guest export
section" for them. PPSA12544 bundles modules with such an export
(RKDbTdN8TO0), so --macos stopped before writing anything.

The macOS writer now resolves a relocation against an absolute symbol to
its value plus the addend, without a rebase, and skips absolute symbols
when exporting, as the Windows writer does. guest_absolute_symbols covers
the macOS output too.

AI-assisted: yes
2026-10-11 10:16:59 +00:00
Adrià ce4263b1a6
Merge pull request #3423 from hawwwwwk/pr/relinker-instruction-length-current
fix(relinker): reject x86 instructions exceeding 15 bytes
2026-10-11 12:22:21 +02:00
boykopovar cfbd516c24
Merge pull request #3397 from boykopovar/feat/show-guest-prx-processing
feat(relinker): show guest prx processing
2026-10-11 13:07:42 +03:00
ethan f2ef0f9557 fix(relinker): reject x86 instructions exceeding 15 bytes
(cherry picked from commit 7243caa56ed79fab09edd23d92851e2508671775)
2026-10-11 03:02:05 -07:00
boykopovar 651edc39f5 test(relinker): expect self containers to be skipped 2026-10-11 12:56:17 +03:00
Adrià 76f2d72d40
Merge pull request #3384 from sypher69/fix/sce-dynlibdata-relocation-offsets
fix(relinker): resolve SCE relocation tables relative to dynlibdata
2026-10-11 11:55:28 +02:00
Dani cdfc11cf56 fix(relinker): resolve SCE relocation tables relative to dynlibdata 2026-10-11 11:34:59 +02:00
boykopovar 480e68a84d fix(relinker): format module size to two decimal places 2026-10-11 12:33:21 +03:00
Adrià Franch de2f7aca22 test(relinker): drop docstring from loader path check 2026-10-11 11:33:17 +02:00
MathiasDevelopes 3f5c6e8336 test(relinker): remove disallowed loader test comments 2026-10-11 11:33:13 +02:00
MathiasDevelopes c245e3abc4 test(relinker): verify unscoped Windows provider load paths 2026-10-11 11:33:13 +02:00
MathiasDevelopes 2faa5dd6ed fix(relinker): load needed providers for unscoped Windows imports 2026-10-11 11:33:13 +02:00
Adrià Franch 364c8936da test(relinker): pin executable import binding to the needed provider 2026-10-11 10:36:00 +02:00
exefer 144b1ea8f8 fix(relinker): bind Linux guest imports by declared module identity 2026-10-11 10:35:55 +02:00
Merijn 1c6eac425d feat(relinker): add --module-dir for modules loaded at run time
Relinks the ELF modules of extra directories under the module parent directory. Modules the executable or another module needs start with the executable; the others are initialized when the title loads them with sceKernelLoadStartModule, with its start arguments (Windows: __aps5_guest_initialize export; Linux: left out of DT_NEEDED).

Squashed onto main by the reviewer (history had a merge commit).
2026-10-11 10:11:31 +02:00
Adrià c8facc79ff
Merge pull request #3325 from AchrafReyani/carry/windows-stub-orphan-failed-line
fix(relinker): print the Windows stub's ' -> FAILED' only with dependency diagnostics
2026-10-11 09:58:25 +02:00
Adrià 832c84298e
Merge pull request #2705 from DariusHQ/fix/windows-guest-libc-placeholders
fix(relinker): skip zero-return guest libc exports for internal libc imports
2026-10-11 09:56:33 +02:00
Achraf Reyani 62d6cbe42d test(relinker): check that a Windows load failure starts with its own message
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:41:25 +09:00
Badr d102e186c9 fix(relinker): print the Windows stub's ' -> FAILED' only with dependency diagnostics 2026-10-11 16:40:50 +09:00
Adrià cfcffebd0f
Merge pull request #3290 from AchrafReyani/carry/relinker-windows-tls-thread-pointer
fix(relinker): place the Windows thread pointer after the TLS size rounded to its own alignment
2026-10-11 09:26:24 +02:00
Adrià 6957bb4ae2
Merge pull request #2785 from tototomate123/fix/hfw-relinker-split
fix(relinker): preserve Linux executable exports and ELF section addresses
2026-10-11 09:20:45 +02:00
DariusHQ e720d3cd61 fix(relinker): skip zero-return guest libc exports for internal libc imports
Since #1454, a libSceLibcInternal import that no native library exports
on Windows falls back to the title's own libc.prx. The loader shim that
ps5-native-app-boilerplate builds into homebrew titles exports 1874
functions at three addresses whose code is `xor eax, eax; ret` or
`pxor xmm0, xmm0; xor eax, eax; ret`. Such an import then binds to a
function that returns 0, and the title starts instead of stopping with
`unresolved ELF import`.

The Windows guest module writer records the exported functions whose
code is one of these two sequences, and the entry stub leaves the guest
libc.prx out of the search for those names. A guest export with code of
its own still provides a missing libSceLibcInternal function, and native
libraries keep their priority.
2026-10-11 09:20:00 +02:00
Adrià a3aca02c5a
Merge pull request #3273 from MarcZX100/codex/fix-relinker-gnu-hash-3224
fix(relinker): read GNU hash symbols during code analysis
2026-10-11 09:17:31 +02:00
Adrià a41bad9771
Merge pull request #3141 from MarcZX100/codex/carry-sce-dyn-3093
fix(relinker): read SCE dynamic tables from PT_SCE_DYNLIBDATA
2026-10-11 09:15:56 +02:00
Adrià 833e5eb507
Merge pull request #3142 from MarcZX100/codex/carry-sce-scan-3093
fix(relinker): stop code scans at the PLT for PS4 executables
2026-10-11 09:12:30 +02:00
Adrià bbb9419642
Merge pull request #3129 from CnRJay/fix/windows-start-without-unused-library
fix(relinker): start on Windows without a missing library nothing imports from
2026-10-11 09:11:54 +02:00
ArjenS-LA 4bc36b19b8 fix(relinker): read GNU hash symbols during code analysis
When the dynamic symbol count is absent from the SCE or SysV hash metadata, derive it from the GNU hash buckets and chain. Keep all table reads within mapped file-backed ranges.

Carried from issue #3224, commit 1a10126089882a2306318f18d19d05b04a764d6c; original author preserved.
2026-10-11 04:48:55 +00:00
MarcZX100 16adcd4871 fix(relinker): validate SCE dynamic data segment 2026-10-11 03:30:09 +00:00
Get-fix ef727569cc fix(relinker): read SCE dynamic tables from PT_SCE_DYNLIBDATA
DT_SCE_STRTAB, DT_SCE_SYMTAB, DT_SCE_RELA and DT_SCE_JMPREL are offsets
into the PT_SCE_DYNLIBDATA segment, as the code analysis and the guest
image reader already read them, but the pipeline read them as file
offsets. That only works when the segment starts at file offset 0, as in
the test fixtures. A PS4 executable (CUSA00900) keeps the segment at
0x53e9b40, so the relinker read its relocations from the code and failed
with "Dynamic string offset is outside DT_STRSZ". Without the segment the
values are still read as file offsets.

(cherry picked from commit 5dbf89a57e096f2891ae786f44c3f57935af2285)
2026-10-11 03:25:49 +00:00
Chad 7755e1d05c fix(relinker): leave needed libraries nothing imports from out of the start-up load list
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 20:14:23 -05:00
Adrià abb2f8e4fc
Merge pull request #2986 from MarcZX100/fix/relinker-windows-unicode-2640
fix(relinker): support Unicode Windows startup paths
2026-10-11 01:46:23 +02:00
Adrià aa79dbdfe3
Merge pull request #2885 from MarcZX100/fix/relinker-linux-input-phdr-interp
fix(relinker): drop input Linux PT_PHDR and PT_INTERP
2026-10-11 01:13:32 +02:00
xXPBSXx 272b9d1338 test(relinker): check Windows TLS thread pointer offset
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 00:56:01 +02:00
xXPBSXx 8e03bb0af8 fix(relinker): place the Windows thread pointer after the TLS size rounded to its own alignment
The converted thread pointer was set to the TLS block plus the size rounded to max(p_align, 16), while the guest reads its first variable at tp minus the size rounded to p_align. For a PT_TLS with memsz 0x21 and p_align 8 (Resident Evil 4) that is 0x30 against 0x28, so the first variable was read from the second slot. The thread pointer now uses the size rounded to p_align; the block layout is unchanged. WIP: the test for this is still missing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 00:56:01 +02:00
Get-fix 9a13dc8c78 fix(relinker): stop code scans at the PLT in executables with PT_SCE_DYNLIBDATA
A PS4 executable (CUSA00900) keeps 37 MiB of read-only data in its
executable segment after the code. The syscall scan and the call-site
resolution decoded the whole segment linearly, reached a float table and
failed with "Unsupported 0F 79 opcode without SSE4A prefix". In
executables with a PT_SCE_DYNLIBDATA segment they now stop at the end of
the PLT that follows the last function of the unwind table. The PLT is
found by searching forward from that function for its first entry, which
pushes the GOT entry at PLTGOT + 8 and jumps through PLTGOT + 16, since
code without unwind entries can sit in between (680 bytes of start-up
code in an OpenOrbis-built sample). When the executable has PLT
relocations and no such entry follows, the relinker fails instead of
guessing. Executables without the segment are scanned as before.

(cherry picked from commit a21e8fe4c0e6c03189d559e992c0f037c076700d)
2026-10-10 22:53:48 +00:00
Abdulrahman Elkordy 87ca3a2cf1 fix(relinker): count unnamed imports only against the library they declare
An import whose module matches no needed library has no library name,
and the Windows startup stub counted it against every library, so a
missing library with nothing imported from it was still never skipped.
Every such import in the executables of Record of Lodoss War, Resident
Evil 4, PRAGMATA and Returnal declares a module that exists under
another file name (libSceJson for libSceJson2.prx, for example), and
none declares libSceXml or Party.

The relinker now keeps the declared module names of those imports, for
the executable and each guest module, and the stub counts a host
library as imported from when its name up to the first dot matches one
of them, ignoring case. A module declared as libGuest still keeps a
missing libGuest.xyz required, as guest_module_identity checks.
Imports without a module ID declare nothing and count against no
library. The rule and the title data are from xXPBSXx.
2026-10-10 17:49:47 -05:00
Abdulrahman Elkordy 8ebf892849 fix(relinker): start on Windows without a missing library nothing imports from
The Windows startup stub stopped at the first DT_NEEDED library it could
not load, even when no import is searched in that library. Titles list
libraries they import nothing from (Road of Death needs libSceXml.prx,
Resident Evil 4 needs Party.prx), so they stopped with GetLastError 126
before running. A host library that no import's search list contains is
now skipped with a message when it is not found; its handle stays null
and is never read. Missing libraries that something imports from, other
load errors and guest modules still stop the start.
2026-10-10 17:49:47 -05:00
simonbbby cfd61a5977 fix(relinker): treat address-taken code as reachable in unused-filter=1
The CFG used by unused-filter=1 followed only direct branches, so code reached
through lea, relative-relocated pointers or jump tables was unreachable and its
imports were dropped. It now roots RIP-relative lea targets, relative relocation
targets and relative jump tables, and counts any RIP-relative reference to a GOT
slot as an access. Address-taken targets are walked after the direct control
flow, and a target that does not decode as an instruction is not code.
2026-10-11 00:35:27 +02:00
StarMrGamer 1a45dee292 fix(relinker): resolve the syscall number through prefixed instructions
The lookback classifies preceding instructions at their decoded opcode
offset, the same place the forbidden-instruction check looks since #1935,
so a legacy-prefixed mov rax, imm or mov r10, rcx is recognized. The REX
byte stays part of the patterns, so mov r8 and mov r8d cannot masquerade
as rax loads. Anything unrecognized still stops the inference.

Adds prefixed fixtures to both test suites: a prefixed constant stub that
must report syscall number 9, and a prefixed clobbered stub that must
report no number.

AI-assisted: yes. The submitting author is responsible for every changed line.
2026-10-11 00:27:44 +02:00
StarMrGamer f7a9629e68 fix(relinker): report the syscall number of a forbidden syscall instruction
The syscall check names only the code offset, so a title that links a FreeBSD
libc (the ps5-payload-dev SDK statically links one into every homebrew binary)
stops with no indication of which call it reached. Those stubs load the number
with a constant before the instruction (mov rax, 9 for link), so decode the
nearest constant load into rax and add it to the message:

  Forbidden syscall instruction at code offset 0xa: syscall number 9

The number is reported only when it can be established. The constant load must
be the instruction directly before the syscall, or one mov r10, rcx (the SDK's
first-argument move, which does not write rax) in front of it; any other
instruction stops the inference instead of returning a stale value, so
mov rax, 9; add rax, 1; syscall reports no number rather than 9. Only the three
invocation opcodes report a number: sysret is a return and keeps the current
message, as does a stub that loads rax from a register, like the SDK's generic
syscall() wrapper. The check still throws; only the text changes.

Tested: relinker-only build, full ctest on Linux x86-64 (45/45). The C++
syscall_scanner test covers the opcode matrix and the review regression; the
Python test_syscall_number covers the same contract through the harness the
relinker lane already runs on Ubuntu, Windows and macOS, where the C++ fixture
helpers (sys/mman.h, posix_spawn) do not build.

AI-assisted: yes
2026-10-11 00:27:44 +02:00
Adrià 4d27834ff9
Merge pull request #2119 from mugurc/macos-rosetta
feat(relinker): convert for Rosetta with --to-rosetta
2026-10-11 00:26:25 +02:00
Adrià Franch 36ffda9a98 test(relinker): check the declared-host import by membership, not as the module's only import 2026-10-11 00:14:26 +02:00
john.maia 5f4a28c2bc fix(relinker): keep Linux imports declared from host modules off guest exports
On Linux every executable or guest-module import whose NID a guest
module exports was renamed to the guest-suffixed name, whatever module
the import declares. A title that bundles a module exporting system
NIDs then had those imports bound to it: the libc.prx loader shim of
ps5-native-app-boilerplate exports placeholder functions under the
libSceLibcInternal NIDs, so DOOM PPSA99666's snprintf, vsnprintf,
memcpy and malloc (declared from libSceLibcInternal) returned 0 and the
title never found its WAD (#1497).

An import now binds to a guest export only when the module it declares
is a guest module, as on Windows. Imports without import-module
metadata keep the previous behaviour, and a title's own libc.prx
imported from libc still binds to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:14:19 +02:00
mugurc 92b20608e8 feat(relinker): convert for Rosetta with --to-rosetta
Rosetta runs AVX2, FMA, BMI1/2, F16C and MOVBE, but, unlike an Intel
host, it has neither RDSEED, CLWB nor RDPID. --to-rosetta converts
everything --to-intel does and lowers these three as well:

- RDSEED becomes RDRAND (the /6 form of the same opcode), which also
  returns a random value and sets CF.
- CLWB only writes a cache line back, so it becomes a NOP of the same
  length.
- RDPID becomes a load of 0 through an optional stub: Rosetta's TSC_AUX
  is a constant, not a processor index, so every thread reports
  processor 0. A site with no movable instruction after it for the jump
  is kept.

The flag implies --to-intel and conflicts with --windows. It is
independent of --macos: it only changes what the conversion produces, so
--macos alone leaves these instructions as they are, as on an Intel Mac,
and a title for Rosetta is relinked with --macos --to-rosetta. Intel
output is unchanged: the target is a parameter of the converter, Intel by
default.
2026-10-10 22:46:45 +03:00
Doston Abdullayev b1f0f1bff7 test(relinker): convert the non-ASCII working directory case in an ASCII directory
The relinker reads its arguments as narrow strings, so on a Windows
system whose ANSI code page cannot represent the directory it cannot
open the input, and the windows_working_directory case failed before
reaching the executable. Convert the case under an ASCII name and rename
the directory before starting the executable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:42:28 +00:00
Doston Abdullayev 28b1f1578f fix(relinker): walk Windows dependency diagnostics through the wide API
The --windows-diagnostics walker looked up modules and directories with
GetModuleHandleA, LoadLibraryExA, GetFileAttributesA,
GetModuleFileNameA and GetSystemDirectoryA, so under a directory outside
the ANSI code page it failed with "dependency diagnostics Windows API
failed" instead of naming the missing dependency.

Keep the walker's paths in UTF-8 and convert them at the Windows API
calls, which now use the wide functions. The entry stub passes it, and
prints, its paths as UTF-8 instead of the ANSI code page. The dependency
diagnostics test now builds its fixtures under a non-ASCII directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:42:28 +00:00
Doston Abdullayev 19803c0086 fix(relinker): start Windows executables from directories outside the ANSI code page
The Windows entry stub read its path with GetModuleFileNameA, which
turns every character the ANSI code page cannot represent into '?', and
then used it with SetCurrentDirectoryA and LoadLibraryExA. A converted
executable in such a directory (Japanese on a Western-locale system, an
emoji, a script without an ANSI code page) stopped at start-up with
ERROR_INVALID_NAME.

Read the path with GetModuleFileNameW and enter the directory and load
the libraries with SetCurrentDirectoryW and LoadLibraryExW, with library
paths stored as UTF-16. Messages and the --windows-diagnostics walker
still get the paths in the ANSI code page, as recorded in TechnicalDebt.

Fixes #2640

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:42:28 +00:00
Dean 4a747c4872
Merge pull request #2882 from MarcZX100/codex/relinker-nonascii-2692
fix(relinker): handle Unicode paths on Windows
2026-10-11 07:56:44 +13:00
ctj01 b7d5f18c41 fix(relinker): drop the input PT_PHDR and PT_INTERP from Linux output
The Linux patcher writes its own PT_PHDR and PT_INTERP but also copied
the input's. glibc takes the load bias from the last PT_PHDR, which was
the input's entry with the pre-relink address, so such an executable
crashed at start. Both copies also took program header slots, so an
input with PT_PHDR and PT_INTERP and no spare slots failed to relink.
2026-10-10 17:33:59 +00:00
MarcZX100 c5ffebe15a fix(relinker): preserve empty Windows arguments 2026-10-10 17:28:07 +00:00
MarcZX100 fe81332b08 test(relinker): cover unicode guest module paths 2026-10-10 17:22:07 +00:00
MarcZX100 8cbebea6b7 fix(relinker): preserve unicode module paths 2026-10-10 17:22:07 +00:00
aplatogg b74774f713 fix(relinker): support non-ASCII input paths on Windows
The MinGW CRT delivers argv to main as ANSI code page bytes, and every narrow string became a filesystem path through the same code page, so a game in a directory with characters outside the code page failed to open (#2692). Read the command line as Unicode (wmain via -municode), keep paths as UTF-8 strings, convert at the filesystem boundaries through Io::NativePath and Io::Utf8Path, and run the --autorun output through CreateProcessW.

(cherry picked from commit 30a5181f8a71b177cf2dc03334e39998938b3472)
2026-10-10 17:22:07 +00:00
AlxcBTW fccfbee72b fix(relinker): convert Windows guest TLS reads after zero alignment padding
The Windows TLS rewriter only patches FS-relative instructions that
CodeInstructionCollector decodes. Code that no symbol, unwind range or
root reaches is covered by a linear sweep that starts after int3 padding
and stops at the first instruction beginning with two zero bytes, so
zero-filled bytes are not read as code.

The .NET NativeAOT homebrew titles pad between functions with zero bytes
instead of int3 and have unwind entries for only part of their code. In
Prospero Vibrate (PPSA99920) the sweep ended at the padding after the
first function. Functions reached only through switch jump tables, which
the control-flow graph does not follow, or through pointers it cannot
resolve kept 105 of 670 FS loads unpatched: 84 `mov reg, fs:[0x28]`
stack-guard reads (65 into rax, 19 into rcx) and 21 `mov rax, fs:[0]`
thread-pointer reads. The title faulted reading address 0x28 within a
second of start.

The sweep now treats a zero run that follows a jump, call, return or
trap and ends at the next 16-byte boundary as alignment padding, and
continues at that boundary. A call counts because a function can end in
a call to a noreturn function. Zero fill after straight-line code, or a
whole zero 16-byte block, still ends the sweep as before.

All 670 FS loads in PPSA99920 are now patched, as are the 102 of 685 in
Prospero Explorer (PPSA99109) and the 103 of 718 in Prospero Multi Tools
(PPSA99110). New tls_function_coverage padding cases: loads behind zero
padding after a return, a call and a jump, with 13, 2, 1 and 5 zero
bytes, are patched; a load behind zero fill after a nop is left
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0306c677784b6c4272990ce65f6daf9fb2dbc3ca)
2026-10-10 16:08:54 +00:00
tototomate123 ded8b4df23 fix(relinker): preserve executable exports and dynamic lookup tags 2026-10-10 16:58:39 +02:00
tototomate123 7ea423f78b fix(relinker): map executable section addresses through load segments 2026-10-10 16:57:31 +02:00
boykopovar 0bd2e4cb90 test(relinker): align module tests with nonrecursive discovery 2026-10-10 15:31:17 +03:00
boykopovar 336d481bff fix(relinker): default module path to input elf directory 2026-10-10 14:12:04 +03:00
boykopovar bec6d62b29 feat(relinker): add explicit guest module parent path option 2026-10-10 14:10:13 +03:00
boykopovar 776f7738d4 fix(relinker): stop requiring host dependencies in guest module directories 2026-10-10 14:04:37 +03:00
boykopovar 400a496792 refactor(relinker): unify guest module diagnostics 2026-10-10 14:02:00 +03:00
boykopovar 41126bfa5b fix(relinker): restrict guest module discovery to adjacent directories 2026-10-10 13:59:11 +03:00
Adrià ebe6c180bf
Merge pull request #2594 from morten-holm/pr/macos-clear-pie
fix(relinker): leave MH_PIE clear in the macOS executable
2026-10-10 11:15:15 +02:00
Adrià 3d1a7d90c7
Merge pull request #2619 from oneandonlydean/fix/carry-2525
fix(relinker): skip repeated DT_NEEDED libraries
2026-10-10 11:01:22 +02:00
Adrià 69e9a2685a
Merge pull request #2605 from elsi06/fix/relinker-self-guest-modules
fix(relinker): reject guest modules in SELF containers
2026-10-10 10:52:52 +02:00
nyavana 8b008a3e96 test(relinker): cover repeated guest module dependencies
Generate guest PRX dependencies with adjacent and separated repeats, equal names at distinct string offsets, and invalid-name controls. Check acceptance for Linux and Windows conversion and first-seen dependency order in ELF outputs.

Depends on the production fix by Hannah Lyons (babyhuey), c1a6696872153b8e41608f4cc8ab9a0d36f1d206. Written with AI assistance.
2026-10-10 21:23:19 +13:00
Yassine 6158444f71 fix(relinker): leave zero-filled PT_LOAD memory out of Windows files
WindowsPeWriter stored every PE section with SizeOfRawData equal to its
virtual size, so the zero-filled tail of a PT_LOAD segment (p_memsz above
p_filesz, the .bss) was written to the executable byte for byte. A segment
with 256 MiB of .bss produced a 269 MB .exe, while the Linux output of the
same image is under 5 KB.

Each section is now stored up to its last non-zero byte, aligned to the file
alignment, and VirtualSize keeps the full size. The PE loader zero-fills the
part of a section beyond SizeOfRawData (Microsoft PE format, section table:
SizeOfRawData). A section with no non-zero byte gets no raw data and a zero
PointerToRawData.

windows_bss relinks an image with 64 MiB of .bss, checks the section table
and the mapped image, and on Windows runs the executable, which reads the
last word of the .bss.
2026-10-10 21:23:19 +13:00
Hannah Lyons 0e03ad0f95 fix(relinker): skip repeated DT_NEEDED libraries 2026-10-10 21:23:19 +13:00
Patrick Elsasser bc444a675d fix(relinker): reject guest modules in SELF containers
A bundled module whose file starts with a SELF container magic
(4f 15 3d 1d or 54 14 f5 ee) was skipped like any other non-ELF file,
so the relink succeeded without it and the module was missing at run
time. The guest module scan now throws, naming the module, as
ElfReader already does for a SELF executable.

Fixes #2599

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:22:58 +02:00
gunerky b2ff4f4b02 test(relinker): split TLS coverage into bounded CTest groups 2026-10-10 10:07:33 +02:00
Hamidreza 41856ea6c5 perf(relinker): single-pass CFG instruction decoding and zero-copy text span 2026-10-10 09:48:02 +02:00
Adrià 2f250f83aa
Merge pull request #1815 from eliasbruno124-dev/fix/nested-required-modules-publication
fix(relinker): discover required modules in nested standard directories
2026-10-10 09:19:07 +02:00
Dean edbf36ad4c
Merge pull request #2574 from oneandonlydean/fix/carry-2464
fix(relinker): start Windows executables in their own directory
2026-10-10 20:07:53 +13:00
Morten Holm 31b6af028f fix(relinker): leave MH_PIE clear in the macOS executable
The executable is linked at a fixed base with a __PAGEZERO that fills the space below it, and
the guest assumes 16 KB pages. With MH_PIE set dyld slides the image by a multiple of 4 KB,
which breaks that assumption and ends in a SIGBUS (KERN_PROTECTION_FAILURE) in about half of
the launches under Rosetta 2. Clearing the flag keeps the image at its linked address.

test_macos_output.py now reads the header flags and checks that MH_PIE is clear.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 09:07:14 +02:00
Adrià 653e3d04d7
Merge pull request #2097 from treuenten/fix/relinker-entry-stub-rel32
fix(relinker): reject a Linux entry stub whose call cannot reach the entry
2026-10-10 08:49:35 +02:00
Dean 6f262eb0f4
Merge pull request #2568 from oneandonlydean/fix/relinker-decode-xop-2559
fix(relinker): decode XOP instructions
2026-10-10 19:47:50 +13:00
Get-fix 975475929e fix(relinker): start Windows executables in their own directory
The guest filesystem root and the save data directory are taken from the
current directory, so an executable started from another directory does
not find its title files and keeps saves elsewhere. Make the executable
directory the current directory in the Windows entry stub before the
system libraries are loaded.
2026-10-10 19:44:06 +13:00
Adrià d7f24e7652
Merge pull request #2294 from Vabian124/cursor/fix-relinker-reject-non-regular-input-9077
fix(relinker): reject non-regular input files
2026-10-10 08:35:29 +02:00
Adrià 8f693fc82c
Merge pull request #2274 from jweidenh/codex/fix-linux-program-header-count
fix(relinker): count all synthetic Linux program headers
2026-10-10 08:32:53 +02:00
Achraf Reyani ce8dbc977f fix(relinker): decode XOP instructions
The x86 decoder had no XOP (AMD 8F escape) support and read 8F E8.. as
POP r/m, losing instruction boundaries. Since #2238 roots code addresses
taken by RIP-relative LEA, code analysis reaches CPU-dispatched XOP
paths, such as the vpperm routines in Stremio Plus (PPSA74126), OpenNOW
(PPSA99082) and PPSA99420, and their Windows conversion failed with
"Code analysis: overlapping instruction boundaries". Decode 8F followed
by a map of 8 or more as a three-byte XOP prefix (8F can only be POP r/m
with ModRM.reg 0) with a ModRM operand, an 8-bit immediate in map 8 and
a 32-bit immediate in map 0Ah, in both the length and operand decoders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:27:24 +13:00
Cursor Agent eba1dec764 fix(relinker): reject non-regular input files
A directory opens and tellg reports an enormous size, so the relinker
tried to allocate it and failed with std::bad_alloc. Require a regular
file and a non-negative size before allocating the input buffer.
2026-10-10 08:26:32 +02:00
simonbbby fcb0b962a7 fix(relinker): collect init and fini array roots through the containing load segment
The unused-filter=1 entry point collector translated DT_INIT_ARRAY and
DT_FINI_ARRAY through PT_DYNAMIC and skipped arrays placed before it, which is
the usual linker layout, so constructors and destructors were not roots and
imports used only by them were dropped. Arrays are now translated through the
PT_LOAD that holds them, slot targets come from RELATIVE relocations when
present, and DT_PREINIT_ARRAY is collected as in the strict filter.
2026-10-10 08:25:50 +02:00
Adrià 019ca236fb
Merge pull request #1958 from arcwiser/fix/windows-pe-relocs-stripped
fix(relinker): keep Windows images without relocations loadable
2026-10-10 08:06:20 +02:00
eliasbruno124-dev e2401a8dc0 fix(relinker): discover required modules in nested standard directories 2026-10-10 08:05:01 +02:00
Adrià be775231a2
Merge pull request #1651 from emirplus/feat/relinker-tls-register-alu
feat(relinker): support Windows guest TLS reads by ALU register-address instructions
2026-10-10 07:58:52 +02:00
Dean 6635c7abbf
Merge pull request #2117 from krishalivaibhav/codex/relinker-help
feat(relinker): support explicit CLI help
2026-10-10 18:54:09 +13:00
Dean e31154aa90
Merge pull request #2196 from AchrafReyani/fix/relinker-entry-point-bounds
fix(relinker): bound the entry point collector's header and symbol reads
2026-10-10 18:54:02 +13:00
jweidenh c8a23b1ad5 test(relinker): reserve all headers in native execution fixtures 2026-10-10 01:38:08 -04:00
jweidenh 25984a728c fix(relinker): count all synthetic Linux program headers 2026-10-10 01:38:07 -04:00
Dean 3aae312a4b
Merge pull request #1552 from arvindfroi/test/decoder-length-table
test(relinker): check decoder lengths against an LLVM-generated table
2026-10-10 18:36:17 +13:00
Achraf Reyani b1599a94ea fix(relinker): bound the entry point collector's header and symbol reads
The CFG/GOT filter's entry point collector checked header and symbol
positions as `offset + size > file size`, which wraps for offsets
near 2^64. A section header or symbol table offset there passed the
check, read bytes before the input buffer, and could reach an
in-bounds table through the wrapped address, adding entry points that
keep relocations alive. Check every position by subtraction instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:23:20 +09:00
JohnM ded18e503f fix(relinker): reject a Linux entry stub whose call cannot reach the entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 13:22:07 +08:00
krishalivaibhav 1fc31ba358 feat(relinker): support explicit CLI help 2026-10-10 10:31:52 +05:30
Dean cb3aecac97
Merge pull request #2339 from johnmaia/fix/relinker-terminate-frame-chain
fix(relinker): end the guest frame-pointer chain at the entry stub
2026-10-10 17:47:11 +13:00
Dean 2c7d2cec17
Merge pull request #2262 from NumberGuan/codex/validate-elf-identification
fix(relinker): validate ELF identification before parsing
2026-10-10 17:46:17 +13:00
Dean 42a1b1d75a
Merge pull request #2256 from NumberGuan/codex/fix-truncated-eh-frame-headers
fix(relinker): reject truncated EH frame headers
2026-10-10 17:46:09 +13:00
Dean a5a4919746
Merge pull request #2245 from NumberGuan/codex/fix-eh-frame-sleb128-overflow
fix(relinker): reject overflowing signed unwind LEB128 values
2026-10-10 17:45:54 +13:00
Dean e2ba429015
Merge pull request #2243 from NumberGuan/codex/protect-relinker-inputs
fix(relinker): protect executable inputs from output overwrites
2026-10-10 17:45:47 +13:00