PRX: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
m (added some sections to make an index appear at top)
 
(19 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category:Software]]
= Overview =
=Overview=
'''S'''igned '''P'''PU '''R'''elocatable E'''x'''ecutable (SPRX)


=Structure=
'''P'''laystation '''R'''elocatable E'''x'''ecutable (PRX)


==First LOAD segment==
= PRX2 =
paddr points to the descriptor for the "dependency table" or "deptable" for short:


*Notes:
PRX2 is only present on PSVita. PSP and PS3 use PRX version 1.
**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===
== Recognition ==
{| 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===
A PRX module is PRX2 format only if ehdr.e_type is ET_SCE_EXEC or ET_SCE_RELEXEC.
{| 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===
A Program Segment is PRX2 format only if p_type is PT_SCE_RELA or PT_SCE_COMMENT.
{| 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==
= Module Info =
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.
PS3 and PSP PRX embed Module Info version 0.


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


Table number two: All longs(?) The very first is a pointer to the very start of the funcpointer table.
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.


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.
== Structure ==
{| 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 =
<source lang="C">
#define MODULE_NAME_MAX_LEN 27


== symbol name suffix ==
typedef struct sceModuleInfo_common { // size is 0x20
symbol_name_suffix: 6759659904250490566427499489741A
  unsigned short modattr;
  unsigned char modver[2];
  char modname[MODULE_NAME_MAX_LEN];
  unsigned char infover;
} sceModuleInfo_common;


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).
typedef struct sceModuleInfo_v0 { // size is 0x34
Let's take, for example, ''_sys_sprintf'':
  sceModuleInfo_common c;
   ''SHA1''('_sys_sprintf' + '\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A') = '''FEEAF9A1'''23D7D1A7619B40CD52500F9735A852A4
  Elf32_Addr gp_value;
   ''FNID''('_sys_sprintf') = ''swap_uint32''('''0xFEEAF9A1''') = '''0xA1F9EAFE'''.
   Elf32_Addr libent_top;
   Elf32_Addr libent_btm;
  Elf32_Addr libstub_top;
  Elf32_Addr libstub_btm;
} sceModuleInfo_v0;
</source>


For C++ functions you should use mangled representation of symbol's name.
= Exports =
For example, mangled name of ''std::runtime_error::what() const'' is ''_ZNKSt13runtime_error4whatEv'' and FNID('_ZNKSt13runtime_error4whatEv') = '''0x5333BDC9'''.
 
More complex example:
PS3 uses exports structure of size 0x1C ?or 0x28 in 64bits?.
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'''
<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.
 
 
 
{{File Formats}}
<noinclude>[[Category:Main]]</noinclude>

Latest revision as of 22:05, 19 January 2020

Overview[edit | edit source]

Playstation Relocatable Executable (PRX)

PRX2[edit | edit source]

PRX2 is only present on PSVita. PSP and PS3 use PRX version 1.

Recognition[edit | edit source]

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[edit | edit source]

PS3 and PSP PRX embed Module Info version 0.

Location[edit | edit source]

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.

Structure[edit | edit source]

#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;

Exports[edit | edit source]

PS3 uses exports structure of size 0x1C ?or 0x28 in 64bits?.

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;

Imports[edit | edit source]

PS3 use imports structures of size 0x2C.

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;

Relocations[edit | edit source]

PS3[edit | edit source]

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.