ddw3/docs/exec.md

3.8 KiB

Executable

The games feature an executable and various dylibs (dynamic libraries) that are loaded at runtime.

The dynamic library loading is still mostly unknown.

File format

The executable is a psexe, which is simply a header following by machine instructions (called text section).

The header has the following structure:

Name Offset Type / Size (bytes) Description
Start address 0x0 u32 (0x4) The address at which the cpu will start executing instructions.
Text base 0x4 u32 (0x4) The location to place the text section at
Text size 0x8 u32 (0x4) The size of the text section
Stack pointer 0x8 u32 (0x4) What to initialize the stack pointer to
License 0xc [u8] (0x7b4) License

In total, it has 0x800 bytes.

Meanwhile, the dynamic libraries are called raw_exe. i.e. they are simply machine instructions.

Usage

psexe Executables

Executables are built from elf files, by using their text section as the text section of the psexe. All fields are automatically filled.

TODO: The stack pointer can't be currently customized, should we allow it? Either way the game sets the stack pointer itself, so it shouldn't matter.

They are built by ddw3-mkpsexe from toml header files, with the following structure:

# The elf file
elf = "<elf path>"

# License
license = "<license path>"

Then using build/tools/ddw3-mkpsexe <toml> --output <psexe> --license <license> --resize-text <text length> (The zbuild file automatically reads the toml and passes the correct arguments)

TODO: Although this can be done in zbuild, maybe we should use an external python script, since it would yield better errors on missing fields, as well as be faster and simpler by not relying on invocations of yq and tools/process_path.py.

raw_exe Dynamic libraries

Dynamic libraries are also built from elf files, by using their text section, similarly to psexes. However, they do not have a header, so no extra input is required.

They are built using objcopy --dump-section=.text=<raw-exe> <elf>.

Elf

Elf files are created from a list of object files. Each object files will have multiple sections that will be flattened into text using the provided order (with a linker script).

They are built by ddw3-mkpsexe from toml header files, with the following structure:

entry = <symbol to start at>
start_addr = <start address>
objs = <list of object files>
sections = <list of ordered sections to include>

Then using tools/ld_from_toml.py <toml> -o <elf> --linker-script-output <linker-script> --ld-bin <ld binary path>.

Object files (assembly)

Assembly object files are created from a single assembly file using as <asm-src> -o <asm-obj> -EL -mabi=32 -mips1 -march=r3000 -msoft-float -g -Iasm/ -I./ -I<asm-src-dir>/ --strip-local-absolute

Object files (rust)

Rust files are created from rust crates.

They are built using cargo build --release --package=<package-name> -Zunstable-options (inside rust/).

This will create the library in rust/target/mipsel-sony-psx/release/lib<package-name>.a.

Organization

The psexe headers are located in /psexe.

The raw-exe headers are in raw_exe.

The assembly sources are in asm/.

The rust sources are in rust/.

Notes

When creating elfs, we can't use the .a archives that rust produces for some reason. You can fix this by replacing it with .o instead, which is a file that zbuild creates from the .a to fix this problem.