#pragma once #include #include "thread.h" #include "time.h" /** * \defgroup coreinit_dynload Dynamic Loading * \ingroup coreinit * @{ */ #ifdef __cplusplus extern "C" { #endif typedef struct OSDynLoad_NotifyData OSDynLoad_NotifyData; typedef struct OSDynLoad_LoaderHeapStatistics OSDynLoad_LoaderHeapStatistics; typedef void *OSDynLoad_Module; typedef struct OSDynLoad_LoaderUserFileInfo OSDynLoad_LoaderUserFileInfo; typedef struct OSDynLoad_LoaderSectionInfo OSDynLoad_LoaderSectionInfo; typedef struct OSDynLoad_InternalData OSDynLoad_InternalData; typedef enum OSDynLoad_Error { OS_DYNLOAD_OK = 0, OS_DYNLOAD_OUT_OF_MEMORY = 0xBAD10002, OS_DYNLOAD_INVALID_NOTIFY_PTR = 0xBAD1000E, OS_DYNLOAD_INVALID_MODULE_NAME_PTR = 0xBAD1000F, OS_DYNLOAD_INVALID_MODULE_NAME = 0xBAD10010, OS_DYNLOAD_INVALID_ACQUIRE_PTR = 0xBAD10011, OS_DYNLOAD_EMPTY_MODULE_NAME = 0xBAD10012, OS_DYNLOAD_INVALID_ALLOCATOR_PTR = 0xBAD10017, OS_DYNLOAD_OUT_OF_SYSTEM_MEMORY = 0xBAD1002F, OS_DYNLOAD_TLS_ALLOCATOR_LOCKED = 0xBAD10031, OS_DYNLOAD_MODULE_NOT_FOUND = 0xFFFFFFFA, } OSDynLoad_Error; typedef OSDynLoad_Error (*OSDynLoadAllocFn)(int32_t size, int32_t align, void **outAddr); typedef void (*OSDynLoadFreeFn)(void *addr); typedef enum OSDynLoad_ExportType { OS_DYNLOAD_EXPORT_FUNC = 0, OS_DYNLOAD_EXPORT_DATA = 1, } OSDynLoad_ExportType; typedef enum OSDynLoad_EntryReason { OS_DYNLOAD_LOADED = 1, OS_DYNLOAD_UNLOADED = 2, } OSDynLoad_EntryReason; struct OSDynLoad_NotifyData { char *name; uint32_t textAddr; uint32_t textOffset; uint32_t textSize; uint32_t dataAddr; uint32_t dataOffset; uint32_t dataSize; uint32_t readAddr; uint32_t readOffset; uint32_t readSize; }; WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x00, name); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x04, textAddr); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x08, textOffset); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x0C, textSize); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x10, dataAddr); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x14, dataOffset); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x18, dataSize); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x1C, readAddr); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x20, readOffset); WUT_CHECK_OFFSET(OSDynLoad_NotifyData, 0x24, readSize); WUT_CHECK_SIZE(OSDynLoad_NotifyData, 0x28); struct OSDynLoad_LoaderHeapStatistics { uint32_t codeHeapUsed; uint32_t unk_0x04; uint32_t codeHeapFree; uint32_t codeHeapLargestFree; uint32_t dataHeapUsed; uint32_t unk_0x14; }; WUT_CHECK_OFFSET(OSDynLoad_LoaderHeapStatistics, 0x00, codeHeapUsed); WUT_CHECK_OFFSET(OSDynLoad_LoaderHeapStatistics, 0x04, unk_0x04); WUT_CHECK_OFFSET(OSDynLoad_LoaderHeapStatistics, 0x08, codeHeapFree); WUT_CHECK_OFFSET(OSDynLoad_LoaderHeapStatistics, 0x0C, codeHeapLargestFree); WUT_CHECK_OFFSET(OSDynLoad_LoaderHeapStatistics, 0x10, dataHeapUsed); WUT_CHECK_OFFSET(OSDynLoad_LoaderHeapStatistics, 0x14, unk_0x14); WUT_CHECK_SIZE(OSDynLoad_LoaderHeapStatistics, 0x18); struct OSDynLoad_LoaderUserFileInfo { uint32_t size; uint32_t magic; uint32_t pathStringLength; char *pathString; uint32_t fileInfoFlags; int16_t tlsModuleIndex; int16_t tlsAlignShift; void *tlsAddressStart; uint32_t tlsSectionSize; uint32_t shstrndx; uint32_t titleLocation; WUT_UNKNOWN_BYTES(0x60 - 0x28); }; WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x00, size); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x04, magic); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x08, pathStringLength); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x0C, pathString); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x10, fileInfoFlags); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x14, tlsModuleIndex); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x16, tlsAlignShift); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x18, tlsAddressStart); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x1C, tlsSectionSize); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x20, shstrndx); WUT_CHECK_OFFSET(OSDynLoad_LoaderUserFileInfo, 0x24, titleLocation); WUT_CHECK_SIZE(OSDynLoad_LoaderUserFileInfo, 0x60); struct OSDynLoad_LoaderSectionInfo { uint32_t type; uint32_t flags; void *address; union { //! Size of the section, set when type != SHT_RPL_IMPORTS uint32_t size; //! Name offset of the section, set when type == SHT_RPL_IMPORTS uint32_t name; }; }; WUT_CHECK_OFFSET(OSDynLoad_LoaderSectionInfo, 0x00, type); WUT_CHECK_OFFSET(OSDynLoad_LoaderSectionInfo, 0x04, flags); WUT_CHECK_OFFSET(OSDynLoad_LoaderSectionInfo, 0x08, address); WUT_CHECK_OFFSET(OSDynLoad_LoaderSectionInfo, 0x0C, size); WUT_CHECK_OFFSET(OSDynLoad_LoaderSectionInfo, 0x0C, name); WUT_CHECK_SIZE(OSDynLoad_LoaderSectionInfo, 0x10); struct OSDynLoad_InternalData { uint32_t handle; void *loaderHandle; char *moduleName; uint32_t moduleNameLen; uint32_t sectionInfoCount; OSDynLoad_LoaderSectionInfo *sectionInfo; OSDynLoad_InternalData **importModules; uint32_t importModuleCount; uint32_t userFileInfoSize; OSDynLoad_LoaderUserFileInfo *userFileInfo; OSDynLoad_NotifyData *notifyData; void *entryPoint; uint32_t dataSectionSize; void *dataSection; uint32_t loadSectionSize; void *loadSection; OSDynLoadFreeFn dynLoadFreeFn; void *codeExports; uint32_t numCodeExports; void *dataExports; uint32_t numDataExports; OSDynLoad_InternalData *next; WUT_UNKNOWN_BYTES(0x94 - 0x58); }; WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x00, handle); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x04, loaderHandle); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x08, moduleName); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x0C, moduleNameLen); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x10, sectionInfoCount); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x14, sectionInfo); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x18, importModules); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x1C, importModuleCount); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x20, userFileInfoSize); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x24, userFileInfo); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x28, notifyData); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x2C, entryPoint); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x30, dataSectionSize); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x34, dataSection); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x38, loadSectionSize); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x3C, loadSection); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x40, dynLoadFreeFn); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x44, codeExports); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x48, numCodeExports); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x4C, dataExports); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x50, numDataExports); WUT_CHECK_OFFSET(OSDynLoad_InternalData, 0x54, next); WUT_CHECK_SIZE(OSDynLoad_InternalData, 0x94); typedef enum OSDynLoad_NotifyReason { OS_DYNLOAD_NOTIFY_UNLOADED = 0, OS_DYNLOAD_NOTIFY_LOADED = 1 } OSDynLoad_NotifyReason; typedef void (*OSDynLoadNotifyFunc)(OSDynLoad_Module module, void *userContext, OSDynLoad_NotifyReason notifyReason, OSDynLoad_NotifyData *infos); /** * Load a module. * * If the module is already loaded, increase reference count. * Similar to LoadLibrary on Windows. */ OSDynLoad_Error OSDynLoad_Acquire(char const *name, OSDynLoad_Module *outModule); /** * Retrieve the address of a function or data export from a module. * * Similar to GetProcAddress on Windows. */ OSDynLoad_Error OSDynLoad_FindExport(OSDynLoad_Module module, OSDynLoad_ExportType exportType, char const *name, void **outAddr); /** * Free a module handle returned from OSDynLoad_Acquire. * * Will decrease reference count and only unload the module if count reaches 0. * Similar to FreeLibrary on Windows. */ void OSDynLoad_Release(OSDynLoad_Module module); /** * Set the allocator functions to use for dynamic loading. */ OSDynLoad_Error OSDynLoad_SetAllocator(OSDynLoadAllocFn allocFn, OSDynLoadFreeFn freeFn); /** * Get the allocator functions used for dynamic loading. */ OSDynLoad_Error OSDynLoad_GetAllocator(OSDynLoadAllocFn *outAllocFn, OSDynLoadFreeFn *outFreeFn); /** * Set the allocator functions to use for thread local storage. */ OSDynLoad_Error OSDynLoad_SetTLSAllocator(OSDynLoadAllocFn allocFn, OSDynLoadFreeFn freeFn); /** * Get the allocator functions used for thread local storage. */ OSDynLoad_Error OSDynLoad_GetTLSAllocator(OSDynLoadAllocFn *outAllocFn, OSDynLoadFreeFn *outFreeFn); /** * Get loader heap statistics. */ OSDynLoad_Error OSDynLoad_GetLoaderHeapStatistics(OSDynLoad_LoaderHeapStatistics *outLoaderHeapStatistics); /** * Gets the name for a given module handle. * Using the value "-1" as module handle gets the name of the running main rpl **/ OSDynLoad_Error OSDynLoad_GetModuleName(OSDynLoad_Module module, char *nameBuf, int32_t *nameBufSize); /** * Gets the number of currently loaded RPLs. * * Always returns 0 on release versions of CafeOS. * Requires OSGetSecurityLevel() > 0. */ int32_t OSDynLoad_GetNumberOfRPLs(); /** * Get information about the currently loaded RPLs. * * \param first the index of the first RPL to retrieve info for. * \param count the number of RPLs to retrieve info for * \param outInfos buffer of RPL info to be filled, should be an array of at * least count size. * * Always returns FALSE on release versions of CafeOS. * Requires OSGetSecurityLevel() > 0. */ BOOL OSDynLoad_GetRPLInfo(uint32_t first, uint32_t count, OSDynLoad_NotifyData *outInfos); /** * Checks if a module is already loaded. Does not load any modules. * * Returns OS_DYNLOAD_OK on success. **/ OSDynLoad_Error OSDynLoad_IsModuleLoaded(char const *name, OSDynLoad_Module *outModule); /** * Registers a callback that's called whenever a new .rpl is loaded or unloaded **/ OSDynLoad_Error OSDynLoad_AddNotifyCallback(OSDynLoadNotifyFunc notifyFn, void *userContext); /** * Removes a previously added a callback **/ OSDynLoad_Error OSDynLoad_DelNotifyCallback(OSDynLoadNotifyFunc notifyFn, void *userContext); /** * The prototype for an RPL entry point. * * Use this instead of main when creating .rpl files */ int rpl_entry(OSDynLoad_Module module, OSDynLoad_EntryReason reason); #ifdef __cplusplus } #endif /** @} */