ELF structures/sections

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
vvuk
Posts: 13
Joined: Mon Apr 25, 2005 3:57 pm
Location: Foster City, CA

ELF structures/sections

Post by vvuk »

On loading an ELF or PRX, the PSP's loader has the ability to dynamically link in other prx modules. There's a couple of structures that are relevant to this; this is what i've deduced so far. nem has much of this in the startup.s in the HelloPSP source zip.

Code: Select all

typedef struct {
    // 0, 0, 1, 1 ?
    unsigned char c1, c2, c3, c4;
    // 28 bytes of module name, packed with 0's.
    char name[28];
    unsigned long gp;		/* ptr to MIPS GOT data */
    unsigned long libent;       /* ptr to .lib.ent section */
    unsigned long libentend;    /* ptr to end of .lib.ent section */
    unsigned long libstub;      /* ptr to .lib.stub section */
    unsigned long libstubend;   /* ptr to end of .lib.stub section */
} __attribute__((packed)) PspModuleInfo;

// this struct seems to appear as the data in
// the .lib.ent section, and is referenced by
// the module info
typedef struct {
    unsigned long l1; // 0x00000000 ?
    unsigned long l2; // 0x80000000, most likely flags ?
    unsigned long l3; // 0x00010104, maybe 2 shorts? one is a version?
    // addr of start of .rodata.sceResident, which has 4
    // longs (and one 0 long) before module name strings start,
    // which includes things like a ptr to _start (see PspResidentData struct)
    unsigned long sceResidentAddr;
} PspLibEntData;

// this struct is pointed to by PspLibEntData, and appears at the
// start of .rodata.sceResident.  Each entry in .rodata.sceResident
// has a null long in between it, with the module strings (used in
// LibStubEntry) being padded to 4-byte alignment, and always
// including a terminating 0.

typedef struct {
    unsigned long l1; // unknown 0xd632acdb
    unsigned long l2; // unknown 0xf01d73a7
    unsigned long startAddress; // address of _start
    unsigned long moduleInfoAddr; // address of sceModuleInfo struct
} PspResidentData;

typedef struct {
    // pointer to module name (will be in .rodata.sceResident section)
    unsigned long moduleNameSymbol;
    // mod version??
    unsigned short version;
    unsigned short val1;
    unsigned char val2; // 0x5
    unsigned char val3;
    // number of function symbols
    unsigned short numFuncs;
    // each symbol has an associated nid; nidData is a pointer
    // (in .rodata.sceNid section) to an array of longs, one
    // for each function, which identifies the function whose
    // address is to be inserted.
    //
    // The hash is the first 4 bytes of a SHA-1 hash of the function
    // name.  (Represented as a little-endian long, so the order 
    // of the bytes is reversed.)
    unsigned long nidData;
    // the address of the function stubs where the function address jumps
    // should be filled in
    unsigned long firstSymAddr;
} __attribute__((packed)) PspLibStubEntry;
Execution seems to involve looking for the .lib.ent section, reading flags and the pointer to the PspResidentData. This chunk of data has 2 magic longs (unknown what their purpose or meaning is -- they seem to work fine for nem..), the program start address, and the address of the module info data (see PspModuleInfo struct).

That's all i've got so far; I'm curious what happens if someone with a 1.0 psp makes those 2 magic longs 0 in the PspResidentData...
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

Since PRX looks like a bastardized IRX (whose format is well known), the first 4 bytes of what you posted for PspModuleInfo appear to be the module version (second 2 bytes) and possibly flags. However it could also be a placeholder to link the PspModuleInfo structure into a linked list of modules, once the module is loaded.
"He was warned..."
nem
Posts: 73
Joined: Thu Jan 13, 2005 9:21 pm
Contact:

Post by nem »

For your interest, notes for PSP ELF format and program loader. Some need confirmation.

- ELF Type: EXEC(0x0002) NB:PRX have 0xffa0,0xff81, etc.
- ELF Flags: seems not to be used
- any section name, any section deploying is allowed, except .rodata.sceModuleInfo for module information
- .rodata.sceModuleInfo is mandantory to execute
- program loading header can be one or more
- physical address of first program loading header is file offset of module information
- can be absolute or relocatable but loading virtual address must be within 0x08900000..0x09ffffff, user memory area
- relocation info are simply omitted when loading
- module information have flags, module name, gp, export table address region(ent) and import table(stub) address region
- export/import is done by ascii string stub group name and 32bit id for each symbol
- 32bit id is independent from actual ascii symbol name as far as loader concerned
- import stub text contains jr ra, nop
- loader rewrites nop to syscall
- user program is executed in cpu's user mode
Warren
Posts: 175
Joined: Sat Jan 24, 2004 8:26 am
Location: San Diego, CA

Post by Warren »

32bit symbol ID is actually the first 4 bytes of SHA1 of the symbol name.
Someone on IRC figured this out the otehr day and there is code to calculate it on the ftp server.
vvuk
Posts: 13
Joined: Mon Apr 25, 2005 3:57 pm
Location: Foster City, CA

Post by vvuk »

Warren wrote:32bit symbol ID is actually the first 4 bytes of SHA1 of the symbol name.
Someone on IRC figured this out the otehr day and there is code to calculate it on the ftp server.
Right, what nem is saying (and as demonstrated by his code) -- the relocation is done only by the NID, the name is irrelevant. It can even be null.
Warren
Posts: 175
Joined: Sat Jan 24, 2004 8:26 am
Location: San Diego, CA

Post by Warren »

Ahh ok, gotcha.
Post Reply