Trailing integer arguments: the variadic stack base, `SifRegisterRpc`'s decode, and the register-then-stack fallbacks

Open
#196 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 5 days

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
22/100
Issue type
Refactor
Clarity
Needs clarification
Activity status
Quiet
Tech stack
cpp

Research direction

Read Ps2VarArgCursor::readWordAtSlot in Kernel/Stubs/Helpers/Support.h, sceGifPkRefLoadImage vs the $sp+0x10 stack base, SifRegisterRpc in Kernel/Syscalls/RPC.cpp, and decodeGsTrailingArgs2/decodeGsTrailingArgs3/decodeGsSetDefImageArgs in Kernel/Stubs/GS.cpp and Support.h. Cross-check #186 and #195. Done is a maintainer decision on stack continuation, RPC decode, and whether the register-then-stack fallbacks stay; this issue does not specify a patch.

Written by the indexing model from the issue text.

Description

enhancement runime

Ps2VarArgCursor::readWordAtSlot in Kernel/Stubs/Helpers/Support.h states the
convention outright — "EE calls use eight integer argument registers (a0-a3,
t0-t3 / r4-r11)". sceMcGetDir/sceMcGetInfo in Kernel/Stubs/MemoryCard.cpp
have already been moved off readStackU32 onto bare GPR 8 reads (and GPR 9 for
the one with a sixth argument), and #195 does the same for
sceSifSendCmd. I am not asking which convention you want — that reads as
decided.

This is not a bug report: I have no reproduction, and nothing here is known to
break a title today. Below are places in the tree that contradict each other and
that I could not resolve by reading.

1. Where the stack continues after the eighth register slot.
sceGifPkRefLoadImage takes eight arguments from GPRs 4-11 and continues at
0(sp), with no caller-reserved save area — which is what the eight-register
convention implies. It reads its ninth and tenth arguments at offsets 0 and 8,
an eight-byte stride rather than the four a 32-bit word occupies.
Ps2VarArgCursor also takes slots 0-7 from GPRs 4-11, but sets its stack base
to $sp + 0x10 — the first o32 stack-argument slot, immediately above the
16-byte caller-reserved save area. For one callee shape those cannot both be
right. Deliberate — variadic callees genuinely differing from non-variadic ones
on the EE — or a leftover? It is the printf family's decoder
(formatPs2StringWithArgs is called by printf, printf_r, sprintf,
snprintf, fprintf and scePrintf), so it only bites once a format run
consumes past the eighth slot. What would decide it: a disassembly of a variadic
call site in a real title, showing whether the ninth argument goes to sp+0x10
or 0(sp), and whether the tenth sits four bytes past it or eight. I do not have
one; if you do, that answers it.

2. SifRegisterRpc still decodes as if only four registers carry arguments.
In Kernel/Syscalls/RPC.cpp it takes sdPtr, sid, func and buf from
$a0-$a3, then reads cfunc, cbuf and qd from 0x10/0x14/0x18 off
$sp. Under the convention those are GPRs 8, 9 and 10. I left it out of
#195 because existing ps2xTest cases pin that decode by seeding all
three on the stack; flipping it means rewriting them, and I did not want to
without knowing whether the stack decode is intentional. Want a follow-up PR
that moves it to registers and updates the tests?

3. Are the register-then-stack fallbacks shims or the intended design?
decodeGsTrailingArgs2/decodeGsTrailingArgs3 in Kernel/Stubs/GS.cpp take the
o32 slots only when the whole register group reads zero and the stack group does
not. decodeGsSetDefImageArgs in Support.h is different again: it weighs
reg10 != 0u || reg11 != 0u against stack2 != 0u || stack3 != 0u, ignoring GPRs
8 and 9 in that test, with a third legacy branch below. They share one blind spot:
none can tell a legitimately zero argument from an empty register window, so
firing on a genuine zero substitutes stale stack bytes. My own position is split
on purpose. #186 (open) adds a call site to decodeGsTrailingArgs3, on the grounds it
gives that helper's existing user, sceGsSetDefDBuffDc, a consistent sibling and
reproduces the previous stack reads exactly when the register group is all zero.
#195 declines the shape, because for sceSifSendCmd an all-zero
register group is the ordinary call, so reproducing the previous stack reads there
reproduces the wrong decode. So I am not asking you to retire them on my account —
only whether they are relied on by titles you have running, or shims you would
take a PR against.

Dominant language
C++
Stars
3.3k
Forks
149
Avg merge
8h 46m
Merged PRs (30d)
1

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ran-j/PS2Recomp

All issues in ran-j/PS2Recomp

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.