PRX
Overview
Signed PPU Relocatable Executable (SPRX)
Structure
First LOAD segment p_paddr points to module info.
Module Info
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
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
Offset | Type | Description |
---|---|---|
+0 | char | Structure size (0x2C) |
+1 | char | Unused |
+2 | short | Version |
+4 | short | Attributes. AUTO_EXPORT=0x0001, WEAK_EXPORT=0x0002, NOLINK_EXPORT=0x0004, WEAK_IMPORT=0x0008, 0x2000 seems to indicate a non-PRX library (like "stdc" or "allocator") that comes from somewhere else (LV2?) |
+6 | short | Number of functions |
+8 | short | Number of variables |
+10 | short | Number of thread local storage variables |
+12 | byte[4] | reserved |
+16 | long | Pointer to imported library name. |
+20 | long | Pointer to the list of NID's for the exported functions. |
+24 | long | Pointer to the list of exported functions. |
+28 | long | var_nid_table |
+32 | long | var_entry_table |
+36 | long | tls_nid_table |
+40 | long | tls_entry_table |
Relocations
Relocations can be found in either PT_SCE_PPURELA segments or SHT_SCE_PPURELA / SHT_RELA sections. RELA relocations are standard relocations while PPURELA relocations have 2 segment (program header) indexes stored in r_sym of r_info.
- The first index can be extracted with 0x7FFFFF00 as a mask and is used as a base address for r_addend. This sum will be the value applied to the patch.
- The second index can be extracted with 0x000000FF as a mask and is used as a base address for the target segment to patch and is added to r_offset.
- The first bit (0x80000000) is also set on earlier PRX's but it is currently unknown what it is used for.
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') = FEEAF9A123D7D1A7619B40CD52500F9735A852A4 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
noname_nid_suffix: 0xbc5eba9e042504905b64274994d9c41f
For import stub's with no names, you must use SHA1 over concatenation of symbol's name and noname_nid_suffix as an ascii string. Some examples of noname imports are module_start, module_info, and module_stop.
SHA1('module_info' + '0xbc5eba9e042504905b64274994d9c41f') = 1630f4d70bf3df419db9d481983411fd3130482a = 0xD7F43016
|