Editing PRX

Jump to navigation Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

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:
= Overview =
=Overview=
'''S'''igned '''P'''PU '''R'''elocatable E'''x'''ecutable (SPRX)


'''P'''laystation '''R'''elocatable E'''x'''ecutable (PRX)
=Structure=
First LOAD segment p_paddr points to module info.
==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
|}


= PRX2 =
===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
|}


PRX2 is only present on PSVita. PSP and PS3 use PRX version 1.
===Imports===
{| class="wikitable"
! 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
|}


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


A PRX module is PRX2 format only if ehdr.e_type is ET_SCE_EXEC or ET_SCE_RELEXEC.


A Program Segment is PRX2 format only if p_type is PT_SCE_RELA or PT_SCE_COMMENT.


= Module Info =
= FNID generation =


PS3 and PSP PRX embed Module Info version 0.
== symbol name suffix ==
symbol_name_suffix: 6759659904250490566427499489741A


== Location ==
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'':
For PS3 (?and PSP?), it is located in text segment (first LOAD segment) at offset Elf32_Phdrs[text_seg_id].p_paddr - Elf32_Phdrs[text_seg_id].p_offset. Or more simply: at offset Elf32_Phdrs[text_seg_id].p_paddr in the ELF file.
  ''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'''.
== Structure ==
 
<source lang="C">
#define MODULE_NAME_MAX_LEN 27
 
typedef struct sceModuleInfo_common { // size is 0x20
   unsigned short modattr;
  unsigned char modver[2];
  char modname[MODULE_NAME_MAX_LEN];
  unsigned char infover;
} sceModuleInfo_common;
 
typedef struct sceModuleInfo_v0 { // size is 0x34
  sceModuleInfo_common c;
  Elf32_Addr gp_value;
  Elf32_Addr libent_top;
  Elf32_Addr libent_btm;
  Elf32_Addr libstub_top;
  Elf32_Addr libstub_btm;
} sceModuleInfo_v0;
</source>
 
= Exports =
 
PS3 uses exports structure of size 0x1C ?or 0x28 in 64bits?.
 
<source lang="C">
typedef struct _scelibent_common { // size is 0x10
unsigned char size;
unsigned char auxattribute;
unsigned short version;
unsigned short attribute;
unsigned short nfunc;
unsigned short nvar;
unsigned short ntls;
unsigned char hashinfo;
unsigned char hashinfotls;
unsigned char reserved;
unsigned char nidaltsets;
} sceKernelLibraryEntryTable_common;
 
typedef struct _scelibent_1C { // size is 0x1C
sceKernelLibraryEntryTable_common c;
Elf32_Addr libname;
Elf32_Addr nid_table;
Elf32_Addr entry_table;
} sceKernelLibraryEntryTable_1C;
</source>
 
= Imports =
 
PS3 use imports structures of size 0x2C.
 
<source lang="C">
typedef struct _scelibstub_common { // size is 0xC
unsigned short size;
unsigned short version;
unsigned short attribute;
unsigned short nfunc;
unsigned short nvar;
unsigned short ntls;
} sceKernelLibraryStubTable_common;
 
typedef struct _scelibstub_2C { // size is 0x2C
sceKernelLibraryStubTable_common c;
unsigned char reserved[4];
Elf32_Addr libname;
Elf32_Addr func_nid_table;
Elf32_Addr func_entry_table;
Elf32_Addr var_nid_table;
Elf32_Addr var_entry_table;
Elf32_Addr tls_nid_table;
Elf32_Addr tls_entry_table;
} sceKernelLibraryStubTable_2C;
</source>
 
= Relocations =
 
== PS3 ==
 
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 PRXs but it is currently unknown what it is used for.


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') = '''1630f4d7'''0bf3df419db9d481983411fd3130482a = '''0xD7F43016'''


{{File Formats}}
{{File Formats}}
<noinclude>[[Category:Main]]</noinclude>
<noinclude>[[Category:Main]]</noinclude>
Please note that all contributions to PS3 Developer wiki are considered to be released under the GNU Free Documentation License 1.2 (see PS3 Developer wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following hCaptcha:

Cancel Editing help (opens in new window)