Editing PRX
Jump to navigation
Jump to search
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
[[Category:Software]] | |||
SPRX stands for Signed PPU Relocatable Executable. | |||
First LOAD segment, paddr points to the descriptor for the "dependency table" or "deptable" for short: | |||
NOTE: All addresses inside the file assume the ELF header isn't there (basically add 0xE0 to all addresses.)(ELF64 header size is 0x40, no?) | |||
Module Info: | |||
{| class="wikitable" | |||
! Offset | |||
! Type | |||
! Description | |||
|- | |||
| +0 | |||
| short | |||
| Module attributes | |||
|- | |||
| +2 | |||
| char[2] | |||
| Module version | |||
|- | |||
| +4 | |||
| char[28] | |||
| Module name | |||
|- | |||
| +32 | |||
| long | |||
| TOC address | |||
|- | |||
| +36 | |||
| long | |||
| Pointer to the start of exports section | |||
|- | |||
| +40 | |||
| long | |||
| Pointer to end of exports section | |||
|- | |||
| +44 | |||
| long | |||
| Points to the start of imports section | |||
|- | |||
| +48 | |||
| long | |||
| Points to the end of imports section | |||
|} | |||
= | Exports: | ||
{| class="wikitable" | |||
! Offset | |||
! Type | |||
! Description | |||
|- | |||
| +0 | |||
| char[2] | |||
| Structure size (0x1C 32-bit or 0x28 64-bit), padding | |||
|- | |||
| +2 | |||
| short | |||
| Version | |||
|- | |||
| +4 | |||
| short | |||
| Attributes | |||
|- | |||
| +6 | |||
| short | |||
| Number of functions | |||
|- | |||
| +8 | |||
| short | |||
| Number of variables | |||
|- | |||
| +10 | |||
| short | |||
| Number of thread local storage variables | |||
|- | |||
| +12 | |||
| char | |||
| Hash info | |||
|- | |||
| +13 | |||
| char | |||
| Thread local storage hash info | |||
|- | |||
| +14 | |||
| char[2] | |||
| Reserved | |||
|- | |||
| +16 | |||
| long | |||
| Pointer to exported library name | |||
|- | |||
| +20 | |||
| long | |||
| Pointer to function NID table | |||
|- | |||
| +24 | |||
| long | |||
| Pointer to function stub table | |||
|} | |||
Imports: | |||
{| class="wikitable" | |||
! Offset | |||
! Type | |||
! Description | |||
|- | |||
| +0 | |||
| char | |||
| Structure size (0x2C) | |||
|- | |||
| +1 | |||
| char | |||
| Unused | |||
|- | |||
| +2 | |||
| short | |||
| Version | |||
|- | |||
| +4 | |||
| short | |||
| Attributes. 0x1 is always set, 0x8 often, 0x2000 seems to indicate a non-PRX library (like "stdc" or "allocator") that comes from somewhere else (LV2?) | |||
|- | |||
| +6 | |||
| short | |||
| The number of functions the depending PRX needs from the depended PRX. There is this many function pointers in the stubtable (see below) for this PRX. Most of the time, there's also this many entries in the Mystery Table for that PRX. But not always? "allocator" in particular seems to get strange stuff. | |||
|- | |||
| +8 | |||
| short | |||
| Number of variables | |||
|- | |||
| +10 | |||
| short | |||
| Number of thread local storage variables | |||
|- | |||
| +12 | |||
| byte[4] | |||
| reserved | |||
|- | |||
| +16 | |||
| long | |||
| Pointer to the ASCII string of the depended PRX's name. These don't seem to consistently map with the PRX's file name in dev_flash. | |||
|- | |||
| +20 | |||
| long | |||
| Pointer to this library's entries in the mystery table. | |||
|- | |||
| +24 | |||
| long | |||
| Pointer to the the pointers to function wrappers for this library in the wrapper list. | |||
|- | |||
| +28 | |||
| long | |||
| ver_nid_table | |||
|- | |||
| +32 | |||
| long | |||
| ver_entry_table | |||
|- | |||
| +36 | |||
| long | |||
| tls_nid_table | |||
|- | |||
| +40 | |||
| long | |||
| tls_entry_table | |||
|} | |||
Second LOAD segment is all the relocation and symbol data, save for the names (as ASCII strings) of the exposed functions (which are in the first LOAD segment along with all the other strings the PRX uses). | |||
At the start of this section is the wrapper list, just a flat array of pointers to subroutines that appear to be wrappers for calling functions in other PRXes. This combined with the deptable maps those wrappers to PRXes. | |||
At EOF-20 is a pointer to the start of the funcpointer table. After 0xFFFFFFFF and a handful of pointers into itself, it goes into a list of pointers to subroutines (as longs) each followed by a long containing the unique ID from the deptable descriptor. | |||
Table number two: All longs(?) The very first is a pointer to the very start of the funcpointer table. | |||
There is a table that's a listing of the functions exposed to apps/other PRXes. This table is usually referenced by a function; how exactly it is reached remains to be seen. | |||
{| class="wikitable" | |||
! Offset | |||
! Type | |||
! Description | |||
|- | |||
| +12n | |||
| long | |||
| Pointer to the ASCII string name of this function | |||
|- | |||
| +12n +4 | |||
| long | |||
| Pointer to this function's entry in the funcpointer table. | |||
|- | |||
| +12n +8 | |||
| long | |||
| Always(?) zero. | |||
|} | |||
= | = FNID generation = | ||
==== symbol name suffix ==== | |||
symbol_name_suffix: 6759659904250490566427499489741A | |||
To calculate FNID value of exported/imported symbol from .PRX you need to take SHA-1 hash over concatenation of symbol's name and symbol_name_suffix and then grab first 4 bytes from it and reverse these bytes (because of little-endian). | |||
Let's take, for example, ''_sys_sprintf'': | |||
''SHA1''('_sys_sprintf' + '\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A') = '''FEEAF9A1'''23D7D1A7619B40CD52500F9735A852A4 | |||
''FNID''('_sys_sprintf') = ''swap_uint32''('''0xFEEAF9A1''') = '''0xA1F9EAFE'''. | |||
For C++ functions you should use mangled representation of symbol's name. | |||
For example, mangled name of ''std::runtime_error::what() const'' is ''_ZNKSt13runtime_error4whatEv'' and FNID('_ZNKSt13runtime_error4whatEv') = '''0x5333BDC9'''. | |||
More complex example: | |||
FNID(mangle('std::basic_filebuf<wchar_t, std::char_traits<wchar_t> >::seekpos(std::fpos<std:: | |||
_Mbstatet>, std::_Iosb<int>::_Openmode)')) = FNID('_ZNSt13basic_filebufIwSt11char_traitsIwEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE') = '''0xB6A4D760''' | |||