Edit me

Overview

On the Wii U all system libraries are linked dynamically (with a few exceptions), not statically. This means the libraries are provides as extra files (.rpl) and loaded + linked when needed.

There are two ways to load and use .rpl files.

  1. The loader resolves any usages of libraries, resulting in a transparent dynamic linking. (recommended)
  2. Using system functions to explicitly load and use libraries via OSDynLoad_Acquire OSDynLoad_FindExport` on run time.

For the system libraries (.rpl files in the OSv10 title) you can link against stub libraries provided by wut.
wut also provides header files for most of the libraries which can be used.
The WUPS loader will resolve the usage of the functions automatically.

To use for example the OSScreenInit function from coreinit.rpl you can simply use the following code:

// Include the coreinit screen function header
#include <coreinit/screen.h>

int main(){
    OSScreenInit();
    OSScreenShutdown();
}

Because we used functions from the coreinit.rpl we need to link with libcoreinit which is located in $(WUT_ROOT)/lib. When using the example Makefile, you simply would have add -lcoreinit to the LIBS variable, and make sure $(WUT_ROOT) was added to LIBDIRS.

The following snippet from the example Makefile allows to use functions from the coreinit.rpl and nsysnet.rpl.

#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS             := $(WUPSDIR) $(WUT_ROOT)

#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lwups -lutilswut -lcoreinit -lnsysnet

How do I know which functions I can use?

A list of all function exports from all system libraries can be found on the wut repository. All of these functions are defined, but not all of them are declared in the wut headers. For the most common functions you should find declarations in wut headers. If you have any declarations that are missing, feel free to add them to wut via an pull request!

How to use functions that are missing in the wut headers?

Example:

// Let's pretends OSScreenInit and OSScreenshutdown are NOT declared in the wut headers.
// We would have to declare them ourselves.

// When we are compiling it as C++, we have to make sure to declare them
// in a C context to avoid function name mangling. 
#ifdef __cplusplus
extern "C" {
#endif
    void OSScreenInit();
    void OSScreenShutdown();
#ifdef __cplusplus
}
#endif

int main(){
    OSScreenInit();
    OSScreenShutdown();
}

Now the file can be simply linked against libcoreinit.

How do I know the return/argument types of a function?

Reverse engineering.
All system libraries can be dumped from your console (TODO: add path) or downloaded from the NUS (title id 00050010-1000400A) with any NUS Downloader.
Downloading via JNUSTool: java -jar JNUSTool.jar 000500101000400A -file .*, bring your own common key.

The .rpl files can be converted to standard elf with rplf2elf.

There are also rpx/rpl plugin for IDA, these allow you to use them without converting to standard elf:

For most cases it’s enough to let the loader resolve any library usages, but you may want to load any extra (optional?) libraries during runtime.

The following example code shows how load a system library (“gx2.rpl”, the library used for graphics).

OSDynLoad_Module gx2ModuleHandle;
OSDynLoad_Error error = OSDynLoad_Acquire("gx2.rpl", &gx2ModuleHandle);
if(error != OS_DYNLOAD_OK){
   // Error while loading
}

The OSDynLoad_Acquire will try to find a gx2.rpl. The system library path and the code folder of the currently running application are checked. On success, the library will be loaded into memory and the pointer module handler (gx2ModuleHandle) will be filled.
This handle can be used to get functions pointers (from the .export section) of library.

void (* GX2Init)();
OSDynLoad_FindExport(coreinit_handle, 0, "GX2Init", &GX2Init);

Now the function GX2Init can be used.

Notice: This was a really oversimplified example, you might take a look at the dynamic_libs.
For more information checkout the dynload functions