From d60b046bf362fcc9332f463823e8d02147d516de Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Thu, 23 Dec 2021 23:20:12 +0100 Subject: Remove PSN00BSDK_LIBS leftovers, improve CI artifact upload --- examples/system/childexec/CMakeLists.txt | 4 ---- examples/system/console/CMakeLists.txt | 4 ---- examples/system/dynlink/CMakeLists.txt | 4 ---- examples/system/timer/CMakeLists.txt | 4 ---- examples/system/tty/CMakeLists.txt | 4 ---- 5 files changed, 20 deletions(-) (limited to 'examples/system') diff --git a/examples/system/childexec/CMakeLists.txt b/examples/system/childexec/CMakeLists.txt index 88168e0..ca0c110 100644 --- a/examples/system/childexec/CMakeLists.txt +++ b/examples/system/childexec/CMakeLists.txt @@ -3,10 +3,6 @@ cmake_minimum_required(VERSION 3.20) -if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS}) - set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake) -endif() - project( childexec LANGUAGES C ASM diff --git a/examples/system/console/CMakeLists.txt b/examples/system/console/CMakeLists.txt index 6dc6154..d58f212 100644 --- a/examples/system/console/CMakeLists.txt +++ b/examples/system/console/CMakeLists.txt @@ -3,10 +3,6 @@ cmake_minimum_required(VERSION 3.20) -if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS}) - set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake) -endif() - project( console LANGUAGES C diff --git a/examples/system/dynlink/CMakeLists.txt b/examples/system/dynlink/CMakeLists.txt index 5834647..aae3bb3 100644 --- a/examples/system/dynlink/CMakeLists.txt +++ b/examples/system/dynlink/CMakeLists.txt @@ -3,10 +3,6 @@ cmake_minimum_required(VERSION 3.20) -if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS}) - set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake) -endif() - project( dynlink LANGUAGES C diff --git a/examples/system/timer/CMakeLists.txt b/examples/system/timer/CMakeLists.txt index 58daf9b..328e07e 100644 --- a/examples/system/timer/CMakeLists.txt +++ b/examples/system/timer/CMakeLists.txt @@ -3,10 +3,6 @@ cmake_minimum_required(VERSION 3.20) -if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS}) - set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake) -endif() - project( timer LANGUAGES C diff --git a/examples/system/tty/CMakeLists.txt b/examples/system/tty/CMakeLists.txt index 4e0ca36..0664502 100644 --- a/examples/system/tty/CMakeLists.txt +++ b/examples/system/tty/CMakeLists.txt @@ -3,10 +3,6 @@ cmake_minimum_required(VERSION 3.20) -if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS}) - set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake) -endif() - project( tty LANGUAGES C -- cgit v1.2.3 From ba03884e3d52d47a4fa1b474ca7dc6b419ee6898 Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Thu, 30 Dec 2021 14:56:55 +0100 Subject: Refactor dynamic linker API, fix system/dynlink example --- examples/system/dynlink/display.c | 74 ----------------- examples/system/dynlink/main.c | 148 +++++++++++++++++++++++++++------ libpsn00b/include/dlfcn.h | 101 ++++++++++++---------- libpsn00b/psxetc/_dl_resolve_wrapper.s | 8 +- libpsn00b/psxetc/dl.c | 51 +++++------- 5 files changed, 207 insertions(+), 175 deletions(-) delete mode 100644 examples/system/dynlink/display.c (limited to 'examples/system') diff --git a/examples/system/dynlink/display.c b/examples/system/dynlink/display.c deleted file mode 100644 index 573f17c..0000000 --- a/examples/system/dynlink/display.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * PSn00bSDK dynamic linker example (utilities) - * (C) 2021 spicyjpeg - MPL licensed - */ - -#include - -#include "library/dll_common.h" - -#define SCREEN_XRES 320 -#define SCREEN_YRES 240 - -#define BGCOLOR_R 48 -#define BGCOLOR_G 24 -#define BGCOLOR_B 0 - -/* Display/GPU context utilities */ - -void init_context(CONTEXT *ctx) { - DB *db; - - ResetGraph(0); - ctx->xres = SCREEN_XRES; - ctx->yres = SCREEN_YRES; - ctx->db_active = 0; - - db = &(ctx->db[0]); - SetDefDispEnv(&(db->disp), 0, 0, SCREEN_XRES, SCREEN_YRES); - SetDefDrawEnv(&(db->draw), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES); - setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); - db->draw.isbg = 1; - db->draw.dtd = 1; - - db = &(ctx->db[1]); - SetDefDispEnv(&(db->disp), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES); - SetDefDrawEnv(&(db->draw), 0, 0, SCREEN_XRES, SCREEN_YRES); - setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); - db->draw.isbg = 1; - db->draw.dtd = 1; - - // Set up the ordering tables and primitive buffers. - db = &(ctx->db[0]); - ctx->db_nextpri = db->p; - ClearOTagR((u_long *) db->ot, OT_LEN); - - PutDrawEnv(&(db->draw)); - //PutDispEnv(&(db->disp)); - - db = &(ctx->db[1]); - ClearOTagR((u_long *) db->ot, OT_LEN); - - // Create a text stream at the top of the screen. - FntLoad(960, 0); - FntOpen(4, 12, 312, 32, 2, 256); -} - -void display(CONTEXT *ctx) { - DB *db; - - DrawSync(0); - VSync(0); - ctx->db_active ^= 1; - - db = &(ctx->db[ctx->db_active]); - ctx->db_nextpri = db->p; - ClearOTagR((u_long *) db->ot, OT_LEN); - - PutDrawEnv(&(db->draw)); - PutDispEnv(&(db->disp)); - SetDispMask(1); - - db = &(ctx->db[!ctx->db_active]); - DrawOTag((u_long *) &(db->ot[OT_LEN - 1])); -} diff --git a/examples/system/dynlink/main.c b/examples/system/dynlink/main.c index 6d93e71..690371e 100644 --- a/examples/system/dynlink/main.c +++ b/examples/system/dynlink/main.c @@ -11,14 +11,14 @@ * however this may be expanded in the future. * * Being able to introspect local symbols at runtime, in turn, allows us to use - * the dl*() set of APIs to load, link and execute code from an external file + * another set of APIs to load, link and execute code from an external file * (compiled with the dll.ld linker script). A dynamically-loaded library can * reference and access any non-static function or variable within the main * executable (and the libraries the main executable has been compiled with); * the dynamic linker will automatically patch the DLL's code and resolve these * references so that they point to the addresses listed in the map file. DLLs * also have their own symbol tables, and any symbol in a DLL is accessible to - * the main executable through dlsym(). + * the main executable through DL_GetDLLSymbol(). * * This example shows how DLLs can be loaded and unloaded at any time. Pressing * START will unload the current DLL and load an alternate one on-the-fly. A @@ -47,6 +47,7 @@ #include #include #include +#include #include "library/dll_common.h" @@ -67,14 +68,77 @@ const void *const DO_NOT_STRIP[] __attribute__((section(".dummy"))) = { }; static const char *const DLL_FILENAMES[] = { - "cdrom:CUBE.DLL;1", - "cdrom:BALLS.DLL;1" + "\\CUBE.DLL;1", + "\\BALLS.DLL;1" }; #define DLL_COUNT 2 -void init_context(CONTEXT *ctx); -void display(CONTEXT *ctx); +/* Display/GPU context utilities */ + +#define SCREEN_XRES 320 +#define SCREEN_YRES 240 + +#define BGCOLOR_R 48 +#define BGCOLOR_G 24 +#define BGCOLOR_B 0 + +void init_context(CONTEXT *ctx) { + DB *db; + + ResetGraph(0); + ctx->xres = SCREEN_XRES; + ctx->yres = SCREEN_YRES; + ctx->db_active = 0; + + db = &(ctx->db[0]); + SetDefDispEnv(&(db->disp), 0, 0, SCREEN_XRES, SCREEN_YRES); + SetDefDrawEnv(&(db->draw), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES); + setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); + db->draw.isbg = 1; + db->draw.dtd = 1; + + db = &(ctx->db[1]); + SetDefDispEnv(&(db->disp), SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES); + SetDefDrawEnv(&(db->draw), 0, 0, SCREEN_XRES, SCREEN_YRES); + setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); + db->draw.isbg = 1; + db->draw.dtd = 1; + + // Set up the ordering tables and primitive buffers. + db = &(ctx->db[0]); + ctx->db_nextpri = db->p; + ClearOTagR((u_long *) db->ot, OT_LEN); + + PutDrawEnv(&(db->draw)); + //PutDispEnv(&(db->disp)); + + db = &(ctx->db[1]); + ClearOTagR((u_long *) db->ot, OT_LEN); + + // Create a text stream at the top of the screen. + FntLoad(960, 0); + FntOpen(4, 12, 312, 32, 2, 256); +} + +void display(CONTEXT *ctx) { + DB *db; + + DrawSync(0); + VSync(0); + ctx->db_active ^= 1; + + db = &(ctx->db[ctx->db_active]); + ctx->db_nextpri = db->p; + ClearOTagR((u_long *) db->ot, OT_LEN); + + PutDrawEnv(&(db->draw)); + PutDispEnv(&(db->disp)); + SetDispMask(1); + + db = &(ctx->db[!ctx->db_active]); + DrawOTag((u_long *) &(db->ot[OT_LEN - 1])); +} /* Symbol overriding example */ @@ -118,8 +182,8 @@ void *custom_resolver(DLL *dll, const char *name) { // Define a struct to store pointers to a DLL's functions into. This is not // strictly required, however looking up symbols is a relatively slow operation -// and the pointers returned by dlsym() should be saved and reused as much as -// possible. +// and the pointers returned by DL_GetDLLSymbol() should be saved and reused as +// much as possible. typedef struct { void (*init)(CONTEXT *); void (*render)(CONTEXT *, uint16_t buttons); @@ -134,47 +198,79 @@ static CONTEXT ctx; #define SHOW_STATUS(...) { FntPrint(-1, __VA_ARGS__); FntFlush(-1); display(&ctx); } #define SHOW_ERROR(...) { SHOW_STATUS(__VA_ARGS__); while (1) __asm__("nop"); } +// This is a simple function to read a CD-ROM file into memory (the dynamic +// linker no longer provides APIs that take file paths directly). You might +// want to replace this with code that e.g. loads the DLL from a compressed +// archive or even from the serial port. +size_t load_file(const char *filename, void **ptr) { + SHOW_STATUS("LOADING %s\n", filename); + + CdlFILE file; + if (!CdSearchFile(&file, filename)) + SHOW_ERROR("FAILED TO FIND %s\n", filename); + + // Round up the file size so it matches the number of sectors occupied by + // the file (as CdRead() can only return entire sectors). + size_t len = (file.size + 2047) & 0xfffff800; + void *_ptr = malloc(len); + if (!_ptr) + SHOW_ERROR("FAILED TO ALLOCATE %d BYTES\n", len); + + CdControl(CdlSetloc, &(file.pos), 0); + CdRead(len / 2048, _ptr, CdlModeSpeed); + if (CdReadSync(0, 0) < 0) + SHOW_ERROR("FAILED TO READ %s\n", filename); + + *ptr = _ptr; + return file.size; +} + void load_dll(const char *filename) { + // As we're passing RTLD_FREE_ON_DESTROY to DL_CreateDLL(), calling + // DL_DestroyDLL() will also deallocate the buffer the DLL was loaded into. if (dll) - dlclose(dll); + DL_DestroyDLL(dll); - SHOW_STATUS("LOADING %s\n", filename); + void *ptr; + size_t len = load_file(filename, &ptr); - dll = dlopen(filename, RTLD_LAZY); + dll = DL_CreateDLL(ptr, len, RTLD_LAZY | RTLD_FREE_ON_DESTROY); if (!dll) - SHOW_ERROR("FAILED TO LOAD %s\nERROR=%d\n", filename, (int32_t) dlerror()); + SHOW_ERROR("FAILED TO PARSE %s\nERROR=%d\n", filename, (int32_t) DL_GetLastError()); - dll_api.init = dlsym(dll, "init"); - dll_api.render = dlsym(dll, "render"); + dll_api.init = DL_GetDLLSymbol(dll, "init"); + dll_api.render = DL_GetDLLSymbol(dll, "render"); printf("DLL init() @ %08x, render() @ %08x\n", dll_api.init, dll_api.render); // Unfortunately, due to how position-independent code works, function - // pointers returned by dlsym() can't be called directly. We have to use - // the DL_CALL() macro instead, which sets up register $t9 to ensure the - // function can locate and reference the DLL's relocation table. + // pointers returned by DL_GetDLLSymbol() can't be called directly. We have + // to use the DL_CALL() macro instead, which sets up register $t9 to ensure + // the function can locate and reference the DLL's relocation table. DL_CALL(dll_api.init, &ctx); } int main(int argc, const char* argv[]) { - // As DL_LoadSymbolMap() and dlopen() rely on BIOS file APIs, the BIOS CD - // driver must be initialized by calling _InitCd() prior to loading the - // symbol map (but after setting up the GPU, for some reason). init_context(&ctx); SHOW_STATUS("INITIALIZING CD\n"); - _InitCd(); + CdInit(); + + // Load the symbol map file, let the dynamic linker parse it and then + // unload it. + void *ptr; + size_t len = load_file("\\MAIN.MAP;1", &ptr); - SHOW_STATUS("LOADING SYMBOL MAP\n"); + if (!DL_ParseSymbolMap(ptr, len)) + SHOW_ERROR("FAILED TO PARSE SYMBOL MAP\nERROR=%d\n", (int32_t) DL_GetLastError()); - if (!DL_LoadSymbolMap("cdrom:MAIN.MAP;1")) - SHOW_ERROR("FAILED TO LOAD SYMBOL MAP\nERROR=%d\n", (int32_t) dlerror()); + free(ptr); // Try to obtain a reference to a local function. void (*_display)() = DL_GetSymbolByName("display"); if (!_display) - SHOW_ERROR("FAILED TO LOOK UP LOCAL FUNCTION\nERROR=%d\n", (int32_t) dlerror()); + SHOW_ERROR("FAILED TO LOOK UP LOCAL FUNCTION\nERROR=%d\n", (int32_t) DL_GetLastError()); printf("Symbol map test, display() @ %08x\n", _display); @@ -220,7 +316,7 @@ int main(int argc, const char* argv[]) { last_buttons = pad->btn; } - //dlclose(dll); + //DL_DestroyDLL(dll); //DL_UnloadSymbolMap(); return 0; } diff --git a/libpsn00b/include/dlfcn.h b/libpsn00b/include/dlfcn.h index b3a5cec..6874d06 100644 --- a/libpsn00b/include/dlfcn.h +++ b/libpsn00b/include/dlfcn.h @@ -21,39 +21,39 @@ #define RTLD_DEFAULT ((DLL *) 0) typedef enum _DL_Error { - RTLD_E_NONE = 0, // No error - RTLD_E_FILE_OPEN = 1, // Unable to find or open file - RTLD_E_FILE_ALLOC = 2, // Unable to allocate buffer to load file into - RTLD_E_FILE_READ = 3, // Failed to read file - RTLD_E_NO_MAP = 4, // No symbol map has been loaded yet - RTLD_E_MAP_ALLOC = 5, // Unable to allocate symbol map structures - RTLD_E_NO_SYMBOLS = 6, // No symbols found in symbol map - RTLD_E_DLL_NULL = 7, // Unable to initialize DLL from null pointer - RTLD_E_DLL_ALLOC = 8, // Unable to allocate DLL metadata structures - RTLD_E_DLL_FORMAT = 9, // Unsupported DLL type or format - RTLD_E_NO_FILE_API = 10, // psxetc has been built without file support - RTLD_E_MAP_SYMBOL = 11, // Symbol not found in symbol map - RTLD_E_DLL_SYMBOL = 12, // Symbol not found in DLL - RTLD_E_HASH_LOOKUP = 13 // Hash table lookup failed due to internal error + RTLD_E_NONE = 0, // No error + RTLD_E_FILE_OPEN = 1, // Unable to find or open file + RTLD_E_FILE_ALLOC = 2, // Unable to allocate buffer to load file into + RTLD_E_FILE_READ = 3, // Failed to read file + RTLD_E_NO_MAP = 4, // No symbol map has been loaded yet + RTLD_E_MAP_ALLOC = 5, // Unable to allocate symbol map structures + RTLD_E_NO_SYMBOLS = 6, // No symbols found in symbol map + RTLD_E_DLL_NULL = 7, // Unable to initialize DLL from null pointer + RTLD_E_DLL_ALLOC = 8, // Unable to allocate DLL metadata structures + RTLD_E_DLL_FORMAT = 9, // Unsupported DLL type or format + RTLD_E_MAP_SYMBOL = 10, // Symbol not found in symbol map + RTLD_E_DLL_SYMBOL = 11, // Symbol not found in DLL + RTLD_E_HASH_LOOKUP = 12 // Hash table lookup failed due to internal error } DL_Error; typedef enum _DL_ResolveMode { - RTLD_LAZY = 1, // Resolve functions when they are first called (default) - RTLD_NOW = 2 // Resolve all symbols immediately on load + RTLD_LAZY = 1, // Resolve functions when they are first called (default) + RTLD_NOW = 2, // Resolve all symbols immediately on load + RTLD_FREE_ON_DESTROY = 4 // Automatically free DLL buffer when closing DLL } DL_ResolveMode; // Members of this struct should not be accessed directly in most cases, but // they are intentionally exposed for easier expandability. typedef struct _DLL { - void *ptr; - void *malloc_ptr; - size_t size; - const uint32_t *hash; - uint32_t *got; - Elf32_Sym *symtab; - const char *strtab; - uint16_t symbol_count; - uint16_t got_length; + void *ptr; + void *malloc_ptr; + size_t size; + const uint32_t *hash; + uint32_t *got; + Elf32_Sym *symtab; + const char *strtab; + uint16_t symbol_count; + uint16_t got_length; } DLL; /* API */ @@ -62,8 +62,6 @@ typedef struct _DLL { extern "C" { #endif -// TODO: rewrite these javadoc comments into proper documentation - /** * @brief Reads the symbol table from the provided string buffer (which may or * may not be null-terminated), parses it and stores the parsed entries into a @@ -80,13 +78,14 @@ extern "C" { * file in the appropriate format after building the executable, by using this * command: * - * mipsel-unknown-elf-nm -f posix -l -n executable.elf >executable.map + * mipsel-none-elf-nm -f posix -l -n executable.elf >executable.map * * @param ptr * @param size * @return -1 or number of entries parsed */ int32_t DL_ParseSymbolMap(const char *ptr, size_t size); + /** * @brief File wrapper around DL_ParseSymbolMap(). Allocates a temporary buffer * then loads the specified map file into it (using BIOS APIs) and calls @@ -96,14 +95,16 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size); * @param filename Must always contain device name, e.g. "cdrom:MODULE.DLL;1" * @return -1 or number of entries parsed */ -int32_t DL_LoadSymbolMap(const char *filename); +//int32_t DL_LoadSymbolMapFromFile(const char *filename); + /** * @brief Frees internal buffers containing the currently loaded symbol map. * This is automatically done before loading a new symbol map so there is no * need to call this function in most cases, however it can still be useful to * free up space on the heap once the symbol map is no longer needed. */ -void DL_UnloadSymbolMap(void); +void DL_UnloadSymbolMap(void); + /** * @brief Queries the currently loaded symbol map for the symbol with the given * name and returns a pointer to it, which can then be used to directly access @@ -112,7 +113,8 @@ void DL_UnloadSymbolMap(void); * @param name * @return NULL or pointer to symbol (any type) */ -void *DL_GetSymbolByName(const char *name); +void *DL_GetSymbolByName(const char *name); + /** * @brief Sets a custom function to be called for resolving symbols in DLLs. * The function will be given a pointer to the current DLL and the unresolved @@ -123,7 +125,7 @@ void *DL_GetSymbolByName(const char *name); * * @param callback NULL or pointer to callback function */ -void DL_SetResolveCallback(void *(*callback)(DLL *, const char *)); +void DL_SetResolveCallback(void *(*callback)(DLL *, const char *)); /** * @brief Initializes a buffer holding the contents of a dynamically-loaded @@ -131,8 +133,8 @@ void DL_SetResolveCallback(void *(*callback)(DLL *, const char *)); * binary) *in-place*. A new DLL struct is allocated to store metadata but, * unlike DL_ParseSymbolMap(), the DLL's actual code, data and tables are * referenced directly from the provided buffer. The buffer must not be moved - * or deallocated, at least not before calling dlclose() on the DLL struct - * returned by this function. + * or deallocated, at least not before calling DL_DestroyDLL() on the DLL + * struct returned by this function. * * The third argument specifies when symbols in the DLL should be resolved. * Setting it to RTLD_LAZY defers resolution of undefined functions to when @@ -145,7 +147,8 @@ void DL_SetResolveCallback(void *(*callback)(DLL *, const char *)); * @param mode RTLD_LAZY or RTLD_NOW * @return NULL or pointer to a new DLL struct */ -DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode); +DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode); + /** * @brief File wrapper around dlinit(). Allocates a new buffer, loads the * specified file into it (using BIOS APIs) and calls dlinit() on that. When @@ -153,19 +156,22 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode); * automatically destroyed. * * @param filename Must always contain device name, e.g. "cdrom:MODULE.DLL;1" - * @param mode RTLD_LAZY or RTLD_NOW + * @param mode RTLD_LAZY or RTLD_NOW + optionally RTLD_FREE_ON_DESTROY * @return NULL or pointer to a new DLL struct */ -DLL *dlopen(const char *filename, DL_ResolveMode mode); +//DLL *DL_LoadDLLFromFile(const char *filename, DL_ResolveMode mode); + /** * @brief Destroys a loaded DLL by calling its global destructors and freeing - * the buffer it's loaded in. Any pointer passed to dlclose() should no longer - * be used after the call. If the DLL was initialized in-place using dlinit(), - * dlclose() will *NOT* free the buffer initially passed to dlinit(). + * the buffer it's loaded in. Any pointer passed to DL_DestroyDLL() should no + * longer be used after the call. If the DLL was initialized in-place using + * DL_CreateDLL(), DL_DestroyDLL() will only free the buffer initially passed + * to DL_CreateDLL() if RTLD_FREE_ON_DESTROY was used. * * @param dll */ -void dlclose(DLL *dll); +void DL_DestroyDLL(DLL *dll); + /** * @brief Returns a pointer to the DLL symbol with the given name, or null if * it can't be found. If null or RTLD_DEFAULT is passed as first argument, the @@ -176,7 +182,8 @@ void dlclose(DLL *dll); * @param name * @return NULL or pointer to symbol (any type) */ -void *dlsym(DLL *dll, const char *name); +void *DL_GetDLLSymbol(const DLL *dll, const char *name); + /** * @brief Returns a code describing the last error that occurred, or DL_E_NONE * if no error has occurred since the last call to dlerror() (i.e. calling this @@ -184,7 +191,15 @@ void *dlsym(DLL *dll, const char *name); * * @return NULL or member of DL_Error enum */ -DL_Error dlerror(void); +DL_Error DL_GetLastError(void); + +/* POSIX "compatibility" macros */ + +#define dlinit(ptr, size, mode) DL_CreateDLL(ptr, size, mode) +//#define dlopen(filename, mode) DL_LoadDLLFromFile(filename, mode) +#define dlsym(dll, name) DL_GetDLLSymbol(dll, name) +#define dlclose(dll) DL_DestroyDLL(dll) +#define dlerror() DL_GetLastError() #ifdef __cplusplus } diff --git a/libpsn00b/psxetc/_dl_resolve_wrapper.s b/libpsn00b/psxetc/_dl_resolve_wrapper.s index 069ee84..7f1132b 100644 --- a/libpsn00b/psxetc/_dl_resolve_wrapper.s +++ b/libpsn00b/psxetc/_dl_resolve_wrapper.s @@ -4,7 +4,7 @@ # This function is called by the lazy loader stubs generated by GCC in the # .plt/.MIPS.stubs section when attempting to call a GOT entry whose address # hasn't yet been resolved. The generated stubs conform to the MIPS ABI and -# uses the following registers to pass the following parameters: +# uses the following registers: # - $t7 = address the resolved function should return to (i.e. $ra of the # caller that triggered the stub) # - $t8 = index of the function in the .dynsym symbol table @@ -25,13 +25,13 @@ _dl_resolve_wrapper: # Figure out where the DLL's struct is. dlinit() places a pointer to the # struct in the second GOT entry, so it's just a matter of indexing the GOT - # using GP. Then call _dl_resolve_helper with the struct and $t8 as + # using $gp. Then call _dl_resolve_helper with the struct and $t8 as # arguments, and store the return value into $t0. - lw $a0, -0x7fec($gp) # sizeof(uint32_t) - 0x7ff0 (see dll.ld) + lw $a0, -0x7fec($gp) # (DLL *) sizeof(uint32_t) - 0x7ff0 [see dll.ld] move $a1, $t8 jal _dl_resolve_helper - addiu $sp, -8 # (branch delay) + addiu $sp, -8 addiu $sp, 8 move $t0, $v0 diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c index e43374f..cbdcb66 100644 --- a/libpsn00b/psxetc/dl.c +++ b/libpsn00b/psxetc/dl.c @@ -38,8 +38,9 @@ //#define DEBUG // Comment before building to disable functions that rely on BIOS file APIs, -// i.e. DL_LoadSymbolMap() and dlopen(). -#define USE_FILE_API +// i.e. DL_LoadSymbolMapFromFile() and DL_LoadDLLFromFile(). +// FIXME: those seem to be broken currently, and shouldn't be used anyway +//#define USE_FILE_API /* Private types */ @@ -132,7 +133,7 @@ static uint32_t _elf_hash(const char *str) { } #ifdef USE_FILE_API -static uint8_t *_load_file(const char *filename, size_t *size_output) { +static uint8_t *_dl_load_file(const char *filename, size_t *size_output) { int32_t fd = open(filename, 1); if (fd < 0) { _LOG("psxetc: Can't open %s, error = %d\n", filename, fd); @@ -286,10 +287,10 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) { return entries; } -int32_t DL_LoadSymbolMap(const char *filename) { #ifdef USE_FILE_API +int32_t DL_LoadSymbolMapFromFile(const char *filename) { size_t size; - char *ptr = _load_file(filename, &size); + char *ptr = _dl_load_file(filename, &size); if (!ptr) return -1; @@ -297,10 +298,8 @@ int32_t DL_LoadSymbolMap(const char *filename) { free(ptr); return entries; -#else - _ERROR(RTLD_E_NO_FILE_API, -1); -#endif } +#endif void DL_UnloadSymbolMap(void) { if (!_symbol_map.entries) @@ -354,7 +353,7 @@ void DL_SetResolveCallback(void *(*callback)(DLL *, const char *)) { /* Library loading and linking API */ -DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) { +DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) { if (!ptr) _ERROR(RTLD_E_DLL_NULL, 0); @@ -365,7 +364,7 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) { } dll->ptr = ptr; - dll->malloc_ptr = 0; + dll->malloc_ptr = (mode & RTLD_FREE_ON_DESTROY) ? ptr : 0; dll->size = size; _LOG("psxetc: Initializing DLL at %08x\n", ptr); @@ -548,7 +547,7 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) { // If RTLD_NOW was passed, resolve GOT entries ahead of time by // cross-referencing them with the symbol table. - if (mode != RTLD_NOW) + if (!(mode & RTLD_NOW)) continue; for (uint32_t j = got_offset; j < dll->got_length; j++) { @@ -584,7 +583,7 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) { // _start() for regular executables, but we have to do it outside of the // DLL as there's no _start() or even a defined entry point within the // DLL itself. - const uint32_t *ctor_list = dlsym(dll, "__CTOR_LIST__"); + const uint32_t *ctor_list = DL_GetDLLSymbol(dll, "__CTOR_LIST__"); if (ctor_list) { for (uint32_t i = ((uint32_t) ctor_list[0]); i >= 1; i--) { void (*ctor)(void) = (void (*)(void)) ctor_list[i]; @@ -595,32 +594,28 @@ DLL *dlinit(void *ptr, size_t size, DL_ResolveMode mode) { return dll; } -DLL *dlopen(const char *filename, DL_ResolveMode mode) { #ifdef USE_FILE_API +DLL *DL_LoadDLLFromFile(const char *filename, DL_ResolveMode mode) { size_t size; - char *ptr = _load_file(filename, &size); + char *ptr = _dl_load_file(filename, &size); if (!ptr) return 0; - DLL *dll = dlinit(ptr, size, mode); - if (dll) - dll->malloc_ptr = dll->ptr; - else + DLL *dll = DL_CreateDLL(ptr, size, mode | RTLD_FREE_ON_DESTROY); + if (!dll) free(ptr); return dll; -#else - _ERROR(RTLD_E_NO_FILE_API, 0); -#endif } +#endif -void dlclose(DLL *dll) { +void DL_DestroyDLL(DLL *dll) { if (dll == RTLD_DEFAULT) return; if (dll->ptr) { // Call the DLL's global destructors. - const uint32_t *dtor_list = dlsym(dll, "__DTOR_LIST__"); + const uint32_t *dtor_list = DL_GetDLLSymbol(dll, "__DTOR_LIST__"); if (dtor_list) { for (uint32_t i = 0; i < ((uint32_t) dtor_list[0]); i++) { void (*dtor)(void) = (void (*)(void)) dtor_list[i + 1]; @@ -629,15 +624,15 @@ void dlclose(DLL *dll) { } } - // If the DLL is associated to a buffer allocated by dlopen(), free that - // buffer. + // If the DLL is associated to a buffer allocated by DL_LoadDLLFromFile(), + // free that buffer. if (dll->malloc_ptr) free(dll->malloc_ptr); free(dll); } -void *dlsym(DLL *dll, const char *name) { +void *DL_GetDLLSymbol(const DLL *dll, const char *name) { if (dll == RTLD_DEFAULT) return DL_GetSymbolByName(name); //return _dl_resolve_callback(RTLD_DEFAULT, name); @@ -654,7 +649,7 @@ void *dlsym(DLL *dll, const char *name) { // provided. for (uint32_t i = bucket[hash_mod]; i != 0xffffffff;) { if (i >= nchain) { - _LOG("psxetc: dlsym() index out of bounds (i = %d, n = %d)\n", i, nchain); + _LOG("psxetc: DL_GetDLLSymbol() index out of bounds (i = %d, n = %d)\n", i, nchain); _ERROR(RTLD_E_HASH_LOOKUP, 0); } @@ -673,7 +668,7 @@ void *dlsym(DLL *dll, const char *name) { _ERROR(RTLD_E_DLL_SYMBOL, 0); } -DL_Error dlerror(void) { +DL_Error DL_GetLastError(void) { DL_Error last = _error_code; _error_code = RTLD_E_NONE; -- cgit v1.2.3