PRX: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
 
(7 intermediate revisions by the same user not shown)
Line 5: Line 5:
= PRX2 =
= PRX2 =


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


A PRX module is PRX2 format only if ehdr.e_type is ET_SCE_EXEC or ET_SCE_RELEXEC.
A PRX module is PRX2 format only if ehdr.e_type is ET_SCE_EXEC or ET_SCE_RELEXEC.
Line 11: Line 13:
A Program Segment is PRX2 format only if p_type is PT_SCE_RELA or PT_SCE_COMMENT.
A Program Segment is PRX2 format only if p_type is PT_SCE_RELA or PT_SCE_COMMENT.


= Relocations =
= Module Info =
 
PS3 and PSP PRX embed Module Info version 0.
 
== Location ==
 
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 ==
 
<source lang="C">
#define MODULE_NAME_MAX_LEN 27


== PS3 ==
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;


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.
typedef struct sceModuleInfo_v0 { // size is 0x34
*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.
  sceModuleInfo_common c;
*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.
  Elf32_Addr gp_value;
*The first bit (0x80000000) is also set on earlier PRXs but it is currently unknown what it is used for.
  Elf32_Addr libent_top;
  Elf32_Addr libent_btm;
  Elf32_Addr libstub_top;
  Elf32_Addr libstub_btm;
} sceModuleInfo_v0;
</source>


=== PT_SCE_PPURELA Segment ===
= Exports =


It seems to be just a big table with following entries:
PS3 uses exports structure of size 0x1C ?or 0x28 in 64bits?.


<source lang="C">
<source lang="C">
struct {
typedef struct _scelibent_common { // size is 0x10
    u64 offset; // Offset in the second LOAD segment
unsigned char size;
    u16 unk0;   // ???
unsigned char auxattribute;
    u8  index; // Seems that: 0 -> First LOAD segment, 1 -> Second LOAD segment
unsigned short version;
    u8  type;   // ??? Not sure what happens when type != 1.
unsigned short attribute;
    u32 unk1;   // ???
unsigned short nfunc;
    u64 ptr;   // Offset of the pointer (while patching add the base address where the segment was allocated).
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>
</source>


My guess is that this segment is used to patch the addresses of the second LOAD segments like this (this may be wrong, but so far it has been proven to work for my emulator's dynamic loader):
= Imports =
 
PS3 use imports structures of size 0x2C.


<source lang="C">
<source lang="C">
for (auto& rel : ppurela_table) {
typedef struct _scelibstub_common { // size is 0xC
    if (rel.type == 1) {
unsigned short size;
        const u32 addr = prx->load_segments[1].addr + rel.offset;
unsigned short version;
        const u32 value = prx->load_segments[rel.index].addr + rel.ptr;
unsigned short attribute;
        write32(addr, value);
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>
</source>


Has anyone worked on this previously? / Can someone confirm this? -- [[User:AlexAltea|AlexAltea]]
= 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}}
{{File Formats}}
<noinclude>[[Category:Main]]</noinclude>
<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.