Repository navigation
feat(libs): implement C runtime re-exports for libSceAmpr - #545
Conversation
Progress report (5c4bc7d → af9dfbf)📈 System libraries: 85.55% (+0.11%, +24 implemented functions) ✅ 24 implemented
|
|
Thanks. This one carries #407's commit, so it can only go in after #407 (or split from it). I also compared the twelve functions with Sony's own CRT: the libc.prx that PPSA21564 ships exports all twelve of these NIDs, and several behave differently from this PR:
These are libc exports. If the title's import table really names libSceAmpr for them, could you check that, and implement them once where both libraries can share them instead of keeping a second copy here? Unrelated to the CRT part, #407 exports T4ucGB8CsnM and 5tRaBjtdTzY from libSceWebBrowserDialog, but they are |
7404b37 to
c37c46f
Compare
|
Reworked per review (rebased onto the new #407, so this is now Ampr-only on top of it; forced update after the rebase): checked all twelve NIDs against the Deathloop ELF — each is imported only from libSceAmpr (IMPORT_LIB 48 / NEEDED 43), so Ampr keeps the exports. The implementations now live once in tools-visible SonyCrt.hpp, compiled into both libc (as real-name exports) and libSceAmpr (as sceAmpr forwarders), which also avoids cross-module calls for the same NID. All seven correctness items addressed: Dinkumware __fpclassifyd codes, C FLT_ROUNDS mapping via fegetround, two-argument _Sinh, Sony lconv layout with decimal_point at 0x48, 16-bit wcscpy_s/mbstowcs with constraint-handler invocation, locked handler with aborting default installed on NULL, and __udivti3 throwing on a zero divisor. New guest_crt test covers all twelve through the Ampr interface (udivti3 values plus the throw, handler counting, layout offset, formats). Notes: the test links libc for __gxx_personality_v0 and uses configure_windows_unwind like the other guest tests (a -fasynchronous-unwind-tables variant broke unwinding with our personality); udivti3 is exercised through the shared header because cross-prx __int128 calls from a MinGW caller come back garbled. 184/184 ctest green locally. |
|
Rebased onto current main (this should also restart CI, which never ran for the previous push): kept both sides where main added code around this PR's areas, and dropped my two Http throwing stubs whose NIDs #555 now implements for real. Full ctest (222) passes locally. |
d4e5819 to
a0b2683
Compare
27e0cc4 to
5570341
Compare
|
Thanks, this covers all seven points: the Dinkumware Two small, optional points:
This carries #407's commits, so it inherits the Linux CI failure I described on #407 (eight libSceAmpr names that interpose libstdc++). |
|
This carries #407's fd3b24e, so the libstdc++ interposition is fixed here too. The Linux CI job, which failed on the previous head, is green now. Since #338 landed, two files conflict with main:
Your own commit is the same as the one I looked at last time (only the |
5570341 to
2a3a2a7
Compare
|
Rebased onto the new #407 (fork/feat/deathloop-loading @ 993ccfa). Git auto-skipped the #407 commits; I skipped the remaining redundant 4231855 (already superseded by fae345a + _nid_postfix fix) and replayed only our own commit as 2a3a2a7. TechnicalDebt.md: kept main/#338 lines first (Http/Http2/Net/SessionSignaling/Trophy/SystemService/Voice + snwprintf_s + Ult queues), then our 3 CRT lines (localeconv, set_constraint_handler_s, __udivti3) after them, before the kernel UnknownNN lines. RuntimeSupport.cpp: auto-merged cleanly - kept upstream state plus our __udivti3_nid_postfix (SonyUdivti3); snwprintf_s stays in FormattingWide.cpp as _nid_postfix, so both functions are preserved. libSceAmpr/Export.cpp: kept both sides - upstream _nid_postfix runtime renames plus our 12 sceAmprXxx forwarders calling SonyXxx with SonyCrt.hpp include; no cross-prx _nid_postfix calls, no externs. Optional points (ctime_s/asctime_s constraint handler, mbstowcs TechnicalDebt line) left out as agreed. Ready after #407. |
|
Rebased onto the new #407 (998016e, itself rebased for the #676/#369/TD points; forced update 2a3a2a7...0647694). Rebase --onto old #407 base, so only our own commit replayed — no stale #407 commits carried. Resolution keeps both sides everywhere: TechnicalDebt.md has main's lines, then our 3 CRT lines (localeconv, set_constraint_handler_s, __udivti3), then #407's kernel lines. RuntimeSupport.cpp only adds the SonyCrt.hpp include + __udivti3_nid_postfix (snwprintf_s untouched upstream in FormattingWide.cpp). Ampr keeps upstream _nid_postfix renames plus our 12 sceAmprXxx forwarders calling SonyXxx, no cross-prx _nid_postfix calls. #676: nothing to drop here — the libSceNpCppWebApi replacement lived in #407's commits, which are gone from this branch after the --onto; diff vs new #407 is Ampr/SonyCrt/libc-wrappers/GuestCrt test/TD only. Optional points left out as agreed. Ready after #407. |
adriadam10
left a comment
There was a problem hiding this comment.
Thanks for the rework; the semantics were already covered by Dean's review. What blocks it now is a conflict with main that needs a logic change:
core/libs/prx/libc/src/Time.cpp: main now converts to the guest's 56-byteGuestTm(GuestTime.hpp,toHostTm, TZ init).asctime_s_nid_postfix(Time.cpp:127) andsceAmprAsctimeStake a hoststd::tm*, which is 36 bytes on Windows and does not match the guest layout. Takeconst GuestTm*and convert withtoHostTmbefore formatting.SonyCtimeS(SonyCrt.hpp:73) callsstd::localtimedirectly, bypassing the guest TZ handlinglocaltime_shas on main. Reuse the same path aslibc_localtime, and take the time asconst int64_t*like the other time functions.core/libs/prx/libc/src/Strings.cpp: conflict at the end of the file, keep main's lines and addstrtok_s_nid_postfixafter them.core/libs/tests/GuestCrt.cpp:59-68callsSonyUdivti3directly; test it through thesceAmprexport and the libc one so the registered exports are covered. Add anasctime_scase with aGuestTmof the guest layout.- The PR description is out of date: it says divide-by-zero yields 0 (the code throws) and mentions only Ampr, while the diff also adds libc exports. Please update What.
Please rebase on current main and rerun guest_crt.
|
For priority: on
Each line is |
|
A data point for
Compared with the TechnicalDebt line here ("seven null pointers ... the int_p/int_n tail fields are left zero and the rest follows the host layout"), three things differ:
The four catalog titles @babyhuey listed import I have a branch with just this struct, a |
PPSA99902 original caller ABI evidence (2026-10-11, c34f5b08)I checked this PR's actual libc implementation at head Target: PPSA99902 Sonic Unleashed Recompiled 01.003.000, original ELF SHA-256
Verification: current original SHA checked, independent ELF header/PT_LOAD parsing and original unwind FDE/CIE boundaries for all 5/5 callers; Capstone and GNU objdump agree on every instruction's bytes in all five bounded functions. Ghidra 12.1.4 read-only recheck matches all 5/5 full PT_LOAD byte hashes and 5/5 import references. Its existing analysis has no functions/instructions at these sites, so failed decompiler queries are not used as supporting evidence; no project mutation or inferred type is used to corroborate the layout. This supports #3245's FreeBSD-style decimal offset 0 for this title. It does not establish all 24 field semantics or one universal PS5 ABI. Several callers tolerate a null decimal pointer, so I am not claiming a measured crash from your layout; the 96-byte copy and non-null locale result still need a compatible prefix. Please keep the differing layout evidence explicit when this work is carried. I have not built or run #545 itself. Independent #3245 adaptation/tests: fork commit Merged Sony CRT retained in fresh startup validation (2026-10-11,main0f863)The earlier head0647694a null-prefix observation is historical. Current main0f863 retains the corrected 0x90-byte SonyLconv, seven monetary pointers to non-null empty strings,14CHAR_MAX chars, decimal pointer at0x48 and Dinkumware tail. This aligns with adriadam10's reported Astro's Playroom library observation; I did not independently measure that console library. Compiled the unchanged current SonyLocaleconv helper in a standalone Windows source probe5times: sizeof=144,decimal offset=72,prefix-first-byte=0,decimal-first-byte=46,prefix-empty=true. Upstream guest_crt passes5repeats, also in the full835-test integration, and5repeats afterward. This confirms current implementation/test behavior, not PS5 equivalence. Our refreshed integrationd8fd7c7 keeps this merged layout and omits our old FreeBSD locale override. With validated math/kernel prerequisites it enters PPSA99902 guest and hits the color guard; changing only the D64 driver advances to the existing MSAA descriptor refusal5/5. Controlled details. Thus this Sony implementation does not prevent the observed startup, and the earlier locale override is not established as necessary on this newer stack. The original ELF caller evidence remains: known libSceLibcInternal localeconv consumers load result+0 as a decimal string or copy96bytes. With today's helper, result+0 points to an empty monetary string, not null; the earlier null-fallback reasoning therefore cannot be reused for this version. These differing guest assumptions need investigation; they do not justify globally replacing the Sony layout, supported by current source and the reported vendor observation, with FreeBSD's. They could involve guest/toolchain ABI assumptions. Actual invocation of these specific locale callers and resulting formatting behavior were not traced in the new replays. No uniform-PS5-ABI, measured locale crash or gameplay claim. AI-assisted validation/report: Codex. |
… per module Co-Authored-By: Claude <noreply@anthropic.com>
0647694 to
af9dfbf
Compare
adriadam10
left a comment
There was a problem hiding this comment.
Rebased on current main and fixed the points from the previous review on your branch (no push from you in 24 h):
Time.cpp/SonyCrt.hpp:asctime_stakesconst GuestTm*(no hoststd::tm);ctime_stakesconst int64_t*and goes throughlocaltime_s_nid_postfix, so it uses the guest time zone. Both exports (libc andsceAmpr*) shareSonyFormatAsctime.Strings.cpp/Math.cpp/Time.cpp: conflicts resolved, keeping main's lines plusstrtok_s_nid_postfix.localeconv: rewritten to the 0x90-byte Dinkumware layout read from thelibc.prxof Astro's Playroom (PPSA01325): empty monetary strings instead of null,CHAR_MAXin all 14charfields,decimal_pointat 0x48, thengrouping,thousands_sep,_Frac_grouping,_Frac_sep,_False,_True,_No,_Yes.static_asserts pin the size and offset. TechnicalDebt line updated.GuestCrt.cpp: also calls the libc exports (ctime_s,asctime_s,mbstowcs,strtok_s,__fpclassifyd,__udivti3,localeconv), addsGuestTmasctime cases (valid, bad weekday, null) and ctime buffer-size cases;Requireprints the failing line.- PR description updated (zero divisor throws; libc exports).
Checked: scoped build and ctest (164 tests) green, guest_crt passes; merging once CI is green.
- #3249 stays open: localeconv is on main since boykopovar/AnyPS5#545 (a4d5d3ce, merged 2026-10-11); the issue waits for a runtime check of the struct layout. New next step, #545 as related PR. - Cloud Play (PPSA99600): first stop on main is getservbyname (#3734, fix PR #3798, open), then sysctl MIB 1.37 (#3700) with #3798 applied. #3249 excluded. - vkQuake (PPSA99010): #3249 excluded; it exits cleanly for lack of game data on main 2ccbd376. - No stage added: the sources name stops, not a stage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
libSceAmpr and libc re-export part of the C runtime (statically linked CRT). 12 of the 36 unknown libSceAmpr NIDs are identified by NID hash (verified by recomputation) as standard C functions and implemented with real semantics instead of throwing stubs: localeconv (Sony's 0x90-byte Dinkumware struct), __udivti3 (manual 128-bit division, no libgcc dependency; a zero divisor throws), strtok_s, ctime_s, wcscpy_s, mbstowcs, asctime_s (takes the guest
GuestTm), __fpclassifyd (Dinkumware codes), _Sinh, _Fltrounds (CFLT_ROUNDSvalues), set_constraint_handler_s and ignore_handler_s. The semantics live once inSonyCrt.hppand are exported both by libc (real names) and libSceAmpr (sceAmpr*forwarders). This unblocks Deathloop past its first Ampr call (128-bit division during init).The remaining 24 (C++ runtime: _Pad, num_get/time_get facets, shared_ptr locks, _Thrd/_Cnd, vtables) keep throwing stubs for follow-ups.
Tested
Checklist