Commit Graph
4 Commits
Author SHA1 Message Date
Karan Shrivastava 0f45390a92 fix(relinker): agree on the syscall number between the two constant-load paths 2026-10-25 23:00:48 -04:00
MarcZX100 0a6247532e feat(relinker): trap exact SDK syscall stubs on request 2026-10-11 16:54:02 +00: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