From 5573bd6122f5bb623daad2ab5e5fbfaf9175f0f6 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Mon, 4 May 2026 12:26:16 +0800 Subject: [PATCH 1/9] Add advanced techniques documentation on PRX Module and adjust nav_order for contributing and downloads pages --- advanced_techniques.md | 111 +++++++++++++++++++++++++++++++++++++++++ contributing.md | 2 +- downloads.md | 2 +- 3 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 advanced_techniques.md diff --git a/advanced_techniques.md b/advanced_techniques.md new file mode 100644 index 0000000..5f59105 --- /dev/null +++ b/advanced_techniques.md @@ -0,0 +1,111 @@ +--- +title: Advanced Techniques +layout: home +nav_order: 7 +--- + +# Advanced Techniques +{: .fs-8 .fw-700 .text-center } + +When developing for the Playstation Portable (PSP), you may want to dynamically load code at runtime. This page will cover how to do that. + +## Basic Concepts +{: .fs-6 .fw-700 } + +Multiple modules can be loaded at the same time on the PSP. The main module is the one which is launched when starting a homebrew, but additional modules can be loaded and unloaded at runtime. These additional modules are called PRX modules and have the `.prx` file extension. They are similar to DLLs on Windows or shared objects on Linux. + +### Stub Library +{: .fs-4 .fw-700 } + +To be able to load a PRX module, the main module needs to know which functions it can call in the PRX module. This is done by creating a stub library, which is a static library that contains the function signatures of the functions in the PRX module. The main module can then link against this stub library and call the functions in the PRX module as if they were regular functions. + +The stub library only contains the Module Name, the NID (Native ID?) of the function and a stub implementation of the function. + +## Basic Workflow +{: .fs-6 .fw-700 } + +> PRX modules can act as a Resident Library, which exposes their own functions inside and export them for other modules to use. + +The core steps for creating a PRX module that others can load are as follows: +1. PRX Module Developers declare which functions are accessible from external modules by **Writing** an **Export Table**. +2. Target Users can establish a reference to the external functions in their own modules by using **Import Table**, which is generated from the PRX module's export table and can be further compiled into a **Stub Library**. + +## Writing Code and Export Table +{: .fs-6 .fw-700 } + +### Writing Code +{: .fs-4 .fw-700 } + +When writing code for a PRX module, the code is mostly the same as writing code for a regular module. The main difference is that the entry point of the module is different. + +When writing PRX module code, do not write regular `main` function, instead write an `module_start` function which will be called when the module is loaded and a `module_stop` function which will be called when the module is unloaded. These functions should return 0 on success and a negative value on failure. + +### Write the Export Table +{: .fs-4 .fw-700 } + +Create a file that ends with `.exp` extension. It is used to declare which functions are accessible from external modules. The format of the file is as follows: + +> Guidelines +> 1. `syslib` is an essential keyword that must be included in the export table. +> 2. It is said that Global Variables are not suggested to be exported. (TODO: Reference needed) + +An example of an export table is as follows, you can check it out on the [SDK source code](https://github.com/pspdev/pspsdk/blob/master/src/samples/prx/testprx/exports.exp): + +``` +# Define the exports for the prx +PSP_BEGIN_EXPORTS + +# These four lines are mandatory (although you can add other functions like module_stop) +# syslib is a psynonym for the single mandatory export. +PSP_EXPORT_START(syslib, 0, 0x8000) +PSP_EXPORT_FUNC_HASH(module_start) +PSP_EXPORT_VAR_HASH(module_info) +PSP_EXPORT_END + +# Export our function +PSP_EXPORT_START(MyLib, 0, 0x0001) +PSP_EXPORT_FUNC_HASH(getModuleInfo) +PSP_EXPORT_END + +PSP_END_EXPORTS +``` + +### Compile the PRX Module +{: .fs-4 .fw-700 } + +If you are using Makefiles, you can add the following lines to your Makefile to compile the PRX module: + +```makefile +# Define to build this as a prx (instead of a static elf) +BUILD_PRX=1 +# Define the name of our custom exports (minus the .exp extension) +PRX_EXPORTS=exports.exp +``` + +When PRX_EXPORTS is defined, the build system will call `psp-build-exports -b` for you and automatically generate code that will be compiled into the PRX module. + +> `.rodata.sceResident` segment contains exported NID and function addresses. +> +> `.lib.ent` segment contains Module Name and Export Table Metadata, including the pointer to the export table in `.rodata.sceResident` segment. +> +> You can checkout the code by running `psp-build-exports -b exports.exp` in the terminal yourself. + +### Generate the Stub Library +{: .fs-4 .fw-700 } + +To generate the stub library, you can run the following command in the terminal: + +```sh +psp-build-exports -k my_lib.exp +``` + +This will generate a Stub File in `.S` Assembly format. Such file can be compiled into a static library first using `psp-gcc` and then `psp-ar`. Also you can directly distribute it. When others want to use your PRX module, they can simply treat this `.S` as one of the source files. + +## Dynamically Loading PRX Modules +{: .fs-6 .fw-700 } + +To dynamically load a PRX module, you can use the `sceKernelLoadModule` function and the `sceKernelStartModule` function. + +When building your programs, you need to include the generated `.S` stub file (or the stub `.a` library) into your OBJS or LIBS for linking. + +The generated `.S` file uses a series of macros, working with the post-processing tool `psp-fixup-imports` to complete the construction of the import table. \ No newline at end of file diff --git a/contributing.md b/contributing.md index bcf9c6e..48ae037 100644 --- a/contributing.md +++ b/contributing.md @@ -1,7 +1,7 @@ --- title: Contributing layout: home -nav_order: 8 +nav_order: 9 --- # Contributing diff --git a/downloads.md b/downloads.md index 0e12b37..99a0322 100644 --- a/downloads.md +++ b/downloads.md @@ -1,7 +1,7 @@ --- title: Downloads layout: home -nav_order: 7 +nav_order: 8 --- # Downloads From 74d88dbf94efeaac2686cd3f34a11a7ef6440ef6 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Tue, 5 May 2026 12:01:19 +0800 Subject: [PATCH 2/9] Fix Grammer Co-authored-by: Copilot --- advanced_techniques.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/advanced_techniques.md b/advanced_techniques.md index 5f59105..5814172 100644 --- a/advanced_techniques.md +++ b/advanced_techniques.md @@ -17,7 +17,7 @@ Multiple modules can be loaded at the same time on the PSP. The main module is t ### Stub Library {: .fs-4 .fw-700 } -To be able to load a PRX module, the main module needs to know which functions it can call in the PRX module. This is done by creating a stub library, which is a static library that contains the function signatures of the functions in the PRX module. The main module can then link against this stub library and call the functions in the PRX module as if they were regular functions. +To load a PRX module, the main module needs to know which functions it can call within that module. This is done by creating a stub library, a static library containing the signatures of the functions in the PRX module. The main module links against this stub library and calls the functions in the PRX module just like regular functions. The stub library only contains the Module Name, the NID (Native ID?) of the function and a stub implementation of the function. @@ -27,8 +27,8 @@ The stub library only contains the Module Name, the NID (Native ID?) of the func > PRX modules can act as a Resident Library, which exposes their own functions inside and export them for other modules to use. The core steps for creating a PRX module that others can load are as follows: -1. PRX Module Developers declare which functions are accessible from external modules by **Writing** an **Export Table**. -2. Target Users can establish a reference to the external functions in their own modules by using **Import Table**, which is generated from the PRX module's export table and can be further compiled into a **Stub Library**. +1. PRX module developers declare which functions are accessible from external modules by writing an **Export Table**. +2. Users can establish a reference to these external functions in their modules by using an **Import Table**, which is generated from the PRX module's export table and can be compiled into a **Stub Library**. ## Writing Code and Export Table {: .fs-6 .fw-700 } @@ -36,20 +36,20 @@ The core steps for creating a PRX module that others can load are as follows: ### Writing Code {: .fs-4 .fw-700 } -When writing code for a PRX module, the code is mostly the same as writing code for a regular module. The main difference is that the entry point of the module is different. +Writing code for a PRX module is largely identical to writing code for a regular module. The primary difference is the entry point. -When writing PRX module code, do not write regular `main` function, instead write an `module_start` function which will be called when the module is loaded and a `module_stop` function which will be called when the module is unloaded. These functions should return 0 on success and a negative value on failure. +Instead of writing a standard `main` function, you write a `module_start` function (called when the module is loaded) and a `module_stop` function (called when unloaded). These functions should return 0 on success and a negative value on failure. ### Write the Export Table {: .fs-4 .fw-700 } -Create a file that ends with `.exp` extension. It is used to declare which functions are accessible from external modules. The format of the file is as follows: +Create a file with an `.exp` extension. It is used to declare which functions are accessible from external modules. The format is as follows: > Guidelines > 1. `syslib` is an essential keyword that must be included in the export table. -> 2. It is said that Global Variables are not suggested to be exported. (TODO: Reference needed) +> 2. It is generally not recommended to export global variables. (TODO: Reference needed) -An example of an export table is as follows, you can check it out on the [SDK source code](https://github.com/pspdev/pspsdk/blob/master/src/samples/prx/testprx/exports.exp): +Here is an example export table (you can view it in the [SDK source code](https://github.com/pspdev/pspsdk/blob/master/src/samples/prx/testprx/exports.exp)): ``` # Define the exports for the prx @@ -82,30 +82,30 @@ BUILD_PRX=1 PRX_EXPORTS=exports.exp ``` -When PRX_EXPORTS is defined, the build system will call `psp-build-exports -b` for you and automatically generate code that will be compiled into the PRX module. +When `PRX_EXPORTS` is defined, the build system calls `psp-build-exports -b` and automatically generates the code to compile into the PRX module. -> `.rodata.sceResident` segment contains exported NID and function addresses. +> The `.rodata.sceResident` segment contains the exported NIDs and function addresses. > -> `.lib.ent` segment contains Module Name and Export Table Metadata, including the pointer to the export table in `.rodata.sceResident` segment. +> The `.lib.ent` segment contains the module name and export table metadata, including a pointer to the export table in the `.rodata.sceResident` segment. > -> You can checkout the code by running `psp-build-exports -b exports.exp` in the terminal yourself. +> You can inspect the generated code by running `psp-build-exports -b exports.exp` in your terminal. ### Generate the Stub Library {: .fs-4 .fw-700 } -To generate the stub library, you can run the following command in the terminal: +To generate the stub library, first run the following command in the terminal: ```sh psp-build-exports -k my_lib.exp ``` -This will generate a Stub File in `.S` Assembly format. Such file can be compiled into a static library first using `psp-gcc` and then `psp-ar`. Also you can directly distribute it. When others want to use your PRX module, they can simply treat this `.S` as one of the source files. +This generates a stub file in `.S` assembly format. This file can be compiled into a static library using `psp-gcc` followed by `psp-ar`, or distributed directly. When others want to use your PRX module, they can simply include this `.S` file as a source file. ## Dynamically Loading PRX Modules {: .fs-6 .fw-700 } -To dynamically load a PRX module, you can use the `sceKernelLoadModule` function and the `sceKernelStartModule` function. +To dynamically load a PRX module, you can use the `sceKernelLoadModule` and `sceKernelStartModule` functions. -When building your programs, you need to include the generated `.S` stub file (or the stub `.a` library) into your OBJS or LIBS for linking. +When building your programs, include the generated `.S` stub file (or the `.a` stub library) in your `OBJS` or `LIBS` for linking. -The generated `.S` file uses a series of macros, working with the post-processing tool `psp-fixup-imports` to complete the construction of the import table. \ No newline at end of file +The generated `.S` file uses several macros along with the post-processing tool `psp-fixup-imports` to construct the import table. \ No newline at end of file From 1b44b9888a138b634050338140cc2e37520caae3 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Tue, 5 May 2026 12:10:53 +0800 Subject: [PATCH 3/9] Update Navigation --- advanced_techniques.md | 103 +--------------------------------- techniques/prx_modules.md | 113 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 100 deletions(-) create mode 100644 techniques/prx_modules.md diff --git a/advanced_techniques.md b/advanced_techniques.md index 5814172..324cbb2 100644 --- a/advanced_techniques.md +++ b/advanced_techniques.md @@ -9,103 +9,6 @@ nav_order: 7 When developing for the Playstation Portable (PSP), you may want to dynamically load code at runtime. This page will cover how to do that. -## Basic Concepts -{: .fs-6 .fw-700 } - -Multiple modules can be loaded at the same time on the PSP. The main module is the one which is launched when starting a homebrew, but additional modules can be loaded and unloaded at runtime. These additional modules are called PRX modules and have the `.prx` file extension. They are similar to DLLs on Windows or shared objects on Linux. - -### Stub Library -{: .fs-4 .fw-700 } - -To load a PRX module, the main module needs to know which functions it can call within that module. This is done by creating a stub library, a static library containing the signatures of the functions in the PRX module. The main module links against this stub library and calls the functions in the PRX module just like regular functions. - -The stub library only contains the Module Name, the NID (Native ID?) of the function and a stub implementation of the function. - -## Basic Workflow -{: .fs-6 .fw-700 } - -> PRX modules can act as a Resident Library, which exposes their own functions inside and export them for other modules to use. - -The core steps for creating a PRX module that others can load are as follows: -1. PRX module developers declare which functions are accessible from external modules by writing an **Export Table**. -2. Users can establish a reference to these external functions in their modules by using an **Import Table**, which is generated from the PRX module's export table and can be compiled into a **Stub Library**. - -## Writing Code and Export Table -{: .fs-6 .fw-700 } - -### Writing Code -{: .fs-4 .fw-700 } - -Writing code for a PRX module is largely identical to writing code for a regular module. The primary difference is the entry point. - -Instead of writing a standard `main` function, you write a `module_start` function (called when the module is loaded) and a `module_stop` function (called when unloaded). These functions should return 0 on success and a negative value on failure. - -### Write the Export Table -{: .fs-4 .fw-700 } - -Create a file with an `.exp` extension. It is used to declare which functions are accessible from external modules. The format is as follows: - -> Guidelines -> 1. `syslib` is an essential keyword that must be included in the export table. -> 2. It is generally not recommended to export global variables. (TODO: Reference needed) - -Here is an example export table (you can view it in the [SDK source code](https://github.com/pspdev/pspsdk/blob/master/src/samples/prx/testprx/exports.exp)): - -``` -# Define the exports for the prx -PSP_BEGIN_EXPORTS - -# These four lines are mandatory (although you can add other functions like module_stop) -# syslib is a psynonym for the single mandatory export. -PSP_EXPORT_START(syslib, 0, 0x8000) -PSP_EXPORT_FUNC_HASH(module_start) -PSP_EXPORT_VAR_HASH(module_info) -PSP_EXPORT_END - -# Export our function -PSP_EXPORT_START(MyLib, 0, 0x0001) -PSP_EXPORT_FUNC_HASH(getModuleInfo) -PSP_EXPORT_END - -PSP_END_EXPORTS -``` - -### Compile the PRX Module -{: .fs-4 .fw-700 } - -If you are using Makefiles, you can add the following lines to your Makefile to compile the PRX module: - -```makefile -# Define to build this as a prx (instead of a static elf) -BUILD_PRX=1 -# Define the name of our custom exports (minus the .exp extension) -PRX_EXPORTS=exports.exp -``` - -When `PRX_EXPORTS` is defined, the build system calls `psp-build-exports -b` and automatically generates the code to compile into the PRX module. - -> The `.rodata.sceResident` segment contains the exported NIDs and function addresses. -> -> The `.lib.ent` segment contains the module name and export table metadata, including a pointer to the export table in the `.rodata.sceResident` segment. -> -> You can inspect the generated code by running `psp-build-exports -b exports.exp` in your terminal. - -### Generate the Stub Library -{: .fs-4 .fw-700 } - -To generate the stub library, first run the following command in the terminal: - -```sh -psp-build-exports -k my_lib.exp -``` - -This generates a stub file in `.S` assembly format. This file can be compiled into a static library using `psp-gcc` followed by `psp-ar`, or distributed directly. When others want to use your PRX module, they can simply include this `.S` file as a source file. - -## Dynamically Loading PRX Modules -{: .fs-6 .fw-700 } - -To dynamically load a PRX module, you can use the `sceKernelLoadModule` and `sceKernelStartModule` functions. - -When building your programs, include the generated `.S` stub file (or the `.a` stub library) in your `OBJS` or `LIBS` for linking. - -The generated `.S` file uses several macros along with the post-processing tool `psp-fixup-imports` to construct the import table. \ No newline at end of file +- [Creating PRX Modules](techniques/prx_modules.html) + + \ No newline at end of file diff --git a/techniques/prx_modules.md b/techniques/prx_modules.md new file mode 100644 index 0000000..087b192 --- /dev/null +++ b/techniques/prx_modules.md @@ -0,0 +1,113 @@ +--- +title: Creating PRX Modules +layout: home +nav_exclude: true +--- +# Creating PRX Modules +{: .fs-8 .fw-700 .text-center } + +## Basic Concepts +{: .fs-6 .fw-700 } + +Multiple modules can be loaded at the same time on the PSP. The main module is the one which is launched when starting a homebrew, but additional modules can be loaded and unloaded at runtime. These additional modules are called PRX modules and have the `.prx` file extension. They are similar to DLLs on Windows or shared objects on Linux. + +### Stub Library +{: .fs-4 .fw-700 } + +To load a PRX module, the main module needs to know which functions it can call within that module. This is done by creating a stub library, a static library containing the signatures of the functions in the PRX module. The main module links against this stub library and calls the functions in the PRX module just like regular functions. + +The stub library only contains the Module Name, the NID (Native ID?) of the function and a stub implementation of the function. + +## Basic Workflow +{: .fs-6 .fw-700 } + +> PRX modules can act as a Resident Library, which exposes their own functions inside and export them for other modules to use. + +The core steps for creating a PRX module that others can load are as follows: +1. PRX module developers declare which functions are accessible from external modules by writing an **Export Table**. +2. Users can establish a reference to these external functions in their modules by using an **Import Table**, which is generated from the PRX module's export table and can be compiled into a **Stub Library**. + +## Writing Code and Export Table +{: .fs-6 .fw-700 } + +### Writing Code +{: .fs-4 .fw-700 } + +Writing code for a PRX module is largely identical to writing code for a regular module. The primary difference is the entry point. + +Instead of writing a standard `main` function, you write a `module_start` function (called when the module is loaded) and a `module_stop` function (called when unloaded). These functions should return 0 on success and a negative value on failure. + +### Write the Export Table +{: .fs-4 .fw-700 } + +Create a file with an `.exp` extension. It is used to declare which functions are accessible from external modules. The format is as follows: + +> Guidelines +> 1. `syslib` is an essential keyword that must be included in the export table. +> 2. It is generally not recommended to export global variables. (TODO: Reference needed) + +Here is an example export table (you can view it in the [SDK source code](https://github.com/pspdev/pspsdk/blob/master/src/samples/prx/testprx/exports.exp)): + +``` +# Define the exports for the prx +PSP_BEGIN_EXPORTS + +# These four lines are mandatory (although you can add other functions like module_stop) +# syslib is a psynonym for the single mandatory export. +PSP_EXPORT_START(syslib, 0, 0x8000) +PSP_EXPORT_FUNC_HASH(module_start) +PSP_EXPORT_VAR_HASH(module_info) +PSP_EXPORT_END + +# Export our function +PSP_EXPORT_START(MyLib, 0, 0x0001) +PSP_EXPORT_FUNC_HASH(getModuleInfo) +PSP_EXPORT_END + +PSP_END_EXPORTS +``` + +### Compile the PRX Module +{: .fs-4 .fw-700 } + +If you are using Makefiles, you can add the following lines to your Makefile to compile the PRX module: + +```makefile +# Define to build this as a prx (instead of a static elf) +BUILD_PRX=1 +# Define the name of our custom exports (minus the .exp extension) +PRX_EXPORTS=exports.exp +``` + +When `PRX_EXPORTS` is defined, the build system calls `psp-build-exports -b` and automatically generates the code to compile into the PRX module. + +> The `.rodata.sceResident` segment contains the exported NIDs and function addresses. +> +> The `.lib.ent` segment contains the module name and export table metadata, including a pointer to the export table in the `.rodata.sceResident` segment. +> +> You can inspect the generated code by running `psp-build-exports -b exports.exp` in your terminal. + +### Generate the Stub Library +{: .fs-4 .fw-700 } + +To generate the stub library, first run the following command in the terminal: + +```sh +psp-build-exports -k my_lib.exp +``` + +This generates a stub file in `.S` assembly format. This file can be compiled into a static library using `psp-gcc` followed by `psp-ar`, or distributed directly. When others want to use your PRX module, they can simply include this `.S` file as a source file. + +## Dynamically Loading PRX Modules +{: .fs-6 .fw-700 } + +To dynamically load a PRX module, you can use the `sceKernelLoadModule` and `sceKernelStartModule` functions. + +When building your programs, include the generated `.S` stub file (or the `.a` stub library) in your `OBJS` or `LIBS` for linking. + +The generated `.S` file uses several macros along with the post-processing tool `psp-fixup-imports` to construct the import table. + +## Further Reading +{: .fs-6 .fw-700 } + +- [PSP Modules, Exports, Imports and Patches](https://uofw.github.io/upspd/docs/software/ModuleTutorialv1.pdf): A short tutorial released in 2007 describing modules used in Sony’s PSP by Anissian. \ No newline at end of file From a8932acb7f839f52cb038a7625f538e64aad90c7 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Tue, 5 May 2026 12:23:38 +0800 Subject: [PATCH 4/9] Add Restrictions on C stdlib and C++ --- techniques/prx_modules.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/techniques/prx_modules.md b/techniques/prx_modules.md index 087b192..0a009ed 100644 --- a/techniques/prx_modules.md +++ b/techniques/prx_modules.md @@ -37,6 +37,10 @@ Writing code for a PRX module is largely identical to writing code for a regular Instead of writing a standard `main` function, you write a `module_start` function (called when the module is loaded) and a `module_stop` function (called when unloaded). These functions should return 0 on success and a negative value on failure. +Also it is not recommended to use any Standard C Library functions in your code. The `newlib` implementation in the PSPSDK often causes issues when used in PRX modules, and it is generally better to avoid it altogether. Instead, you can use the PSPSDK's own functions for memory management, string manipulation, etc. + +Due to similar reasons, C++ is also not recommended for PRX modules. + ### Write the Export Table {: .fs-4 .fw-700 } @@ -87,6 +91,12 @@ When `PRX_EXPORTS` is defined, the build system calls `psp-build-exports -b` and > > You can inspect the generated code by running `psp-build-exports -b exports.exp` in your terminal. +Also, when building a PRX module, you should add the `-nostartfiles` flag to your `LDFLAGS` to prevent the linker from including the startup files, which are not needed and can cause issues in PRX modules. + +```makefile +LDFLAGS = -nostartfiles +``` + ### Generate the Stub Library {: .fs-4 .fw-700 } From 46c233042ec4b630b00e6abeb99226fbbd461623 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Tue, 5 May 2026 17:48:56 +0800 Subject: [PATCH 5/9] Provide Example on Module Side --- advanced_techniques.md | 4 +- techniques/prx_modules.md | 88 +++++++++++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/advanced_techniques.md b/advanced_techniques.md index 324cbb2..2610a7a 100644 --- a/advanced_techniques.md +++ b/advanced_techniques.md @@ -9,6 +9,4 @@ nav_order: 7 When developing for the Playstation Portable (PSP), you may want to dynamically load code at runtime. This page will cover how to do that. -- [Creating PRX Modules](techniques/prx_modules.html) - - \ No newline at end of file +- [Creating PRX Modules](techniques/prx_modules.html) \ No newline at end of file diff --git a/techniques/prx_modules.md b/techniques/prx_modules.md index 0a009ed..e4065b2 100644 --- a/techniques/prx_modules.md +++ b/techniques/prx_modules.md @@ -16,7 +16,7 @@ Multiple modules can be loaded at the same time on the PSP. The main module is t To load a PRX module, the main module needs to know which functions it can call within that module. This is done by creating a stub library, a static library containing the signatures of the functions in the PRX module. The main module links against this stub library and calls the functions in the PRX module just like regular functions. -The stub library only contains the Module Name, the NID (Native ID?) of the function and a stub implementation of the function. +The stub library only contains the Module Name, the NID (hash of the function name) of the function and a stub implementation of the function. ## Basic Workflow {: .fs-6 .fw-700 } @@ -37,10 +37,44 @@ Writing code for a PRX module is largely identical to writing code for a regular Instead of writing a standard `main` function, you write a `module_start` function (called when the module is loaded) and a `module_stop` function (called when unloaded). These functions should return 0 on success and a negative value on failure. +> Make sure to use at least on function form other modules (for example, `pspDebugScreenPrintf`), otherwise `psp-fixup-imports` will complain `Error, no .lib.stub section found`. + Also it is not recommended to use any Standard C Library functions in your code. The `newlib` implementation in the PSPSDK often causes issues when used in PRX modules, and it is generally better to avoid it altogether. Instead, you can use the PSPSDK's own functions for memory management, string manipulation, etc. Due to similar reasons, C++ is also not recommended for PRX modules. +```c +#include + +// Module Name, Attributes, Major Version, Minor Version +// This module is a user module +PSP_MODULE_INFO("SamplePlugin", PSP_MODULE_USER, 1, 0); +PSP_NO_CREATE_MAIN_THREAD(); + +int module_start() { + SceUID fd = sceIoOpen("log.txt", PSP_O_WRONLY | PSP_O_CREAT | PSP_O_APPEND, 0777); + if (fd >= 0) { + sceIoWrite(fd, "Hello World!", 12); + sceIoClose(fd); + } + return 0; +} + +int module_stop() { + SceUID fd = sceIoOpen("log.txt", PSP_O_WRONLY | PSP_O_CREAT | PSP_O_APPEND, 0777); + if (fd >= 0) { + sceIoWrite(fd, "Goodbye World!", 14); + sceIoClose(fd); + } + return 0; +} + +// This function will be exported and can be called from other modules +int sum(int a, int b) { + return a + b; +} +``` + ### Write the Export Table {: .fs-4 .fw-700 } @@ -48,7 +82,7 @@ Create a file with an `.exp` extension. It is used to declare which functions ar > Guidelines > 1. `syslib` is an essential keyword that must be included in the export table. -> 2. It is generally not recommended to export global variables. (TODO: Reference needed) +> 2. It is generally not recommended to export global variables. Here is an example export table (you can view it in the [SDK source code](https://github.com/pspdev/pspsdk/blob/master/src/samples/prx/testprx/exports.exp)): @@ -56,16 +90,17 @@ Here is an example export table (you can view it in the [SDK source code](https: # Define the exports for the prx PSP_BEGIN_EXPORTS -# These four lines are mandatory (although you can add other functions like module_stop) -# syslib is a psynonym for the single mandatory export. +# These lines are mandatory PSP_EXPORT_START(syslib, 0, 0x8000) -PSP_EXPORT_FUNC_HASH(module_start) -PSP_EXPORT_VAR_HASH(module_info) +PSP_EXPORT_FUNC(module_start) +PSP_EXPORT_FUNC(module_stop) +PSP_EXPORT_VAR(module_info) PSP_EXPORT_END # Export our function +# 'MyLib' is the name of the library, it doesn't have to match the module name PSP_EXPORT_START(MyLib, 0, 0x0001) -PSP_EXPORT_FUNC_HASH(getModuleInfo) +PSP_EXPORT_FUNC_HASH(sum) PSP_EXPORT_END PSP_END_EXPORTS @@ -97,16 +132,51 @@ Also, when building a PRX module, you should add the `-nostartfiles` flag to you LDFLAGS = -nostartfiles ``` +The whole Makefile looks like this: + +```makefile +TARGET = SamplePlugin + +OBJS = main.o + +CFLAGS = -O2 -Wall +LDFLAGS = -nostartfiles + +BUILD_PRX = 1 +PRX_EXPORTS = exports.exp + +PSPSDK=$(shell psp-config --pspsdk-path) +include $(PSPSDK)/lib/build.mak +``` + ### Generate the Stub Library {: .fs-4 .fw-700 } To generate the stub library, first run the following command in the terminal: ```sh -psp-build-exports -k my_lib.exp +psp-build-exports -k exports.exp +``` + +This generates a stub file in `.S` assembly format. It's name is `MyLib.S` as the library name in the export table is `MyLib`. + +```c + .set noreorder + +#include "pspimport.s" + +// Build files +// MyLib_0000.o MyLib_0001.o + +#ifdef F_MyLib_0000 + IMPORT_START "MyLib",0x00090000 +#endif +#ifdef F_MyLib_0001 + IMPORT_FUNC "MyLib",0x55F3DFE9,sum +#endif ``` -This generates a stub file in `.S` assembly format. This file can be compiled into a static library using `psp-gcc` followed by `psp-ar`, or distributed directly. When others want to use your PRX module, they can simply include this `.S` file as a source file. +This file can be compiled into a static library using `psp-gcc` followed by `psp-ar`, or distributed directly. When others want to use your PRX module, they can simply include this `.S` file as a source file. ## Dynamically Loading PRX Modules {: .fs-6 .fw-700 } From bda133f52a357dcfe4144c98b9859103acae2f21 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Tue, 5 May 2026 17:51:12 +0800 Subject: [PATCH 6/9] Fix typo --- techniques/prx_modules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techniques/prx_modules.md b/techniques/prx_modules.md index e4065b2..17d5a55 100644 --- a/techniques/prx_modules.md +++ b/techniques/prx_modules.md @@ -112,9 +112,9 @@ PSP_END_EXPORTS If you are using Makefiles, you can add the following lines to your Makefile to compile the PRX module: ```makefile -# Define to build this as a prx (instead of a static elf) +# Define to build this as a prx BUILD_PRX=1 -# Define the name of our custom exports (minus the .exp extension) +# Define the name of our custom exports PRX_EXPORTS=exports.exp ``` From 889e703cd8be06f4e650094ec25ea3303488ac18 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Tue, 5 May 2026 17:52:42 +0800 Subject: [PATCH 7/9] Update Intro on Advanced Topics --- advanced_techniques.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced_techniques.md b/advanced_techniques.md index 2610a7a..2d7b6df 100644 --- a/advanced_techniques.md +++ b/advanced_techniques.md @@ -7,6 +7,6 @@ nav_order: 7 # Advanced Techniques {: .fs-8 .fw-700 .text-center } -When developing for the Playstation Portable (PSP), you may want to dynamically load code at runtime. This page will cover how to do that. +Here are links to more in depth explanations of specific more advanced PSP programming topics. - [Creating PRX Modules](techniques/prx_modules.html) \ No newline at end of file From e14bd0c94a86b3652e04f3a9b5df6645c7affad8 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Wed, 6 May 2026 12:48:56 +0800 Subject: [PATCH 8/9] Fix Typo and update Functions that are recommended to use --- techniques/prx_modules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techniques/prx_modules.md b/techniques/prx_modules.md index 17d5a55..c3c17e1 100644 --- a/techniques/prx_modules.md +++ b/techniques/prx_modules.md @@ -37,9 +37,9 @@ Writing code for a PRX module is largely identical to writing code for a regular Instead of writing a standard `main` function, you write a `module_start` function (called when the module is loaded) and a `module_stop` function (called when unloaded). These functions should return 0 on success and a negative value on failure. -> Make sure to use at least on function form other modules (for example, `pspDebugScreenPrintf`), otherwise `psp-fixup-imports` will complain `Error, no .lib.stub section found`. +> Make sure to use at least one function from other modules (for example, `sceIoOpen`), otherwise `psp-fixup-imports` will complain `Error, no .lib.stub section found`. -Also it is not recommended to use any Standard C Library functions in your code. The `newlib` implementation in the PSPSDK often causes issues when used in PRX modules, and it is generally better to avoid it altogether. Instead, you can use the PSPSDK's own functions for memory management, string manipulation, etc. +Also it is not recommended to use any Standard C Library functions in your code. The `newlib` implementation in the PSPSDK often causes issues when used in PRX modules, and it is generally better to avoid it altogether. Instead, you can use the PSPSDK's own functions with `sce` prefix for memory management, string manipulation, etc. Due to similar reasons, C++ is also not recommended for PRX modules. From 67b61c2e1943e2ad0b12b0126162e1695e1a9b63 Mon Sep 17 00:00:00 2001 From: liu <62530004+xeonliu@users.noreply.github.com> Date: Wed, 6 May 2026 12:49:43 +0800 Subject: [PATCH 9/9] Remove unused link --- techniques/prx_modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techniques/prx_modules.md b/techniques/prx_modules.md index c3c17e1..ab1eca6 100644 --- a/techniques/prx_modules.md +++ b/techniques/prx_modules.md @@ -84,7 +84,7 @@ Create a file with an `.exp` extension. It is used to declare which functions ar > 1. `syslib` is an essential keyword that must be included in the export table. > 2. It is generally not recommended to export global variables. -Here is an example export table (you can view it in the [SDK source code](https://github.com/pspdev/pspsdk/blob/master/src/samples/prx/testprx/exports.exp)): +Here is an example export table: ``` # Define the exports for the prx