Repository navigation
fix(relinker): treat address-taken code as reachable in unused-filter=1 - #2332
Conversation
|
Tested on Linux (CachyOS x86_64, Intel RPL-S iGPU / Mesa 26.3.0-devel / Vulkan 1.4.363, GCC 16.2.1) at
LGTM! |
|
Please rebase onto main: #2238 landed and conflicts in |
adriadam10
left a comment
There was a problem hiding this comment.
Thanks, the DOOM measurement is convincing. This needs a rebase onto main after #2238, and the conflict in ControlFlowGraph.cpp is not mechanical, so it should be resolved by you:
BuildControlFlowGraphonmainnow takesbool followCodeAddresses(REX.Wlearip-relative → enqueue the target). This PR replaces that same parameter withconst std::vector<StrictDataRegion>* dataand handles the sameleawithtakeAddressplus jump-table targets. Please unify them: either keep one parameter that covers both cases or keep both explicitly, and make sure theleatarget is not enqueued twice with different rules (#2238's callers must keep their behaviour; its tests must still pass).core/relinker/CMakeLists.txt: keep bothentry_point_boundsandunused_filter_indirectadd_testentries.- Heads-up: since #2238, LEA-rooted targets can reach CPU-dispatched XOP code (see #2559); worth checking the new roots don't hit that on the catalog titles.
After the rebase please rerun unused_filter_indirect and tls_function_coverage.
|
Additional platform validation on standalone PR head Windows: passed — Windows 11, supported WinLibs GCC 15.2.0 UCRT/POSIX/SEH r7; CMake 4.3.1 / Ninja. Release / All 41 registered relinker tests passed ( Integration limitation: a local merge against main |
4ea9f97 to
814fcc4
Compare
|
Rebased onto
|
|
Checked
Not checked here: the catalog conversions and the XOP question from the review (no titles on this machine), and nothing ran in a game. AI-assisted: yes (Claude Code). Edited: removed the ctest pass count, which this PR's relinker CI job already reports. |
814fcc4 to
a781718
Compare
adriadam10
left a comment
There was a problem hiding this comment.
Rebased onto current main (one conflict in core/relinker/CMakeLists.txt after #2119: kept both to_rosetta and unused_filter_indirect). Relinker-scoped build and ctest: 91/91 pass. unused_filter_indirect fails with the non-test changes reverted. Merging on green CI.
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.
|
Rebased onto current |
a781718 to
cfd61a5
Compare
What
At
unused-filter=1the CFG followed only direct branches andcall/jmp [rip+slot]through RELATIVE-relocated slots. Code reached through a register (lea reg, [rip+f]; call reg, vtables and callback tables, switch jump tables) was unreachable, and imports used only there were removed. GOT accesses were counted only formovloads andcall/jmp [rip+slot].The CFG now also walks RELATIVE relocation targets in text, RIP-relative
leatargets, and int32 jump tables at alea'd data address, using the strict filter's walk moved toReadRelativeTableTargets. Any RIP-relative operand that names a GOT slot counts as an access. Address-taken targets are walked after the direct control flow. A target that does not decode is not code and ends that path, so a stray table entry cannot abort the conversion. Strict filter behaviour is unchanged.Absolute immediates (
mov r, imm,push imm) and raw data words pointing into text are still not roots at level 1.Changes the same files as #2238 (LEA roots for the Windows TLS collector) and #2304 (CFG decoding performance), with a different scope.
Tested
macOS arm64, relinker-only Release build: ctest 39/39,
strict_nid_filterunchanged.test_unused_filter_indirect.pycovers lea + call reg, a RELATIVE pointer called through a register, a jump-table case block, GOT access by lea/push/cmp, two unreachable controls, and two address-taken targets on undecodable bytes. On main the six indirect cases reportCFG/GOT filtering: 1 -> 0. No title was converted from a retail dump.Linux (Ubuntu 24.04, GCC 13.3), relinker-only Release build: ctest 44/44.
Also converted 43 open-source titles from the PS5 homebrew catalog (eboot.bin and bundled libc.prx, unwrapped from fSELF) with main and with this branch, for Linux and Windows at unused-filter 0, 1 and 2. No conversion changed outcome. At unused-filter=1, all 38 titles that convert keep more imports, 1 to 283 each (5,812 in total), on both outputs; none keeps fewer.
Runtime check on Linux (Ryzen 9 9950X, RTX 3090, NVIDIA 595.99.02) with DOOM PPSA99666 v1.1.1 from the catalog. Both trees relink it with
--registry unused-filter=1and run the title's owntest/console-play.cfgwithout itsserveline: it startsdoom1.wad, plays and exits at frame 900. Both trees carry #1529, without which the bundledlibc.prxshim takes DOOM's libc imports on Linux (#1497); this PR does not depend on it.maind70b899 + #1529HU_Init, before the first frame (2 of 2 runs)On
mainthe crash is a call to address 0 in the audio thread. Its start routine is referenced only by theleathat passes it topthread_create, so level 1 dropssceAudioOutOutput, which the thread loads withmov <GOT>, %r14and calls through%r14. The other 59 dropped imports include ones used by the download worker and upload server threads (sceHttp*,accept), the on-screen keyboard (sceImeDialog*) and music (log10). At levels 0 and 2 both trees produce the same executable. #2238 and #2304, built the same way, produce a level-1 executable byte-identical tomain's.ScreenTester5 PPSA69420 on
mainand Yamagi Quake II PPSA99007 with #2330, both at level 1, stop on a call through the removed GOT slot ofpthread_key_create. This branch keeps that slot. Both titles then keep imports that AnyPS5 does not implement yet and stop at load instead: ScreenTester5 withundefined symbol: MhC53TKmjVA(sysctlbyname); for Quake II the import audit lists 20.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)