The RSO Library is a dynamic module system.
It uses main memory efficiently by dynamically reading and releasing the program module in the game application.
Unlike the dynamic link libraries of other operating systems, with this library the game application is responsible for allocating and deallocating main memory and loading modules from discs.
The RSO library consists of one static module (the .elf file), one static information module (the .sel file), and multiple dynamic (that is, relocatable) modules (the .rso files). After the boot ROM loads the static module of the program, the static module controls the memory location of the dynamic module. The static module is built as a normal .elf file. The static module contains common functions and common variables referenced by the dynamic modules.
Dynamic modules can call functions and refer to the variables defined in static modules. In addition, dynamic modules can call functions and refer to variables in other dynamic modules loaded into main memory. Referencing among modules can be resolved by directly editing the code and data sections when the module is loaded.
Functions and variables of the dynamic module can be accessed by specifying the symbol name from the static module.
Accordingly, the program must be aware of the dynamic modules that it uses, unlike when calling functions within static modules.
A dynamic module (RSO) application is written in the same manner as the main C/C++ code, except that the dynamic module is built from a partially-linked .elf file (PLF). A PLF file contains unresolved external symbols and debug information. The .plf file is then converted to a Wii-specific dynamic module format by using the makerso tool provided in the Revolution SDK. These Wii-specific dynamic modules include, in addition to the standard application code and data section, a relocation instruction list, import information, and export information.
Import information is used to reference external elements, while export information allows referencing by external elements.
- The dynamic module functions and variables can be accessed from the static module by specifying symbol names.
- As long as there are .rso files, the library can run, even if all the dynamic module .plf files have not been prepared first. (For example, you can run RSO files that have been pre-stored in NAND memory or other areas and update dynamic modules through downloading, etc.)
- The user can specify the links.
- Modules include symbol information, so they are larger than REL files (by about the character count in bytes).
- The user must manage access to dynamic modules from static modules.
- Since dynamic modules can be accessed from static modules, it is hard to eliminate code by optimizing compilation.
- Since resolution is done using symbol names, more processing is required for linking than with REL.
- The static module information (the .sel file) is required for initializing the link list.
.elf files.The RSO library uses the static linker partial link option. Each dynamic module is made from a separate set of partially linked files. Using the partial link option (-r), the linker can create an .elf file that includes unresolved external reference symbols. The unresolved symbols of the dynamic module are resolved when the application is run.
Three functions can be defined for a dynamic module: _prolog, _epilog, and _unresolved. The _prolog and _epilog functions can be called from the static module or from the other dynamic modules loaded into main memory. The _unresolved function is called when the module makes a function call to an external function that is not yet loaded into main memory.
The linker command file for the dynamic module is the sum of the <revolution/eppc.$(PLATFORM)> file with FORCEFILES and FORCEACTIVE. FORCEFILES includes the target files, and FORCEACTIVE includes the __global_destructor_chain.
The sample is output in .plf format.
Note:The dynamic module must not have small data sections. Small data section anchor registers (r2 and r13) are reserved for the static portion of the program. To prevent the compiler from generating small data sections, use the -sdata 0 -sdata2 0 compiler option when compiling a dynamic module.
.elf files.
Run the makerso tool to create a dynamic module file (.rso) from a partially linked .plf file.
|
Run the makelcf tool to create a static module linker command file and symbol list from all dynamic module files.
The linker command file is generated by attaching the FORCEACTIVE list to the <Revolution/eppc.$(PLATFORM).lcf> file.
The following shows how to generate a static module linker command file as static.lcf and a symbol list as symbol.lst.
|
Link the static modules of the program with the linker command file generated in the previous section. All the static libraries should be linked with the static module.
.elf file.Use the makerso tool to create static module information from the static .elf file and the symbol list generated in section 3.
The following shows how to generate a static module information as a static.sel file.
|
Note: Memory allocation/deallocation for loading dynamic modules and loading dynamic modules from game discs is performed by the game application.
The dynamic module loaded into main memory has type RSOObjectHeade data, followed by the module code and data sections.
Static module information has the same data structure as dynamic modules, but without the code, the import information, or the internal processing information.
The following is an example of loading modules:
|
Initialize the linked list, using RSOListInit.
Static module information is set at this time.
The static module information is used to obtain the function and variable addresses of the static module referenced by the dynamic module.
|
Link the dynamic module, using RSOLinkList.
The bss argument is a pointer to the section used as a bss section (section initialized by 0), and which the programmer allocates and specifies.
The required size for the bss section is defined vy RSOObjectHeader.bssSize.
You must call the prolog function (a member of the RSOObjectHeader structure) after the module is linked (optional).
|
If the loaded module becomes unnecessary, call RSOUnLinkList to free the memory space for another purpose.
You must call the epilog function (a member of the RSOObjectHeader structure) before unlinking the module (optional).
|
The RSOLinkListFixed function links the specified module and deallocates part of the memory occupied by the dynamic module.
Once the module is linked using RSOLinkListFixed, the remaining memory that comes after (specified by RSOGetFixedSize) can be used for any purpose (for example, for the bss area).
However, several restrictions may apply, depending on the deallocation timing. (See RSOLinkListFixed for details)
Also note that the location specified by RSOGetFixedSize is converted from the file offset to the virtual address when the module is linked.
The following is an example of partial deallocation of module memory and its reuse as a bss area:
|
Dynamic modules and bss sections both have address-alignment constraints. The dynamic module must be aligned at the maximum alignment value required by the .init, .text, .ctor, .dtor, .rodata, and .data sections. A bss section must be aligned at the maximum alignment value required by the data item within the bss section. Typically, both dynamic modules and bss sections require 8-byte alignment.
To access dynamic module functions and variables from the static module, the address is acquired by using RSOFindExportSymbolAddr based on the linked module information and label name.
The following example acquires and uses the addresses of the int foo(int a); function and the int g_int; variable from the dynamic module.
|
If using C++ global constructors in dynamic modules, global constructors and destructors must be called manually from _prolog and _epilog, respectively, as shown in the following code:
|
In addition, make sure that each dynamic module is linked to global_destructor_chain.c (in the $(CWFOLDER)/PowerPC_EABI_Support/Runtime/Src folder). Linking to this file guarantees that each global destructor is called every time the _epilog function of the module is called. Otherwise, module global variables in each module are linked to the global destructor chain in the static module, and unless the static module exists, destructors are never called.Be aware that since Runtime.PPCEABI.H.a uses small data sections and contains unnecessary functions, dynamic modules cannot be linked to it.
MEM2 region).
Typically, the branch instructions (bx) have only the 28-bit offset (± 32 MB). Therefore, when a relocatable module is placed in external main memory (MEM2), functions in internal main memory (MEM1) cannot be accessed.
This issue can be avoided by using pragma, or by using RSOLinkFar and RSOLinkJump.
Indicate to the compiler that the module needs to be branched in a 32-bit absolute address, using pragma.
For example, the MyFunction function (located in MEM1), must be branched in the absolute address. This applies, whether the target function is a static module or a dynamic module.
Also take similar precautions when calling functions in MEM2 from a dynamic module in MEM1.
|
Note as of 6/15/2006:
Certain runtime codes may not be properly called in 32-bit codes in the release version.
As a temporary remedy, apply use_lmw_stmw pragma to avoid using those runtime codes.
The pragma directive should be applied to the source of modules placed in MEM2.
This is also true for the compile option -use_lmw_stmw on.
|
Because using just the standard RSOLink causes this issue, re-link the modules located in main memory (both MEM1 and MEM2) using RSOLinkFar. RSOLinkFar places relay jump codes in buff. The linking modules then link to these jump codes to access the referenced modules in MEM2.
In the following example function LinkFar, the linked module (i_rsoImp) and the referenced module (i_rsoEx) are linked using a relay jump code. The return value is a pointer to the allocated buffer.
The required buffer size is obtained using RSOGetFarCodeSize, and then allocated. This is then linked using RSOLinkFar.
|
Note: Allocate the buffer from the same main memory (MEM2 or MEM1) as the linking module (i_rsoImp).
In addition, the code in the module is overwritten normally after linking. Thus, when using RSOLinkListFixed, proceed to RSO_FL_INTERNAL at the release stage.
RSOLinkJump creates a relay code to the module being referenced. The referencing side then uses this to link.
To create a relay code, obtain the necessary buffer size, using RSOGetJumpCodeSize, and then create the relay code, using RSOMakeJumpCode.
|
Link with the created buffer and RSOLinkJump.
|
12/19/2006 Added description for RSOLinkJump.
10/25/2006 Added description for RSOLinkFar.
6/14/2006 Initial version.
CONFIDENTIAL