From 58e34e5103e028022ee00d8171e7a832d1b61643 Mon Sep 17 00:00:00 2001 From: Andress Barajas Date: Tue, 19 Nov 2024 20:19:27 -0800 Subject: [PATCH] Pull latest changes from upstream --- .gitignore | 12 +- Makefile.rules | 18 ++ environ_base.sh | 1 + examples/dreamcast/library/Makefile | 47 +++ examples/dreamcast/library/exports.txt | 7 + examples/dreamcast/library/library-test.c | 137 +++++++++ .../library/loadable-dependence/Makefile | 24 ++ .../library/loadable-dependence/exports.txt | 10 + .../loadable-dependence/library-dependence.c | 55 ++++ .../loadable-dependence/library-dependence.h | 18 ++ .../library/loadable-dependent/Makefile | 18 ++ .../loadable-dependent/library-dependent.c | 52 ++++ include/kos/exports.h | 30 +- include/kos/library.h | 61 ++-- kernel/exports/exports.c | 64 +++- kernel/exports/library.c | 77 +++-- kernel/fs/elf.c | 2 +- loadable/Makefile.prefab | 39 +-- loadable/shlelf_dc.xr | 288 ++++++------------ 19 files changed, 683 insertions(+), 277 deletions(-) create mode 100644 examples/dreamcast/library/Makefile create mode 100644 examples/dreamcast/library/exports.txt create mode 100644 examples/dreamcast/library/library-test.c create mode 100644 examples/dreamcast/library/loadable-dependence/Makefile create mode 100644 examples/dreamcast/library/loadable-dependence/exports.txt create mode 100644 examples/dreamcast/library/loadable-dependence/library-dependence.c create mode 100644 examples/dreamcast/library/loadable-dependence/library-dependence.h create mode 100644 examples/dreamcast/library/loadable-dependent/Makefile create mode 100644 examples/dreamcast/library/loadable-dependent/library-dependent.c diff --git a/.gitignore b/.gitignore index 713d4aea60..7a84f4e58c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ *.o +*.a *.elf +*.bin +*.klf *.exe *.dll *.map @@ -15,8 +18,6 @@ kernel/exports/kernel_exports.c kernel/arch/dreamcast/kernel/arch_exports.c kernel/arch/dreamcast/kernel/banner.h kernel/arch/dreamcast/sound/arm/stream.drv -lib/dreamcast/*.a -addons/lib/dreamcast/*.a utils/bincnv/bincnv utils/genromfs/genromfs utils/vqenc/vqenc @@ -45,7 +46,14 @@ examples/dreamcast/pvr/bumpmap/romdisk/bumpmap.raw examples/dreamcast/pvr/modifier_volume_tex/romdisk/fruit.kmg examples/dreamcast/pvr/texture_render/texture_render.bin examples/dreamcast/video/screenshot/screenshot*.ppm +<<<<<<< HEAD examples/dreamcast/*/nehe/nehe26/romdisk/*.bin +======= +examples/dreamcast/library/exports.c +examples/dreamcast/library/exports_stubs.c +examples/dreamcast/library/*/exports.c +examples/dreamcast/library/*/exports_stubs.c +>>>>>>> e1d7e5b4 (Loadable library recovery and example (#819)) utils/dc-chain/logs utils/dc-chain/*.tar.bz2 utils/dc-chain/*.tar.gz diff --git a/Makefile.rules b/Makefile.rules index f8f1b16e68..9fa4aa6296 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -3,6 +3,7 @@ # Makefile.rules # Copyright (c) 2000, 2001 Megan Potter # Copyright (c) 2024 Eric Fradella +# Copyright (C) 2024 Ruslan Rostovtsev # # Global KallistiOS Makefile include @@ -104,3 +105,20 @@ endef define KOS_GCCVER_MIN_WARNING @echo "Skipping $(TARGET) build as current GCC version ($(KOS_GCCVER)) is less than $(KOS_GCCVER_MIN)." endef + +ifdef EXPORTS_FILE + +OBJS += exports.o + +exports.o: exports.c +exports.c: $(EXPORTS_FILE) + $(KOS_BASE)/utils/genexports/genexports.sh $(EXPORTS_FILE) exports.c $(EXPORTS_SYMBOL) + +exports_stubs.o: exports_stubs.c +exports_stubs.c: $(EXPORTS_FILE) + $(KOS_BASE)/utils/genexports/genexportstubs.sh $(EXPORTS_FILE) exports_stubs.c + +$(TARGET_LIB): exports_stubs.o + $(KOS_AR) rcs $(TARGET_LIB) exports_stubs.o + +endif diff --git a/environ_base.sh b/environ_base.sh index a6fada4434..ca64b7b47b 100644 --- a/environ_base.sh +++ b/environ_base.sh @@ -47,6 +47,7 @@ export KOS_ADDR2LINE="${KOS_CC_BASE}/bin/${KOS_CC_PREFIX}-addr2line" export KOS_LD="${KOS_CC_BASE}/bin/${KOS_CC_PREFIX}-ld" export KOS_RANLIB="${KOS_CC_BASE}/bin/${KOS_CC_PREFIX}-gcc-ranlib" export KOS_STRIP="${KOS_CC_BASE}/bin/${KOS_CC_PREFIX}-strip" +export KOS_SIZE="${KOS_CC_BASE}/bin/${KOS_CC_PREFIX}-size" export KOS_CFLAGS="${KOS_CFLAGS} ${KOS_INC_PATHS} -D_arch_${KOS_ARCH} -D_arch_sub_${KOS_SUBARCH} -Wall -g" export KOS_CPPFLAGS="${KOS_CPPFLAGS} ${KOS_INC_PATHS_CPP}" diff --git a/examples/dreamcast/library/Makefile b/examples/dreamcast/library/Makefile new file mode 100644 index 0000000000..18bd32fce9 --- /dev/null +++ b/examples/dreamcast/library/Makefile @@ -0,0 +1,47 @@ +# KallistiOS ##version## +# +# examples/dreamcast/library/Makefile +# Copyright (C) 2024 Ruslan Rostovtsev +# + +TARGET_NAME = library-test +TARGET = $(TARGET_NAME).elf +TARGET_LIB = lib$(TARGET_NAME).a +TARGET_BIN = $(TARGET_NAME).bin +OBJS = $(TARGET_NAME).o romdisk.o + +EXPORTS_FILE = exports.txt +EXPORTS_SYMBOL = libtest_symtab +KOS_ROMDISK_DIR = romdisk + +include $(KOS_BASE)/Makefile.rules + +KOS_CFLAGS += -I./loadable-dependence + +all: rm-elf $(TARGET_LIB) loadable $(TARGET) + +clean: rm-elf + -rm -f $(OBJS) + -rm -rf ./romdisk + cd loadable-dependence && make clean + cd loadable-dependent && make clean + +rm-elf: + -rm -f $(TARGET) $(TARGET_BIN) $(TARGET_LIB) romdisk.* + +loadable: + mkdir -p romdisk + cd loadable-dependence && make && cp library-dependence.klf ../romdisk + cd loadable-dependent && make && cp library-dependent.klf ../romdisk + +$(TARGET): $(OBJS) + kos-cc -o $(TARGET) $(OBJS) + +run: $(TARGET) + $(KOS_LOADER) $(TARGET) + +dist: $(TARGET) + -rm -f $(OBJS) romdisk.img + $(KOS_STRIP) $(TARGET) + $(KOS_OBJCOPY) -R .stack -O binary $(TARGET) $(TARGET_BIN) + $(KOS_SIZE) $(TARGET) diff --git a/examples/dreamcast/library/exports.txt b/examples/dreamcast/library/exports.txt new file mode 100644 index 0000000000..6a8503c3c2 --- /dev/null +++ b/examples/dreamcast/library/exports.txt @@ -0,0 +1,7 @@ +include kos/exports.h +include string.h + +# Additional newlib functions to export +# Some part of it already exported by kernel/exports.txt +strcmp +strncmp diff --git a/examples/dreamcast/library/library-test.c b/examples/dreamcast/library/library-test.c new file mode 100644 index 0000000000..680db5c145 --- /dev/null +++ b/examples/dreamcast/library/library-test.c @@ -0,0 +1,137 @@ +/* KallistiOS ##version## + + library-test.c + Copyright (C) 2024 Ruslan Rostovtsev + + This example program simply show how library works. +*/ + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "library-dependence.h" + +KOS_INIT_FLAGS(INIT_DEFAULT | INIT_EXPORT); + +extern export_sym_t libtest_symtab[]; +static symtab_handler_t st_libtest = { + { + "sym/library/test", + 0, + 0x00010000, + 0, + NMMGR_TYPE_SYMTAB, + NMMGR_LIST_INIT + }, + libtest_symtab +}; + +static void __attribute__((__noreturn__)) wait_exit(void) { + maple_device_t *dev; + cont_state_t *state; + + dbglog(DBG_DEBUG, "Press any button to exit.\n"); + + for(;;) { + dev = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + + if(dev) { + state = (cont_state_t *)maple_dev_status(dev); + if(state) { + if(state->buttons) { + arch_exit(); + } + } + } + } +} + +int main(int argc, char *argv[]) { + + klibrary_t *lib_dependence; + klibrary_t *lib_dependent; + export_sym_t *sym; + uint32_t ver; + library_test_func_t library_test_func; + library_test_func2_t library_test_func2; + + // dbgio_dev_select("fb"); + dbglog(DBG_DEBUG, "Initializing exports.\n"); + + if(nmmgr_handler_add(&st_libtest.nmmgr) < 0) { + dbglog(DBG_ERROR, "Failed."); + wait_exit(); + return -1; + } + + dbglog(DBG_DEBUG, "Loading /rd/library-dependence.klf\n"); + lib_dependence = library_open("dependence", "/rd/library-dependence.klf"); + + if (lib_dependence == NULL) { + dbglog(DBG_ERROR, "Loading failed.\n"); + wait_exit(); + return -1; + } + + ver = library_get_version(lib_dependence); + + dbglog(DBG_DEBUG, "Successfully loaded: %s v%ld.%ld.%ld\n", + library_get_name(lib_dependence), + (ver >> 16) & 0xff, (ver >> 8) & 0xff, ver & 0xff); + + dbglog(DBG_DEBUG, "Loading /rd/library-dependence.klf\n"); + lib_dependent = library_open("dependent", "/rd/library-dependent.klf"); + + if (lib_dependence == NULL) { + dbglog(DBG_ERROR, "Loading failed.\n"); + wait_exit(); + return -1; + } + + ver = library_get_version(lib_dependent); + + dbglog(DBG_DEBUG, "Successfully loaded: %s v%ld.%ld.%ld\n", + library_get_name(lib_dependent), + (ver >> 16) & 0xff, (ver >> 8) & 0xff, ver & 0xff); + + dbglog(DBG_DEBUG, "Testing exports runtime on host\n"); + + sym = export_lookup("library_test_func"); + + if (sym && sym->ptr != (uint32_t)-1) { + library_test_func = (library_test_func_t)sym->ptr; + library_test_func(444); + } + else { + dbglog(DBG_ERROR, "Lookup symbol failed: library_test_func"); + } + + sym = export_lookup("library_test_func2"); + + if (sym && sym->ptr != (uint32_t)-1) { + library_test_func2 = (library_test_func2_t)sym->ptr; + library_test_func2("Hello from library test"); + } + else { + dbglog(DBG_ERROR, "Lookup symbol failed: library_test_func"); + } + + library_close(lib_dependent); + library_close(lib_dependence); + nmmgr_handler_remove(&st_libtest.nmmgr); + + wait_exit(); + return 0; +} diff --git a/examples/dreamcast/library/loadable-dependence/Makefile b/examples/dreamcast/library/loadable-dependence/Makefile new file mode 100644 index 0000000000..4037085e75 --- /dev/null +++ b/examples/dreamcast/library/loadable-dependence/Makefile @@ -0,0 +1,24 @@ +# KallistiOS ##version## +# +# examples/dreamcast/library/loadable-dependence/Makefile +# Copyright (C) 2024 Ruslan Rostovtsev +# + +TARGET_NAME = library-dependence +TARGET = $(TARGET_NAME).klf +TARGET_LIB = lib$(TARGET_NAME).a +OBJS = $(TARGET_NAME).o + +# For exporting kos_md5 +LIBS = -lkosutils + +# library-test exported stub for link test +DBG_LIBS = -llibrary-test + +EXPORTS_SYMBOL = library_symtab +EXPORTS_FILE = exports.txt + +KOS_CFLAGS += -I./ +KOS_LIB_PATHS += -L../ + +include $(KOS_BASE)/loadable/Makefile.prefab diff --git a/examples/dreamcast/library/loadable-dependence/exports.txt b/examples/dreamcast/library/loadable-dependence/exports.txt new file mode 100644 index 0000000000..8577494fc0 --- /dev/null +++ b/examples/dreamcast/library/loadable-dependence/exports.txt @@ -0,0 +1,10 @@ +include kos/exports.h +include kos/md5.h +include library-dependence.h + +# Loadable library exported functions +library_test_func +library_test_func2 + +# Linked library exported functions +kos_md5 diff --git a/examples/dreamcast/library/loadable-dependence/library-dependence.c b/examples/dreamcast/library/loadable-dependence/library-dependence.c new file mode 100644 index 0000000000..28dd0b7603 --- /dev/null +++ b/examples/dreamcast/library/loadable-dependence/library-dependence.c @@ -0,0 +1,55 @@ +/* KallistiOS ##version## + + library-dependence.c + Copyright (C) 2024 Ruslan Rostovtsev + + This example program simply show how library works. +*/ + +#include +#include +#include +#include +#include + +extern export_sym_t library_symtab[]; +static symtab_handler_t library_hnd = { + { + "sym/library/dependence", + 0, + 0x00010000, + 0, + NMMGR_TYPE_SYMTAB, + NMMGR_LIST_INIT + }, + library_symtab +}; + +/* Library functions */ +const char *lib_get_name() { + return library_hnd.nmmgr.pathname + 12; +} + +uint32_t lib_get_version() { + return KOS_VERSION_MAKE(1, 0, 0); +} + +int lib_open(klibrary_t *lib) { + dbglog(DBG_DEBUG, "Library \"%s\" opened.\n", lib_get_name()); + return nmmgr_handler_add(&library_hnd.nmmgr); +} + +int lib_close(klibrary_t *lib) { + dbglog(DBG_DEBUG, "Library \"%s\" closed.\n", lib_get_name()); + return nmmgr_handler_remove(&library_hnd.nmmgr); +} + +/* Exported functions */ +int library_test_func(int arg) { + dbglog(DBG_DEBUG, "Library \"%s\" test int: %d\n", lib_get_name(), arg); + return 0; +} + +void library_test_func2(const char *arg) { + dbglog(DBG_DEBUG, "Library \"%s\" test char: %s\n", lib_get_name(), arg); +} diff --git a/examples/dreamcast/library/loadable-dependence/library-dependence.h b/examples/dreamcast/library/loadable-dependence/library-dependence.h new file mode 100644 index 0000000000..241b7ac77e --- /dev/null +++ b/examples/dreamcast/library/loadable-dependence/library-dependence.h @@ -0,0 +1,18 @@ +/* KallistiOS ##version## + + library-dependence.h + Copyright (C) 2024 Ruslan Rostovtsev + + This example program simply show how library works. +*/ + +#include + +/** + * @brief Exported test functions + */ +int library_test_func(int arg); +void library_test_func2(const char *arg); + +typedef int (*library_test_func_t)(int arg); +typedef void (*library_test_func2_t)(const char *arg); diff --git a/examples/dreamcast/library/loadable-dependent/Makefile b/examples/dreamcast/library/loadable-dependent/Makefile new file mode 100644 index 0000000000..772a00a4d5 --- /dev/null +++ b/examples/dreamcast/library/loadable-dependent/Makefile @@ -0,0 +1,18 @@ +# KallistiOS ##version## +# +# examples/dreamcast/library/loadable-dependent/Makefile +# Copyright (C) 2024 Ruslan Rostovtsev +# + +TARGET_NAME = library-dependent +TARGET = $(TARGET_NAME).klf +OBJS = $(TARGET_NAME).o + +# Dependence library and host stubs for link test +DBG_LIBS = -llibrary-dependence -llibrary-test +KOS_LIB_PATHS += -L../loadable-dependence -L../ + +# Dependence include +KOS_CFLAGS += -I../loadable-dependence + +include $(KOS_BASE)/loadable/Makefile.prefab diff --git a/examples/dreamcast/library/loadable-dependent/library-dependent.c b/examples/dreamcast/library/loadable-dependent/library-dependent.c new file mode 100644 index 0000000000..e2fad53a5d --- /dev/null +++ b/examples/dreamcast/library/loadable-dependent/library-dependent.c @@ -0,0 +1,52 @@ +/* KallistiOS ##version## + + library-dependent.c + Copyright (C) 2024 Ruslan Rostovtsev + + This example program simply show how library works. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "library-dependence.h" + +const char *lib_get_name() { + return "dependent"; +} + +uint32_t lib_get_version() { + return KOS_VERSION_MAKE(1, 0, 0); +} + +int lib_open(klibrary_t *lib) { + uint8_t output[16]; + + dbglog(DBG_DEBUG, "Library \"%s\" opened.\n", lib_get_name()); + + // Test exports from dependence library + library_test_func(333); + library_test_func2("Hello from library dependent"); + + // Test libkosutils from dependence library + kos_md5((const uint8_t *)lib_get_name(), strlen(lib_get_name()), output); + dbglog(DBG_DEBUG, "MD5 of \"%s\": %02X%02X%02X%02X...\n", + lib_get_name(), output[0], output[1], output[2], output[3]); + + // Test host exported newlib + if(strcmp(lib_get_name(), "dependent")) { + return -1; + } + + return 0; +} + +int lib_close(klibrary_t *lib) { + dbglog(DBG_DEBUG, "Library \"%s\" closed.\n", lib_get_name()); + return 0; +} diff --git a/include/kos/exports.h b/include/kos/exports.h index 3b4c1d3a3e..ca98489a66 100644 --- a/include/kos/exports.h +++ b/include/kos/exports.h @@ -1,7 +1,8 @@ /* KallistiOS ##version## kos/exports.h - Copyright (C)2003 Megan Potter + Copyright (C) 2003 Megan Potter + Copyright (C) 2024 Ruslan Rostovtsev */ @@ -14,6 +15,7 @@ be looked through using the functionality in this file. \author Megan Potter + \author Ruslan Rostovtsev */ #ifndef __KOS_EXPORTS_H @@ -23,6 +25,7 @@ __BEGIN_DECLS #include +#include /** \addtogroup system_libraries @{ @@ -36,8 +39,8 @@ __BEGIN_DECLS \headerfile kos/exports.h */ typedef struct export_sym { - const char * name; /**< \brief The name of the symbol. */ - ptr_t ptr; /**< \brief A pointer to the symbol. */ + const char *name; /**< \brief The name of the symbol. */ + uintptr_t ptr; /**< \brief A pointer to the symbol. */ } export_sym_t; /** \cond */ @@ -55,8 +58,8 @@ extern export_sym_t arch_symtab[]; \headerfile kos/exports.h */ typedef struct symtab_handler { - struct nmmgr_handler nmmgr; /**< \brief Name manager handler header */ - export_sym_t * table; /**< \brief Location of the first entry */ + struct nmmgr_handler nmmgr; /**< \brief Name manager handler header */ + export_sym_t *table; /**< \brief Location of the first entry */ } symtab_handler_t; #endif @@ -67,11 +70,24 @@ void export_init(void); \param name The symbol to look up \return The export structure, or NULL on failure */ -export_sym_t * export_lookup(const char * name); +export_sym_t *export_lookup(const char *name); + +/** \brief Look up a symbol by name and Name Manager path. + \param name The symbol to look up + \param path The Name Manager path to look up + \return The export structure, or NULL on failure +*/ +export_sym_t *export_lookup_path(const char *name, const char *path); + +/** \brief Look up a symbol by approx addr. + It can be useful for unhandled exceptions messages. + \param addr The symbol to look up + \return The export structure, or NULL on failure +*/ +export_sym_t *export_lookup_addr(uintptr_t addr); /** @} */ __END_DECLS #endif /* __KOS_EXPORTS_H */ - diff --git a/include/kos/library.h b/include/kos/library.h index f0f50ab4ce..ac51e2be4d 100644 --- a/include/kos/library.h +++ b/include/kos/library.h @@ -1,7 +1,8 @@ /* KallistiOS ##version## include/kos/library.h - Copyright (C)2003 Megan Potter + Copyright (C) 2003 Megan Potter + Copyright (C) 2024 Ruslan Rostovtsev */ @@ -21,6 +22,7 @@ this. \author Megan Potter + \author Ruslan Rostovtsev */ #ifndef __KOS_LIBRARY_H @@ -79,7 +81,7 @@ typedef struct klibrary { libid_t libid; /** \brief Library flags. */ - uint32 flags; + uint32_t flags; /** \brief ELF image for this library. @@ -106,7 +108,7 @@ typedef struct klibrary { \return The library's symbolic name */ - const char * (*lib_get_name)(void); + const char *(*lib_get_name)(void); /** \brief Retrieve the library's version. @@ -116,32 +118,29 @@ typedef struct klibrary { \return The library's version number */ - uint32(*lib_get_version)(void); + uint32_t(*lib_get_version)(void); /** \brief Open a library. This function must be implemented by all loadable libraries to - initialize the library on load. If the library is already opened, this - may only involve increasing the reference count. + initialize the library on load. \param lib The library structure \return Values >= 0 indicate success, < 0 indicates failure. A failure on the first lib_open is indicative that the library should be removed from memory. */ - int (*lib_open)(struct klibrary * lib); + int (*lib_open)(struct klibrary *lib); /** \brief Close an opened library. This function must be implemented by all loadable libraries to close and - deinitialize a library. If the library's reference count is > 1 when - this function is called, this may involve simply decrementing the - reference count. + deinitialize a library. \param lib The library structure \return Values >= 0 indicate success, < 0 indicates failure */ - int (*lib_close)(struct klibrary * lib); + int (*lib_close)(struct klibrary *lib); } klibrary_t; /* Library flag values */ @@ -187,8 +186,10 @@ int library_destroy(klibrary_t *lib); /** \brief Try to open a library by name. This function attempts to open a library by its name. If it cannot be found - by name, this function will attempt to load the library from the specified - filename. + by name, this function will attempt to open by filename. If it cannot be found + by filename, this function will attempt to load the library from the specified + filename. If the library is already opened, this may only involve increasing + the reference count. \param name The symbolic name of the library \param fn The filename to load the library from @@ -200,13 +201,12 @@ int library_destroy(klibrary_t *lib); \em ENOMEM - out of memory \n \em ENOENT - library not found and no filename given */ -klibrary_t * library_open(const char * name, const char * fn); +klibrary_t *library_open(const char *name, const char *fn); /** \brief Look up a library by name. - This function looks up a library by its symbolic name without trying to - actually load or open it. This is useful if you want to open a library but - not keep around a handle to it (which isn't necessarily encouraged). + This is useful if you want to reuse opened library and + this is used for library_open(). \param name The name of the library to search for \return The library, if found. NULL if not found, errno set @@ -215,7 +215,21 @@ klibrary_t * library_open(const char * name, const char * fn); \par Error Conditions: \em ENOENT - the library was not found */ -klibrary_t * library_lookup(const char * name); +klibrary_t *library_lookup(const char *name); + +/** \brief Look up a library by filename. + + This is useful if you want to reuse opened library and + this is used for library_open(). + + \param fn The filename of the library to search for + \return The library, if found. NULL if not found, errno set + as appropriate. + + \par Error Conditions: + \em ENOENT - the library was not found +*/ +klibrary_t *library_lookup_fn(const char *fn); /** \brief Close a previously opened library. @@ -231,7 +245,7 @@ klibrary_t * library_lookup(const char * name); \par Error Conditions: \em EINVAL - the library is not valid */ -int library_close(klibrary_t * lib); +int library_close(klibrary_t *lib); /** \brief Retrieve the specified library's runtime-assigned ID. \param lib The library to examine @@ -240,7 +254,7 @@ int library_close(klibrary_t * lib); \par Error Conditions: \em EINVAL - the library is not valid */ -libid_t library_get_libid(klibrary_t * lib); +libid_t library_get_libid(klibrary_t *lib); /** \brief Retrieve the specified library's reference count. \param lib The library to examine @@ -249,7 +263,7 @@ libid_t library_get_libid(klibrary_t * lib); \par Error Conditions: \em EINVAL - the library is not valid */ -int library_get_refcnt(klibrary_t * lib); +int library_get_refcnt(klibrary_t *lib); /** \brief Retrieve the specified library's name. \param lib The library to examine @@ -258,7 +272,7 @@ int library_get_refcnt(klibrary_t * lib); \par Error Conditions: \em EINVAL - the library is not valid */ -const char * library_get_name(klibrary_t * lib); +const char *library_get_name(klibrary_t *lib); /** \brief Retrieve the specified library's version. \param lib The library to examine @@ -267,7 +281,7 @@ const char * library_get_name(klibrary_t * lib); \par Error Conditions \em EINVAL - the library is not valid */ -uint32 library_get_version(klibrary_t * lib); +uint32_t library_get_version(klibrary_t *lib); /** \cond */ /* Init */ @@ -282,4 +296,3 @@ void library_shutdown(void); __END_DECLS #endif /* __KOS_LIBRARY_H */ - diff --git a/kernel/exports/exports.c b/kernel/exports/exports.c index 88e7e78430..e1763b71c9 100644 --- a/kernel/exports/exports.c +++ b/kernel/exports/exports.c @@ -1,7 +1,8 @@ /* KallistiOS ##version## exports.c - Copyright (C)2003 Megan Potter + Copyright (C) 2003 Megan Potter + Copyright (C) 2024 Ruslan Rostovtsev */ @@ -49,11 +50,11 @@ void export_init(void) { nmmgr_handler_add(&st_arch.nmmgr); } -export_sym_t * export_lookup(const char * name) { +export_sym_t *export_lookup(const char *name) { nmmgr_handler_t *nmmgr; - nmmgr_list_t *nmmgrs; - int i; - symtab_handler_t * sth; + nmmgr_list_t *nmmgrs; + int i; + symtab_handler_t *sth; /* Get the name manager list */ nmmgrs = nmmgr_get_list(); @@ -78,3 +79,56 @@ export_sym_t * export_lookup(const char * name) { return NULL; } + +export_sym_t *export_lookup_path(const char *name, const char *path) { + nmmgr_handler_t *nmmgr; + symtab_handler_t *sth; + int i; + + /* Get the name manager list */ + nmmgr = nmmgr_lookup(path); + + if(nmmgr == NULL) { + return NULL; + } + sth = (symtab_handler_t *)nmmgr; + + for(i = 0; sth->table[i].name; i++) { + if(!strcmp(name, sth->table[i].name)) + return sth->table + i; + } + + return NULL; +} + +export_sym_t *export_lookup_addr(uintptr_t addr) { + nmmgr_handler_t *nmmgr; + nmmgr_list_t *nmmgrs; + int i; + symtab_handler_t *sth; + + uintptr_t dist = ~0; + export_sym_t *best = NULL; + + /* Get the name manager list */ + nmmgrs = nmmgr_get_list(); + + /* Go through and look at each symtab entry */ + LIST_FOREACH(nmmgr, nmmgrs, list_ent) { + /* Not a symtab -> ignore */ + if(nmmgr->type != NMMGR_TYPE_SYMTAB) + continue; + + sth = (symtab_handler_t *)nmmgr; + + /* First look through the kernel table */ + for(i = 0; sth->table[i].name; i++) { + if(addr - sth->table[i].ptr < dist) { + dist = addr - sth->table[i].ptr; + best = sth->table + i; + } + } + } + + return best; +} diff --git a/kernel/exports/library.c b/kernel/exports/library.c index 0b602296fc..bd2923f8e9 100644 --- a/kernel/exports/library.c +++ b/kernel/exports/library.c @@ -2,6 +2,7 @@ kernel/library.c Copyright (C) 2003 Megan Potter + Copyright (C) 2024 Ruslan Rostovtsev */ #include @@ -127,7 +128,7 @@ klibrary_t * library_create(int flags) { /* Populate the context */ np->libid = libid; np->flags = flags; - np->refcnt = 0; + np->refcnt = 1; /* Insert it into the library list */ LIST_INSERT_HEAD(&library_list, np, list); @@ -137,8 +138,8 @@ klibrary_t * library_create(int flags) { return np; } -int library_destroy(klibrary_t * lib) { - int oldirq = 0; +int library_destroy(klibrary_t *lib) { + int oldirq = 0; oldirq = irq_disable(); @@ -160,7 +161,7 @@ int library_destroy(klibrary_t * lib) { /*****************************************************************************/ /* Library attribute functions -- all read-only */ -libid_t library_get_libid(klibrary_t * lib) { +libid_t library_get_libid(klibrary_t *lib) { if(lib == NULL) { errno = EINVAL; return -1; @@ -169,7 +170,7 @@ libid_t library_get_libid(klibrary_t * lib) { return lib->libid; } -int library_get_refcnt(klibrary_t * lib) { +int library_get_refcnt(klibrary_t *lib) { if(lib == NULL) { errno = EINVAL; return -1; @@ -178,7 +179,7 @@ int library_get_refcnt(klibrary_t * lib) { return lib->refcnt; } -const char * library_get_name(klibrary_t * lib) { +const char *library_get_name(klibrary_t *lib) { if(lib == NULL || lib->lib_get_name == NULL) { errno = EINVAL; return NULL; @@ -187,7 +188,7 @@ const char * library_get_name(klibrary_t * lib) { return lib->lib_get_name(); } -uint32 library_get_version(klibrary_t * lib) { +uint32_t library_get_version(klibrary_t *lib) { if(lib == NULL || lib->lib_get_version == NULL) { errno = EINVAL; return 0; @@ -197,8 +198,8 @@ uint32 library_get_version(klibrary_t * lib) { } /*****************************************************************************/ -klibrary_t * library_lookup(const char * name) { - klibrary_t * lib; +klibrary_t *library_lookup(const char *name) { + klibrary_t *lib; irq_disable_scoped(); @@ -213,28 +214,36 @@ klibrary_t * library_lookup(const char * name) { return lib; } -klibrary_t * library_open(const char * name, const char * fn) { - klibrary_t * lib; +klibrary_t *library_lookup_fn(const char *fn) { + klibrary_t *lib; + + irq_disable_scoped(); + + LIST_FOREACH(lib, &library_list, list) { + if(!strncmp(lib->image.fn, fn, NAME_MAX)) + break; + } + + if(!lib) + errno = ENOENT; + + return lib; +} + +klibrary_t *library_open(const char *name, const char *fn) { + klibrary_t *lib = NULL; // If they passed us a valid name, try that first. if(name) { lib = library_lookup(name); + } + else { + lib = library_lookup_fn(fn); + } - if(lib) { - // Make sure lib_open is valid. Note that since we - // _have_ found something, any inconsistencies here - // are errors and not a signal to load another copy. - if(!lib->lib_open) { - errno = EINVAL; - return NULL; - } - - // Open the lib. - if(lib->lib_open(lib) < 0) - return NULL; - - return lib; - } + if(lib) { + ++lib->refcnt; + return lib; } // Ok, we need to load. Make sure we have a valid filename. @@ -259,7 +268,7 @@ klibrary_t * library_open(const char * name, const char * fn) { // Pull out the image pointers lib->lib_get_name = (const char * (*)())lib->image.lib_get_name; - lib->lib_get_version = (uint32(*)())lib->image.lib_get_version; + lib->lib_get_version = (uint32_t(*)())lib->image.lib_get_version; lib->lib_open = (int (*)(klibrary_t *))lib->image.lib_open; lib->lib_close = (int (*)(klibrary_t *))lib->image.lib_close; @@ -281,20 +290,24 @@ klibrary_t * library_open(const char * name, const char * fn) { return lib; } -int library_close(klibrary_t * lib) { +int library_close(klibrary_t *lib) { // Make sure it's valid. if(lib == NULL || lib->lib_close == NULL) { errno = EINVAL; return -1; } + // Check for reference + if(--lib->refcnt > 0) { + return 0; + } + // Call down and "close" the lib. if(lib->lib_close(lib) < 0) return -1; - // If the refcount is down to zero, unload this lib. - if(lib->refcnt <= 0) - library_destroy(lib); + // Unload this lib. + library_destroy(lib); // It's all good. return 0; @@ -330,5 +343,3 @@ void library_shutdown(void) { LIST_INIT(&library_list); } - - diff --git a/kernel/fs/elf.c b/kernel/fs/elf.c index 2d98a5b601..abcc5ccdc7 100644 --- a/kernel/fs/elf.c +++ b/kernel/fs/elf.c @@ -79,7 +79,7 @@ int elf_load(const char * fn, klibrary_t * shell, elf_prog_t * out) { sz = fs_total(fd); DBG(("Loading ELF file of size %d\n", sz)); - img = malloc(sz); + img = memalign(32, sz); if(img == NULL) { dbglog(DBG_ERROR, "elf_load: can't allocate %d bytes for ELF load\n", sz); diff --git a/loadable/Makefile.prefab b/loadable/Makefile.prefab index 03d3650baf..080bd75f8a 100644 --- a/loadable/Makefile.prefab +++ b/loadable/Makefile.prefab @@ -1,30 +1,33 @@ # KallistiOS ##version## # -# Makefile_dll.prefab -# Copyright (C)2000,2003 Megan Potter +# loadable/Makefile.prefab +# Copyright (C) 2000, 2003 Megan Potter +# Copyright (C) 2024 Ruslan Rostovtsev # -all: $(TARGET) - include $(KOS_BASE)/Makefile.rules +ifdef DBG_LIBS +DBG_LIBS += -lkallisti_exports +else +DBG_LIBS = -lkallisti_exports +endif + +ifdef TARGET_LIB +all: rm-elf $(TARGET) $(TARGET_LIB) +else +all: rm-elf $(TARGET) +endif + # First one checks for missing symbols (and fully links with an offset # of zero so we can do tracebacks later), second one makes the real file. $(TARGET): $(OBJS) - $(KOS_CC) -g -ml -m4-single-only -O2 -g -Wl,-Ttext=0x00000000 -e _start -nostartfiles -nostdlib -o dbg-$(TARGET) $(OBJS) $(KOS_LIB_PATHS) -Wl,--start-group $(LIBS) -lkallisti_exports -lgcc -Wl,--end-group - $(KOS_CC) -g -ml -m4-single-only -O2 -Wl,-d -Wl,-r -Wl,-S -Wl,-x -nostartfiles -nostdlib -o $(TARGET) -Wl,-T $(KOS_BASE)/loadable/shlelf_dc.xr $(OBJS) $(KOS_LIB_PATHS) -Wl,--start-group $(LIBS) -lgcc -Wl,--end-group - -chmod +x $(TARGET) + $(KOS_CC) -g -ml -m4-single-only -O2 -g -Wl,-Ttext=0x00000000 -e _start -nostartfiles -nodefaultlibs -o dbg-$(TARGET) $(OBJS) $(KOS_LIB_PATHS) -Wl,--start-group $(LIBS) $(DBG_LIBS) -lgcc -Wl,--end-group + $(KOS_CC) -g -ml -m4-single-only -O2 -Wl,-d -Wl,-r -Wl,-S -Wl,-x -nostartfiles -nodefaultlibs -o $(TARGET) -Wl,-T $(KOS_BASE)/loadable/shlelf_dc.xr $(OBJS) $(KOS_LIB_PATHS) -Wl,--start-group $(LIBS) -lgcc -Wl,--end-group + $(KOS_SIZE) $(TARGET) clean: - -rm -f $(OBJS) $(TARGET) dbg-$(TARGET) romdisk.o romdisk.img - -copy: - cp $(TARGET) $(KOS_BASE)/kernel/romdisk/ + -rm -f $(OBJS) $(TARGET) dbg-$(TARGET) $(TARGET_LIB) romdisk.* exports.c exports_stubs.* -# If they want an exports table, we'll set that up too. -ifdef EXPORTS_SYMBOL -exports.o: exports.c - -exports.c: $(EXPORTS_FILE) - $(KOS_BASE)/utils/genexports/genexports.sh $(EXPORTS_FILE) exports.c $(EXPORTS_SYMBOL) -endif +rm-elf: + -rm -f $(TARGET) dbg-$(TARGET) $(TARGET_LIB) diff --git a/loadable/shlelf_dc.xr b/loadable/shlelf_dc.xr index 6d02a72cbc..be62ab696f 100644 --- a/loadable/shlelf_dc.xr +++ b/loadable/shlelf_dc.xr @@ -1,5 +1,6 @@ -/* OUTPUT_FORMAT("elf32-sh-dreamcast", "elf32-sh-dreamcast", - "elf32-sh-dreamcast") +/* Script for ld -r: link without relocation */ +/* OUTPUT_FORMAT("elf32-shl", "elf32-shl", + "elf32-shl") OUTPUT_ARCH(sh) */ ENTRY(_start) /* For some reason, the Solaris linker makes bad executables @@ -9,223 +10,124 @@ ENTRY(_start) SECTIONS { /* Read-only sections, merged into text segment: */ - .interp 0 : { *(.interp) } - .hash 0 : { *(.hash) } - .dynsym 0 : { *(.dynsym) } - .dynstr 0 : { *(.dynstr) } - .gnu.version 0 : { *(.gnu.version) } - .gnu.version_d 0 : { *(.gnu.version_d) } - .gnu.version_r 0 : { *(.gnu.version_r) } - .rel.init 0 : { *(.rel.init) } - .rela.init 0 : { *(.rela.init) } - .rel.text 0 : + .interp 0 : { *(.interp) } + .note.gnu.build-id 0: { *(.note.gnu.build-id) } + .hash 0 : { *(.hash) } + .gnu.hash 0 : { *(.gnu.hash) } + .dynsym 0 : { *(.dynsym) } + .dynstr 0 : { *(.dynstr) } + .gnu.version 0 : { *(.gnu.version) } + .gnu.version_d 0: { *(.gnu.version_d) } + .gnu.version_r 0: { *(.gnu.version_r) } + .rela.init 0 : { *(.rela.init) } + .rela.text 0 : { *(.rela.text) } + .rela.fini 0 : { *(.rela.fini) } + .rela.rodata 0 : { *(.rela.rodata) } + .rela.data.rel.ro 0 : { *(.rela.data.rel.ro) } + .rela.data 0 : { *(.rela.data) } + .rela.tdata 0 : { *(.rela.tdata) } + .rela.tbss 0 : { *(.rela.tbss) } + .rela.ctors 0 : { *(.rela.ctors) } + .rela.dtors 0 : { *(.rela.dtors) } + .rela.got 0 : { *(.rela.got) } + .rela.sdata 0 : { *(.rela.sdata) } + .rela.sbss 0 : { *(.rela.sbss) } + .rela.sdata2 0 : { *(.rela.sdata2) } + .rela.sbss2 0 : { *(.rela.sbss2) } + .rela.bss 0 : { *(.rela.bss) } + .rela.iplt 0 : { - *(.rel.text) - *(.rel.text.*) - *(.rel.gnu.linkonce.t.*) + *(.rela.iplt) } - .rela.text 0 : + .rela.plt 0 : { - *(.rela.text) - *(.rela.text.*) - *(.rela.gnu.linkonce.t.*) + *(.rela.plt) } - .rel.fini 0 : { *(.rel.fini) } - .rela.fini 0 : { *(.rela.fini) } - .rel.rodata 0 : - { - *(.rel.rodata) - *(.rel.rodata.*) - *(.rel.gnu.linkonce.r.*) - } - .rela.rodata 0 : - { - *(.rela.rodata) - *(.rela.rodata.*) - *(.rela.gnu.linkonce.r.*) - } - .rel.data 0 : - { - *(.rel.data) - *(.rel.data.*) - *(.rel.gnu.linkonce.d.*) - } - .rela.data 0 : - { - *(.rela.data) - *(.rela.data.*) - *(.rela.gnu.linkonce.d.*) - } - .rel.ctors 0 : { *(.rel.ctors) } - .rela.ctors 0 : { *(.rela.ctors) } - .rel.dtors 0 : { *(.rel.dtors) } - .rela.dtors 0 : { *(.rela.dtors) } - .rel.got 0 : { *(.rel.got) } - .rela.got 0 : { *(.rela.got) } - .rel.sdata 0 : - { - *(.rel.sdata) - *(.rel.sdata.*) - *(.rel.gnu.linkonce.s.*) - } - .rela.sdata 0 : - { - *(.rela.sdata) - *(.rela.sdata.*) - *(.rela.gnu.linkonce.s.*) - } - .rel.sbss 0 : - { - *(.rel.sbss) - *(.rel.sbss.*) - *(.rel.gnu.linkonce.sb.*) - } - .rela.sbss 0 : - { - *(.rela.sbss) - *(.rela.sbss.*) - *(.rela.gnu.linkonce.sb.*) - } - .rel.sdata2 0 : - { - *(.rel.sdata2) - *(.rel.sdata2.*) - *(.rel.gnu.linkonce.s2.*) - } - .rela.sdata2 0 : - { - *(.rela.sdata2) - *(.rela.sdata2.*) - *(.rela.gnu.linkonce.s2.*) - } - .rel.sbss2 0 : - { - *(.rel.sbss2) - *(.rel.sbss2.*) - *(.rel.gnu.linkonce.sb2.*) - } - .rela.sbss2 0 : - { - *(.rela.sbss2) - *(.rela.sbss2.*) - *(.rela.gnu.linkonce.sb2.*) - } - .rel.bss 0 : - { - *(.rel.bss) - *(.rel.bss.*) - *(.rel.gnu.linkonce.b.*) - } - .rela.bss 0 : - { - *(.rela.bss) - *(.rela.bss.*) - *(.rela.gnu.linkonce.b.*) - } - .rel.plt 0 : { *(.rel.plt) } - .rela.plt 0 : { *(.rela.plt) } - .init 0 : - { - KEEP (*(.init)) - } =0 - .plt 0 : { *(.plt) } - .text 0 : + .init 0 : + { + KEEP (*(SORT_NONE(.init))) + } + .plt 0 : { *(.plt) } + .iplt 0 : { *(.iplt) } + .text 0 : { - *(.text) - *(.text.*) - *(.stub) + *(.text .stub) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) - *(.gnu.linkonce.t.*) - } =0 - .fini 0 : + } + .fini 0 : { - KEEP (*(.fini)) - } =0 - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata 0 : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) } - .rodata1 0 : { *(.rodata1) } - .sdata2 0 : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) } - .sbss2 0 : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - .data 0 : + KEEP (*(SORT_NONE(.fini))) + } + .rodata 0 : { *(.rodata) } + .rodata1 0 : { *(.rodata1) } + .sdata2 0 : { - *(.data) - *(.data.*) - *(.gnu.linkonce.d.*) - SORT(CONSTRUCTORS) + *(.sdata2) } - .data1 0 : { *(.data1) } - .eh_frame : { KEEP (*(.eh_frame)) } - .gcc_except_table : { *(.gcc_except_table) } - .ctors 0 : + .sbss2 0 : { *(.sbss2) } + .eh_frame_hdr 0 : { *(.eh_frame_hdr) } + .eh_frame 0 : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .sframe 0 : ONLY_IF_RO { *(.sframe) } + .gcc_except_table 0 : ONLY_IF_RO { *(.gcc_except_table) } + .gnu_extab 0 : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges 0 : ONLY_IF_RO { *(.exception_ranges) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + /* Exception handling */ + .eh_frame 0 : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .sframe 0 : ONLY_IF_RW { *(.sframe) } + .gnu_extab 0 : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table 0 : ONLY_IF_RW { *(.gcc_except_table) } + .exception_ranges 0 : ONLY_IF_RW { *(.exception_ranges) } + /* Thread Local Storage sections */ + .tdata 0 : { *(.tdata) } + .tbss 0 : { *(.tbss) } + .preinit_array 0 : { - ___ctors = .; - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - ___ctors_end = .; + KEEP (*(.preinit_array)) } - .dtors 0 : + .jcr 0 : { KEEP (*(.jcr)) } + .dynamic 0 : { *(.dynamic) } + .data 0 : { - ___dtors = .; - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - ___dtors_end = .; + *(.data) } - .got 0 : { *(.got.plt) *(.got) } - .dynamic 0 : { *(.dynamic) } + .data1 0 : { *(.data1) } + .got 0 : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ - .sdata 0 : + .sdata 0 : { *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s.*) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .sbss 0 : + .sbss 0 : { - PROVIDE (__sbss_start = .); - PROVIDE (___sbss_start = .); *(.dynsbss) *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb.*) *(.scommon) - PROVIDE (__sbss_end = .); - PROVIDE (___sbss_end = .); } - .bss 0 : + .bss 0 : { *(.dynbss) *(.bss) - *(.bss.*) - *(.gnu.linkonce.b.*) *(COMMON) /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ } - _end = .; - PROVIDE (end = .); /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } + .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ @@ -239,7 +141,7 @@ SECTIONS .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } + .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } @@ -251,5 +153,17 @@ SECTIONS .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } - /* These must appear regardless of . */ + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + .debug_sup 0 : { *(.debug_sup) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } }