When a computed jump cannot be resolved to a jump table, every instruction in
the function becomes an entry point, because the jump could land on any of
them. That fallback was also applied to JALR, which is not a jump but a call:
it transfers control to another function and returns to the instruction after
the delay slot. That return address is already queued as a resume target a few
lines above, so nothing else in the function needs to be reachable from
outside.
Indirect calls are ordinary code -- function pointers, virtual dispatch,
callbacks -- so the fallback fired constantly. On a 3 MB PS2 executable, 2,210
of the 2,422 unresolved sites were JALR, and 1,078 of the 1,282 affected
functions contained no unresolved jump at all.
Restrict the fallback to JR. Promoted entries drop from 189,876 to 1,688,
registered table entries from 156,783 to 75,386, the generated registration
file from 13 MB to 6 MB, and total output from 180 MB to 163 MB. Every
indirect call site in real code keeps its return-address resume entry (the
only sites that lose one are bogus functions carved out of rodata, where the
address is outside the function anyway).
ps2xRecomp and ps2xAnalyzer reached ps2xRuntime through CMAKE_SOURCE_DIR,
which is the top-level source directory of whatever build is running. That
holds only when this repository is itself the top level; adding it to another
project with add_subdirectory() made both components look for
ps2xRuntime/cmake/ReleaseMode.cmake under the consuming project and fail at
configure time.
Use CMAKE_CURRENT_SOURCE_DIR-relative paths, as ps2xRecomp already does for
its ps2xRuntime include directory and ps2xRuntime does for its own cmake
include. Note that each component declares its own project(), so
PROJECT_SOURCE_DIR is not an alternative here.
BEQ and BNE already compare the full GPR, but BLEZ, BGTZ, BLTZ and BGEZ (and
their likely/and-link variants) were emitted against the low word only. The
R5900 compares the whole 64-bit register, so any value whose upper half is
significant takes the wrong branch.
Compilers reach these opcodes through the dsll32/dsra32 sign-extension idiom,
which leaves a canonical value and hides the bug; code that keeps a genuine
64-bit quantity in the register does not.
Not every toolchain points e_entry at an instruction. Metrowerks CodeWarrior
for PS2 emits a crt0 data table there -- scratchpad addresses and size words --
with the first real instruction some way past it, so no function covers the
entry address and neither entryName nor getFunctionName() resolves.
The emitter threw in that case, which aborted the run after every per-function
source had already been written but before register_functions.cpp,
ps2_recompiled_functions.h and ps2_recompiled_stubs.h were generated, leaving
an output directory that looks complete and is not.
Skip the entry registration with a warning instead. Synthesizing a name would
emit a table reference to a definition that was never generated and fail at
link time, and the start address for such a binary has to come from
configuration regardless.
On an ELF with no symbols and no DWARF, parse() carves functions from JAL
targets. Those carvings end at the next JAL target or, for the last one in a
region, at the end of the code section, so on a single-PROGBITS executable
they can run straight through interleaved rodata.
loadGhidraFunctionMap() appended its rows to the same vector and then purged
auto-named entries only where no map row shared the start address. Since both
the carvings ("sub_") and the names Ghidra exports by default ("FUN_") count
as auto-generated, a carving that shared a start with a map row survived the
purge and then won the "larger end" tie-break, so the imprecise bounds
replaced the ones the map had just supplied.
Collect the map rows into a local vector, drop every auto-named carving once
the map has parsed, and append the rows afterwards. Entries named from
symbols or DWARF are unaffected.
On a 3 MB Metrowerks-built PS2 executable with an 11,491-row map, 5,613
functions (48.8%) had been emitted with inflated bounds; the worst grew from
368 bytes to 0x51 KB and produced 22 MB of C++ decoding string data as
instructions. Output for that function is now 19 KB and total output drops
from 235 MB to 180 MB.
* refactor: from guest threads to EE scheduler
* feat: bad wip mpeg fix for code veronica
* feat: cheap copy from host
feat: small perf o vsync tick
* feat: added EE clock Hz
fix: fix MPEG out of sync with new EE refactor
* fix: fix lotr tests
* fix: fix cri dtx loading
fix: fix wrong mmi instruction translation
fix: fix thread info params
feat: added EE timers decoder and consumer
feat: split SFI and IOP memory to prevent collision and overrides
* feat: revert wrong changes
* refactor: from guest threads to EE scheduler
* feat: bad wip mpeg fix for code veronica
* feat: cheap copy from host
feat: small perf o vsync tick
* feat: added EE clock Hz
fix: fix MPEG out of sync with new EE refactor
* fix: fix lotr tests
* feat: implement fix and changes based on dark cloud report
fix: fix GS AFAIL for RGB/alpha/Z, ZMSK
fix: fix VU1 flags mask and pipeline
fix: small VU1 cache fix
feat: __ct__, __sinit_ are not sillent stubs anymore
* feat: fix song JP pulling
* feat: sound update for lotR
* feat: prevent guest execution to be very slow
* fix: small gs size bug
* feat: refactor VU
fix: fix cliping and other issues on gs
fix: fix wrong vu0 register on recompiler
* fix fix ACC scheduler stall
feat: remove unused test
fix: .fix overflow e underflow on FMAC
* feat: small setting for windows test
ELFIO, pinned at Release_3.12 via FetchContent, uses uint16_t, uint32_t
and uint64_t in elf_types.hpp without including <cstdint> itself. Newer
libstdc++ releases trimmed the transitive includes that used to supply
those typedefs, so building elf_parser.cpp fails:
elf_types.hpp:30:20: error: 'uint16_t' does not name a type
30 | using Elf_Half = uint16_t;
Include <cstdint> ahead of elfio.hpp so the typedefs are visible when
that header is processed. Header-only change; no behaviour is affected.
* fix(recomp): advance ctx->pc on fallthrough functions with no terminating branch
FunctionEmitter::emit only ever advances ctx->pc via the per-instruction
`ctx->pc = 0x<addr>u;` assignment (overwritten by the next instruction in
the same function) or via handleBranchDelaySlots when the last instruction
is a branch/jump. A function whose last instruction is neither (e.g. a
lone padduw/NOP-style instruction with no terminator) leaves ctx->pc
pointing at its own last instruction forever after returning, since
nothing ever advances it to the next function.
dispatchLoop then reads ctx->pc, looks up the same function, and calls it
again -- forever. No exception, no crash, just an infinite loop that
silently never makes forward progress.
Reproduced on SDBZ's SLUS_214.42 ELF entry point: 0x100008 is emitted as a
standalone 1-instruction function (padduw $at, $zero, $zero) with no
branch, causing dispatchLoop to spin on pc=0x100008 indefinitely.
Fix: track whether the last processed instruction had a delay slot (i.e.
was a branch/jump); if the function ends without one, emit an
unconditional ctx->pc = function.end before closing the function so
dispatchLoop resumes at the next function instead of spinning.
* review: trim overly verbose comment per ran-j feedback
* feat: added guestBranchKind enum to categorize branch types
feat: added missingFunctionPolicy enum to define behaviors for missing function scenarios
refactor: added handle guest branches and report missing functions
feat lookupFunction to utilize new dispatch logic and improve error handling for unregistered functions
* fix: fix test conflict
* feat: added debug sound driver logs
* feat: emmiter for return
* feat: added recompiler reporter
feat: added strict diagnostics flag for heavy debug calls
* feat: staticc table insted of hashmap for runtime
* feat: back file to ignore
* feat: explode code across helpers and classes
* feat: update codegen test
feat: better guest nop check
* feat: fix link problem on linux
* feat: fix Segmentation fault
* feat: added recompile replace for DMA and MMIO
feat: added a clean memory helpers
feat: use memory helpers across the project
feat: fix ucrt on msvc
* feat: undo messup merge
* feat: added guestBranchKind enum to categorize branch types
feat: added missingFunctionPolicy enum to define behaviors for missing function scenarios
refactor: added handle guest branches and report missing functions
feat lookupFunction to utilize new dispatch logic and improve error handling for unregistered functions
* fix: fix test conflict
* feat: added debug sound driver logs
* feat: emmiter for return
* feat: added recompiler reporter
feat: added strict diagnostics flag for heavy debug calls
* feat: staticc table insted of hashmap for runtime
* feat: back file to ignore
* feat: explode code across helpers and classes
* feat: update codegen test
feat: better guest nop check
* feat: fix link problem on linux
* feat: fix Segmentation fault
* feat: added ffmepg as dependency
* feat: wip decoder video
* feat: some perf and cleanup
* feat: added generic MPEG stream notification
* feat: CMakeLists.txt in ps2xStudio to configure SDL2 build options for static linking.
fix: fix ffmpeg setup for linux
fix: now MPEG decoder now identify that movie has ended and can play again anytime
feat: better audio stub to not block games
* feat: fix expansion test
* feat: foo
* a
* feat: finally added a helper to to prevent thread starvation
* feat: added basic vu0 code execution
* feat: added yield Guest Execution After Wake to prevent deadlock
* feat: added options on cmake for logs
feat: better input for keyboard pad
* feat: small corrections like top and itop vu branches etc
* feat: changes
* feat: working feature
* feat: fatal frame iop
* feat: test fix
feat: z buffer fix
* fix: gix GsPutIMR IMR
* feat: added rl imgui
* feat: added helper to get snapshot
* feat: added debug panel consuming snapshots
* feat: added pad snapshot
feat: added RCP debug events
* feat: final cleanup from old code
* feat: added EE timer counter
feat: applyed sound driver for Lotr
feat: better check for sound driver compat layout
feat: enquee and cosumed DMa cause
feat: added Pad execCMd
feat: update GS vsync signal flag
feat: custom IOPs for LotR
* feat: small cleanups
* fix: fix wrong import
* feat: invert codegen hight to low convertion
feat: added copy and GetEntryAddress
feat: handle truncated DMAC
* feat: always use address on analyzer now
* feat: correct pick syscalls ID
* feat: added deci2Call
* feat: added wip dbcmain IOP
* feat: added InitTLB
feat: added err logs on thread for debug sus crash
* fix: fix SetupHeap for strange cases
* feat: fix incorrect SetupHeap test(it use a wrong idea on how heap allocate memory)
* feat: added memalign and memalign_r
feat: added GetOsdConfigParam2 and SetOsdConfigParam2 but idk if was a good idea
* feat: added more memory stuff
* feat: back to library functions
* feat: modularize elf analyzer
feat: added experimental sce symbol scanner
feat: change analyzer order
feat: small optimizations on analyzer
* feat: remove example_config.toml because its causing confusion on some people
* feat: embed sce symbol but leave optional import path
feat: killed skip function on analyzer but leave it so you can skip manual if you want
* feat: pin elfio tag
* feat: manually create string view with size
* feat: update ghidra script
* feat(recomp): Reduce recompiler output memory usage
Stream output generation, add low-memory config controls, and avoid
pathological indirect-jump switch expansion in generated C++.
Low-memory mode now avoids retaining per-instruction disassembly strings
while still emitting asm comments during output generation. Output workers
are bounded/configurable, combined output is streamed, and decoded buffers
are released after generation.
Also document the new output memory settings.
* fix(recomp): added tests for unregistered JR/JALR, updated fallback logic to cover JR/JALR, moved Rabbitizer formatting into R5900Decoder
* feat: remove memory and pad from stub section
* feat: add support for resume entry targets in CodeGenerator (this allow jumps in address outside function)
feat: refactor entry point discovery one more try to reduce big generated file
* feat: optmizations for release build
* feat: remove unused file
* feat: added some test cases for code gen
* feat: added log macro and remove win specific code
* feat: refactor runtime folder structure
feat: added reset sound driver RPC state and compatibility layout
feat: rename and added new test
feat: update RPC calls to use defined constants
feat: added more PSMC(16, 32)
feat: change cd read to try find the asset ignoring case sensitive
fix: fix some render problems
feat: add logs on pad
feat: added more RPC handles
* feat: added game override for code veronica
* feat: apply vita patch
* feat: flags to disable build
* feat: fix merges
feat: break a lot of tests
* feat: better throw error on empty cd path
feat: remove recompiler unusde function
feat: apply missing patch
* feat: gamedp is now part of lib
feat: missing file
* feat: small cleanup
* feat: missing vita changes
* feat: fix more merge
* feat: fix tests
* feat: last missing feature
* feat: added missing import
* feat: rename test local functions
* feat: init syscall on ps2 list
* feat: added DMA helpers
* feat: faster builds
feat: more implement for darkcloud
* feat: back missing file
* feat: added missing includes
* feat: remove test
* feat: missing include
* feat: read register funtion
* feat: build fix
* feat: force exit on detach thread
* fix: CRITICAL fix on code gen on generating BEQ translation, I added a small yeld because goto could spin forever and monopolize guest execution
* feat: add scratchpad alias base and improve scratchpad address handling
* feat: added debug logging on GifArbiter for submit and drain operations
* feat: add interrupt and thread management syscall implementations
fix: change some IDs calls to match ps2sdk
* feat: added vif1 logs
* feat: added logs on gs gpu
feat: added performLocalToLocalTransfer to GS emulation path for TRXDIR = 2. (emulates the PS2 GS “copy this rectangle from one place in VRAM to another”)
* feat: added PSMT8 and refactor PSMT4
* feat: some identation on vu1
feat: added some logs on vu1
* feat: added GuestExecutionScope to temporarily stop owning guest execution, then restore it exactly as it was.
feat: added vsync wizardry
feat: added some regression test
* fix: fix gs logger
* feat: remove extra logs I think they will help no one
feat: move join all threads to prevent the app to get stuck on close, but now it random crash on closing
feat: one more small test on psmt4 to try fix ghosting on re code veronica
* feat: added a small case for exporter from ghidra for metal slug 3
* feat: added ugly code to pass on test
* docs: deprecate the local analyzer workflow in favor of Ghidra
feat: improve the Ghidra exporter for stripped games and internal entry points
fix: correct FindAddress behavior in the runtime
fix: emit missing delay-slot code in recompiler edge cases
feat: add SetSyscall support from @Whoneon
feat: add dispatchSyscallOverride support from @Whoneon
fix: fix Unmatched '{' due to missing newlines from issue #96
feat: delete python ghidra script I never updated it anyway
feat: added a lot more of regression test
feat: added a lot of logs to help debug on runtime
fix: fix wrong syscall ID on runtime
* feat: small fixes on code gen
* feat: added code gen test
* feat: rename IOP
* fix: fix special case on JR
feat: added code generator test
* feat: ps2 logs now need special macros
* feat: a lot of regressions test
feat: use test to fix bugs on runtime
fix: fix incorrect instructions on code generator
feat: added missing decode on r5900 decoder
feat: added scissor on rasterizer
* feat: better ghidra plugin analyzer
fix: fix real bug on function finding on elf analyzer
* feat: some logs on GS
feat: added more syscalls stubs
feat: added more ps2 stubs
* feat: added missing stub
* feat: basic gs
feat: basic rasterizer
fix: a lot of fixes to runtime stubs
feat: basic vif intercepter
feat: return "ok" for some stubs
feat: disassembly code as comment
fix: fix code gen instructions set
fix: again jump
feat: remove unused macro
fix: fix some problematic macros
feat: track delayslots on runtime
and many more
* feat: added missing files
* fix: fix instruction test
* fix: MULT/MULTU now write rd in addition to HI/LO (R5900 extension)
* fix: EI/DI instructions now toggle COP0 Status bit 16 (EIE) instead of bit 0 (IE)
* feat: split runtime code in small files to be easy to develop
* feat: split stubs in inl files
* feat: function auto link function treat functions with underscore as same as without underscore
* feat: remove underscore prefix from stubs
* feat: thread and flags refactor
* feat: propagate request stop
feat: some elf validation on runtime
* feat: remove Z7 compiler options
feat: added a literal float case error on vu
* fix: fix critical recompiler error on marking pc calls
* feat: better system interrupt
refactor: small refactor on thread system
* feat: stubs implements for resident evil code veronica
* feat: merge fileio
* feat: stub by address
* feat: codegen now auto-routes J/JAL callssites with known relocation symbols to syscalls/stubs
* feat: split runtime code in small files to be easy to develop
* feat: split stubs in inl files
* feat: function auto link function treat functions with underscore as same as without underscore
* feat: remove underscore prefix from stubs
* feat: thread and flags refactor
* feat: propagate request stop
feat: some elf validation on runtime
* feat: remove Z7 compiler options
feat: added a literal float case error on vu
* fix: fix critical recompiler error on marking pc calls
* feat: better system interrupt
refactor: small refactor on thread system
* feat: stubs implements for resident evil code veronica
* feat: merge fileio
* feat: split runtime code in small files to be easy to develop
* feat: split stubs in inl files
* feat: function auto link function treat functions with underscore as same as without underscore
* feat: remove underscore prefix from stubs
* fix: added missing header include for gcc
* fix: small thread fix on syscalls
fix: fix incorrect VU translations (they was using wrong register)
* feat: added authoritative system for function extraction, this will prevent functions overlap when we have debug symbols
* Add missing VU0 Special1 macro translations
* Fix VU0 macro decode and field ops
Align Special2 decoding with fhi_flo, implement VCLIPw/VABS, and fix field variants (VADDx/VSUBx/VMULx). Keep C++17 compatibility by replacing unordered_set::contains and remove dead ADDIU return. Update Special2 metadata for VWAITQ.
* vu0: complete macro mappings and add coverage test
* review: clean up vu macro handling
* fix: restore C++20 contains in code generator
* fix: correct VU0 Special2 instruction encoding in decoder test
---------
Co-authored-by: Antonio Guastella <antonioguastella@energine.it>
Co-authored-by: Ranieri <ran-junior@hotmail.com>
fix: patching NOP things that code gen already know how to handle
feat: added a bug on JAL/J/JAR code gen
feat: enhanced tom file
fix: fix memory layout for ps2 macros
feat: added a lot of not working garbabe to runtime (fix later)
feat: some code organization
feat: added new tests
feat: update readme
* feat: added thread naming functionality
feat: improve function name sanitization
* fix: fix decode jump target
feat: better word read
feat: prevent unexpect path on output tom
feat: analyzeEntryPoint now lookup for correct entry insted of rely on names
fix: fix CFG graph
feat: mangled name are not handle and sysfunctions anymore
feat: heavy loop flag count is not 5 from 3
* fix: skip/stubs now under [general]
fix: patch address now saves as true hex insted of decimal with 0x
fix: fix J/JAL reconstruction (PC+4)
feat: better C++ identifier sanitization
feat: decoder now dont stop the execution anymore just keep going
* refactor: update function name checks to use contains method
* refactor: update code generation to use static_cast
* refactor: made member methods const
* refactor: made range-based loop
* refactor: make one variable constructor explicit
* refactor: remove redundant else
* refactor: turn includes to forward declarations
* refactor: brace placements turned into allman style
* refactor: structed binding for readability and clarity, used emplace_back to prevent extra-copied object
* fix: add dwarf_private.h include
* fix: update GPR_U32 and GPR_S32 macros to use _mm_extract_epi32 for SSE/AVX intrinsics
* refactor: update function name checks to use contains method
* refactor: update code generation to use static_cast
* refactor: made member methods const
* refactor: made range-based loop
* refactor: make one variable constructor explicit
* refactor: remove redundant else
* refactor: turn includes to forward declarations
* refactor: brace placements turned into allman style
* refactor: structed binding for readability and clarity, used emplace_back to prevent extra-copied object
* refactor: update function name checks to use contains method
* refactor: update code generation to use static_cast
* refactor: made member methods const
* refactor: made range-based loop
* refactor: make one variable constructor explicit
* refactor: remove redundant else
* refactor: turn includes to forward declarations
* refactor: brace placements turned into allman style