PRX: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
(Added more complex example for C++)
(better structure info)
Line 1: Line 1:
[[Category:Software]]
[[Category:Software]]
scetool can decrypt SPRX's, producing an ELF... or is it? Not really. It has an ELF header but...
SPRX stands for Signed PPU Relocatable Executable.  


First LOAD segment, paddr points to the descriptor for the "dependency table" or "deptable" for short:
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?)
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"
{| class="wikitable"
! Offset
! Offset
Line 11: Line 13:
|-
|-
| +0
| +0
| long
| short
| Always(?) 0x101
| Module attributes
|-
| +2
| char[2]
| Module version
|-
|-
| +4
| +4
| char[28]
| char[28]
| Name of this module, padded out with zeroes. Doesn't necessarily match the file name(why?)(it not matching the file name is the norm, why should it?)(Strange..for fw sprx I couldn't find anywhere near this the prx name, for Engine.BuildInfo_Ps3_Retail.sprx it's at 0x1FC(from the start))
| Module name
|-
|-
| +32
| +32
| long
| long
| A unique module ID? Gets used a lot later...
| TOC address
|-
|-
| +36
| +36
| long
| long
| Points to the deptable header
| Pointer to the start of exports section
|-
|-
| +40
| +40
| long
| long
| Points to the END of the deptable header
| Pointer to end of exports section
|-
|-
| +44
| +44
| long
| long
| Points to the start of first deptable entry
| Points to the start of imports section
|-
|-
| +48
| +48
| long
| long
| points to the end of the LAST deptable entry
| Points to the end of imports section
|}
|}


Line 46: Line 52:
|-
|-
| +0
| +0
| long[5]
| char[2]
| Always(?) 0x1C000000(entry size(0x1c)), 0x80000002(, 0x10000, 0, 0
| 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
| +20
| long
| long
| Points to three longs which are always(?) 0xBC9A0086, 0xAB779874, 0xD7F43016.... Export FNID's
| Pointer to function NID table
|-
|-
| +24
| +24
| long
| long
| Stubtable <br> Export FNID Functions. The first entry here corresponds to the function whose FNID is the first FNID table entry and so forth
| Pointer to function stub table
|}
|}


Line 65: Line 107:
|-
|-
| +0
| +0
| short[2]
| char
| Always(?) 0x2C00, 1
| Structure size (0x2C)
|-
| +1
| char
| Unused
|-
| +2
| short
| Version
|-
|-
| +4
| +4
| short
| short
| Flags? 0x1 is always set, 0x8 often, 0x2000 seems to indicate a non-PRX library (like "stdc" or "allocator") that comes from somewhere else (LV2?)
| 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
| +6
Line 78: Line 128:
| +8
| +8
| short
| short
| Usually 0, but "paf" gets sometimes 5, sometimes 6, sometimes 0. More flags maybe?
| Number of variables
|-
|-
| +10
| +10
| short[3]
| short
| Always(?) 0. Probably for alignment.
| Number of thread local storage variables
|-
| +12
| byte[4]
| reserved
|-
|-
| +16
| +16
Line 97: Line 151:
|-
|-
| +28
| +28
| long[2]
| long
| 0, 0 for every PRX except paf, which gets two more sets in the mystery table, pointed to by these, unless +8 is 0.
| ver_nid_table
|-
| +32
| long
| ver_entry_table
|-
| +36
| long
| tls_nid_table
|-
| +40
| long
| tls_entry_table
|}
|}



Revision as of 05:04, 27 November 2013

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:

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. 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.

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') = 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