-
Notifications
You must be signed in to change notification settings - Fork 3
PsyQ Lib File Format
PsyQ static libraries are shipped with the official PS1 SDK and provides all needed APIs for develop games on this console.
Some fields are still unknown but it's possible to extract all function signatures, names and relocation info.
NOTE: All std::string
in structs are parsed from a PsyQString
type.
A PsyQ Lib begin with "LIB" signature and its version.
struct PSYQFile {
char signature[3]; // "LIB"
u8 version; // Always 1
};
The PsyQ string is represented in this way:
struct PSYQString {
u8 length;
char data[1];
};
If the length
field is 0, the data
one doesn't exist.
NOTE: those strings are are not null terminated.
Modules are the main data structure of LIB files, they contains one or more function definitions, sections, relocations and data/function references, the size of this structure is variable, so it must be read sequencially.
By using C++, the structure is more or less this:
struct PSYQModule {
std::string name;
u32 unk, offsetlink, offsetnext;
std::list<std::string> names;
PSYQLink link;
};
- name: Max length 8.
- offsetlink: Relative offset to "LNK" structure (see below).
- offsetnext: Relative offset to the next module.
- names: PSYQString array of definitions.
-
link: "LNK" structure.
NOTE: Offsets are relative to the beginning of PSYQModule.
Every module provides a "LNK" structure which contains all useful data of a LIB file, this structure is not fixed.
struct PSYQLink {
char signature[3]; // "LNK"
u8 version, processorType;
std::unordered_map<u16, PSYQSection> sections;
std::unordered_map<u16, PSYQDefinition> definitions;
std::unordered_map<u16, PSYQReference> references;
std::unordered_map<u16, PSYQBss> bss;
std::list<PSYQPatch> patches;
};
- signature: "LNK".
- version: Always 2.
- processorType: Always 7 (MIPS?).
After the processorType
field the structure is variable: sections, definition, references, bss and patches can be available in every order.
Before every structure there is an hint byte which help to understand which data is following, there are the known values:
enum PSYQState: u8 {
SectionEOF = 0,
SectionCode = 2,
SectionSwitch = 6,
SectionBss = 8,
SectionPatch = 10,
SymbolRef = 14,
SymbolDef = 12,
SectionSymbol = 16,
Processor = 46,
SymbolBss = 48,
};
- SectionEOF: This module is terminated.
- SectionCode: Here we have the section's bytes.
- SectionSwitch: We are switching section, all information that follows belongs to this one.
- SectionBSS: Size of unallocated data.
- SectionPatch: Relocations.
- SymbolRef: Imported/External symbols.
- SymbolDef: Function declaration.
- SectionSymbol: The section header (with symbolnumber, group and alignment).
- Processor: A single byte which is always 7.
- SymbolBss: Variable references.
We can get the function signatures from here!
struct PSYQSectionCode {
u16 length;
u8 data[1];
}
A unsigned 16-bit integer with the section number
An unsigned 32-bit integer which contains size of the current BSS section.
This section contains the relocations for this module, the structure is variable and contains some kind of substates
struct PSYQPatch {
u8 type;
u16 offset;
struct {
u8 unk1;
u32 value;
} patchvalue;
struct {
u16 symbolnumber;
u16 sectionnumber;
};
};
These are the relocation states.
Names are guessed, so they may be wrong:
enum PSYQPatchState: u8 {
PatchToReference = 2,
PatchToSection = 4,
PatchToValue = 44,
PatchToDiff = 46,
};
Every relocation begins with type
and offset
fieldd and is followed by a PSYQPatchState
unsgined 8-bit value which explains how to read the rest of the relocation:
- PatchToReference: Unsigned 16-bit integer which represents the symbol number.
- PatchToSection: Unsigned 16-bit integer which represents the section number.
- PatchToValue: An unknown 8-bit value followed by a 32-bit integer with the relocation value.
-
PatchToDiff: Same as
PatchToValue
.
This state contains all external references with the symbol number (useful for relocations) and its name.
struct PSYQReference {
u16 symbolnumber;
std::string name;
};
This is a symbol defined inside the library with its code/data.
struct PSYQDefinition {
u16 symbolnumber, sectionnumber;
u32 offset;
std::string name;
};
- symbolnumber: A unique id for this symbol.
- sectionnumber: The section that contains this symbol.
- offset: A section relative offset where you can find the data of this symbol (function bytes, etc.)
- name: The name of this symbol.
This state contains the header of a single section:
struct PSYQSection {
u16 symbolnumber, group;
u8 alignment;
std::string name;
std::vector<u8> code;
// u32 sizebss;
};
- symbolnumber: The unique id for this section (used in relocations and symbol definitions).
- group: It seems to be always 0.
- alignment: Always 8.
- name: The name of this section (.text, .data, .bss, etc).
- code: The section bytes (if not bss).
-
sizebss: The size of BSS section (0 if
code
is valid).
An 8-bit integer which is always 7.
struct PSYQBss {
u16 symbolnumber, sectionnumber;
u32 size;
std::string name;
};
- symbolnumber: The unique id (used in relocations and symbol definitions).
- sectionnumber: The section that contains this symbol.
- size: Size, in bytes.
- name: Name.
- https://github.com/REDasmOrg/REDasm-Signature/blob/master/parsers/psyqlib.h
- https://github.com/REDasmOrg/REDasm-Signature/blob/master/parsers/psyqlib.cpp
- PSYLIB.EXE from PsyQ
- DUMPOBJ.EXE from PsyQ