aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorspicyjpeg <88942473+spicyjpeg@users.noreply.github.com>2021-12-30 14:56:55 +0100
committerspicyjpeg <88942473+spicyjpeg@users.noreply.github.com>2021-12-30 14:56:55 +0100
commitba03884e3d52d47a4fa1b474ca7dc6b419ee6898 (patch)
treea5e711b2bbc6980b8f06af21cca02a6823757168
parentfe42ce7f1c98947baa49427835deb5ce70470afb (diff)
downloadpsn00bsdk-ba03884e3d52d47a4fa1b474ca7dc6b419ee6898.tar.gz
Refactor dynamic linker API, fix system/dynlink example
-rw-r--r--examples/system/dynlink/display.c74
-rw-r--r--examples/system/dynlink/main.c148
-rw-r--r--libpsn00b/include/dlfcn.h101
-rw-r--r--libpsn00b/psxetc/_dl_resolve_wrapper.s8
-rw-r--r--libpsn00b/psxetc/dl.c51
5 files changed, 207 insertions, 175 deletions
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 <psxgpu.h>
-
-#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 <psxgte.h>
#include <psxgpu.h>
#include <psxpad.h>
+#include <psxcd.h>
#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;