aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchandramouli narayanan <mouli@linux.intel.com>2012-06-25 12:40:02 -0700
committerchandramouli narayanan <mouli@linux.intel.com>2012-06-25 12:40:02 -0700
commitb664835d1583be53f34b412b38df53f21f100e24 (patch)
tree0fee5d81e7377395f4c6be94b4d10241f38846f4
parentca8533f1ef1d60dffa21449633dec9d26baeb29d (diff)
downloadsyslinux-b664835d1583be53f34b412b38df53f21f100e24.tar.gz
syslinux-b664835d1583be53f34b412b38df53f21f100e24.tar.xz
syslinux-b664835d1583be53f34b412b38df53f21f100e24.zip
The ELF module load and the utility library routines fully support lookup, resolution and relocation
of symbols for both ELF32 and ELF64 environments. With this, syslinux.efi built for i386 and x86_64 can load the respective native command modules dynamically. The architecture dependent files are split into respective subdirectories (com32/lib/sys/module/i386 & com32/lib/sys/module/x86_64) for the build environment to pick. Files changed for commit: com32/include/sys/elfcommon.h com32/include/sys/module.h and its i386/ x86_64/ specific files com32/lib/sys/module/i386/common.[ch] and its counterpart in x86_64 com32/lib/sys/module/i386/elfutils.h and its counterpart in x86_64 com32/lib/sys/module/i386/elf_module.c and its counterpart in x86_64 com32/lib/sys/module/i386/shallow_module.c and its counterpart in x86_64 The implementation of com32/elflink/load_env32.c now takes care of both i386 and x86_64 to set up elf module system. Remanants of the unused old i386-only files, if any, need to be pruned.
-rw-r--r--com32/include/sys/elfcommon.h50
-rw-r--r--com32/include/sys/i386/module.h369
-rw-r--r--com32/include/sys/module.h370
-rw-r--r--com32/include/sys/x86_64/module.h369
-rw-r--r--com32/lib/sys/module/common.c12
-rw-r--r--com32/lib/sys/module/common.h1
-rw-r--r--com32/lib/sys/module/elfutils.h71
-rw-r--r--com32/lib/sys/module/i386/common.c571
-rw-r--r--com32/lib/sys/module/i386/common.h65
-rw-r--r--com32/lib/sys/module/i386/elf_module.c555
-rw-r--r--com32/lib/sys/module/i386/elfutils.h64
-rw-r--r--com32/lib/sys/module/i386/shallow_module.c161
-rw-r--r--com32/lib/sys/module/x86_64/common.c567
-rw-r--r--com32/lib/sys/module/x86_64/common.h64
-rw-r--r--com32/lib/sys/module/x86_64/elf_module.c603
-rw-r--r--com32/lib/sys/module/x86_64/elfutils.h64
-rw-r--r--com32/lib/sys/module/x86_64/shallow_module.c161
-rw-r--r--core/elflink/load_env32.c25
18 files changed, 3706 insertions, 436 deletions
diff --git a/com32/include/sys/elfcommon.h b/com32/include/sys/elfcommon.h
index 8d6ddb05..99b5ad10 100644
--- a/com32/include/sys/elfcommon.h
+++ b/com32/include/sys/elfcommon.h
@@ -361,4 +361,54 @@
/* Keep this the last entry. */
#define R_386_NUM 38
+/* AMD x86-64 relocations. */
+#define R_X86_64_NONE 0 /* No reloc */
+#define R_X86_64_64 1 /* Direct 64 bit */
+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
+#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
+ offset to GOT */
+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
+#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
+#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
+#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
+ to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
+ to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
+#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
+ to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
+#define R_X86_64_PC64 24 /* PC relative 64 bit */
+#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */
+#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative
+ offset to GOT */
+#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */
+#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset
+ to GOT entry */
+#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */
+#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */
+#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset
+ to PLT entry */
+#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */
+#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */
+#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */
+#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
+ descriptor. */
+#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
+#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
+
+#define R_X86_64_NUM 38
+
#endif /* _SYS_ELFCOMMON_H */
diff --git a/com32/include/sys/i386/module.h b/com32/include/sys/i386/module.h
new file mode 100644
index 00000000..5890d771
--- /dev/null
+++ b/com32/include/sys/i386/module.h
@@ -0,0 +1,369 @@
+/**
+ * syslinux/module.h
+ *
+ * Dynamic ELF modules definitions and services.
+ */
+
+
+#include <stdio.h>
+#include <elf.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <linux/list.h>
+
+/*
+ * The maximum length of the module file name (including path), stored
+ * in the struct module descriptor.
+ */
+#define MODULE_NAME_SIZE 256
+
+/*
+ * Some common information about what kind of modules we're dealing with
+ */
+#define UNKNOWN_MODULE -1
+#define EXEC_MODULE 0
+#define LIB_MODULE 1
+
+/*
+ * Initialization and finalization function signatures
+ */
+
+
+/**
+ * module_init_t - pointer to a initialization routine
+ *
+ * The initialization routine is called after all module constructors were invoked.
+ * It takes no parameters and returns 0 if the module was initialized successfully,
+ * or a non-zero value if errors have occurred.
+ */
+typedef int (*module_init_t)(void);
+
+/**
+ * module_exit_t - pointer to a finalization routine
+ *
+ * The finalization routine is called before the module destructors are to be invoked.
+ * It simply executes some cleanup code, without error reporting.
+ */
+typedef void (*module_exit_t)(void);
+
+/**
+ * module_main_t - pointer to an entry routine
+ *
+ * The entry routine is present only in executable modules, and represents
+ * the entry point for the program.
+ */
+typedef int (*module_main_t)(int, char**);
+
+
+/**
+ * struct elf_module - structure encapsulating a module loaded in memory.
+ *
+ * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
+ * that keeps track of memory allocations, symbol information, and various other
+ * resources needed by the module itself or by other modules that depend on it.
+ *
+ * There are two types of modules:
+ * - regular modules, which are actual memory images of a loaded & linked shared
+ * object (ELF file). Memory is reserved for the struct elf_module structure itself
+ * and for the object loadable sections read from the file.
+ * - shallow modules, which are not associated with an ELF shared object, but contain
+ * metainformation about a memory region already present and containing the
+ * actual code and data. One particular usage of shallow modules is to access
+ * symbol information from the root COM32 module loaded by the SYSLINUX core.
+ * As their name suggests, memory is reserved only for the elf_module structure
+ * itself and optionally for a usually small memory region containing metainformation
+ * (symbol information).
+ *
+ * Module descriptors are related to each other through dependency information. A module
+ * can depend on symbols from other modules, and in turn it can provide symbols used
+ * by other dependant modules. This relationship can be described as a directed
+ * acyclic graph (DAG). The graph is stored using double linked lists of
+ * predecessors and successors. There is also a global linked list containing all
+ * the modules currently loaded.
+ */
+struct atexit;
+struct elf_module {
+ char name[MODULE_NAME_SIZE]; // The module name
+
+ bool shallow; // Whether the module contains any code
+
+ struct list_head required; // Head of the required modules list
+ struct list_head dependants; // Head of module dependants list
+ struct list_head list; // The list entry in the module list
+
+ module_init_t *init_func; // The initialization entry point
+ module_exit_t *exit_func; // The module finalization code
+ module_main_t main_func; // The main function (for executable modules)
+
+
+ void *module_addr; // The module location in the memory
+ Elf32_Addr base_addr; // The base address of the module
+ Elf32_Word module_size; // The module size in memory
+
+ Elf32_Word *hash_table; // The symbol hash table
+ Elf32_Word *ghash_table; // The GNU style hash table
+ char *str_table; // The string table
+ void *sym_table; // The symbol table
+ void *got; // The Global Offset Table
+ Elf32_Dyn *dyn_table; // Dynamic loading information table
+
+ Elf32_Word strtable_size; // The size of the string table
+ Elf32_Word syment_size; // The size of a symbol entry
+ Elf32_Word symtable_size; // The size of the symbol table
+
+
+ union {
+ // Transient - Data available while the module is loading
+ struct {
+ FILE *_file; // The file object of the open file
+ Elf32_Off _cr_offset; // The current offset in the open file
+ } l;
+
+ // Process execution data
+ struct {
+ jmp_buf process_exit; // Exit state
+ struct atexit *atexit_list; // atexit() chain
+ } x;
+ } u;
+
+};
+
+static inline void dump_elf_module(struct elf_module *module)
+{
+ /*
+ dprintf("module name = %s", module->name);
+ printf("base_addr = 0x%p, module_size = %d\n", module->base_addr, module->module_size);
+ printf("hash tlb = 0x%p, ghash tbl = 0x%p\n", module->hash_table, module->ghash_table);
+ printf("str tbl = 0x%p, size = %d\n", module->str_table, module->strtable_size);
+ printf("sym tbl = 0x%p, entry = %d, size = %d\n", module->sym_table, module->syment_size, module->symtable_size);
+ printf("init: %p", module->init_func);
+ printf("main: %p", module->main_func);
+ printf("exit: %p", module->exit_func);
+ printf("", module->base_addr);
+ printf("", module->base_addr);
+ printf("", module->base_addr);
+ */
+}
+
+/**
+ * struct module_dep - structure encapsulating a module dependency need
+ *
+ * This structure represents an item in a double linked list of predecessors or
+ * successors. The item contents is a pointer to the corresponding module descriptor.
+ */
+struct module_dep {
+ struct list_head list; // The list entry in the dependency list
+
+ struct elf_module *module; // The target module descriptor
+};
+
+
+
+#ifdef DYNAMIC_MODULE
+
+/*
+ * This portion is included by dynamic (ELF) module source files.
+ */
+
+#define MODULE_INIT(fn) static module_init_t __module_init \
+ __used __attribute__((section(".ctors_modinit"))) = fn
+
+#define MODULE_EXIT(fn) static module_exit_t __module_exit \
+ __used __attribute__((section(".dtors_modexit"))) = fn
+
+#else
+
+/*
+ * This portion is included by the core COM32 module.
+ */
+
+/*
+ * Accepted values for various ELF header parameters found in an ELF dynamic
+ * object.
+ */
+#define MODULE_ELF_CLASS ELFCLASS32 // 32-bit modules
+#define MODULE_ELF_CLASS_SIZE 32 // Size of a word value
+#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess
+#define MODULE_ELF_VERSION EV_CURRENT // Object version
+#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
+#define MODULE_ELF_MACHINE EM_386 // Target architecture
+
+/**
+ * Names of symbols with special meaning (treated as special cases at linking)
+ */
+#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
+#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
+#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
+
+/**
+ * modules_head - A global linked list containing all the loaded modules.
+ */
+extern struct list_head modules_head;
+
+
+/**
+ * for_each_module - iterator loop through the list of loaded modules.
+ */
+#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
+
+/**
+ * modules_init - initialize the module subsystem.
+ *
+ * This function must be called before any module operation is to be performed.
+ */
+extern int modules_init(void);
+
+
+/**
+ * modules_term - releases all resources pertaining to the module subsystem.
+ *
+ * This function should be called after all module operations.
+ */
+extern void modules_term(void);
+
+
+/**
+ * module_alloc - reserves space for a new module descriptor.
+ * @name: the file name of the module to be loaded.
+ *
+ * The function simply allocates a new module descriptor and initializes its fields
+ * in order to be used by subsequent loading operations.
+ */
+extern struct elf_module *module_alloc(const char *name);
+
+
+/**
+ * module_load - loads a regular ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a
+ * valid structure, then loads into memory the code and the data and performs
+ * any symbol relocations. A module dependency is created automatically when the
+ * relocated symbol is defined in a different module.
+ *
+ * The function returns 0 if the operation is completed successfully, and
+ * a non-zero value if an error occurs. Possible errors include invalid module
+ * structure, missing symbol definitions (unsatisfied dependencies) and memory
+ * allocation issues.
+ */
+extern int module_load(struct elf_module *module);
+
+
+/**
+ * module_load_shallow - loads a shallow ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a valid
+ * structure, then loads into memory the module metadata. The metadata currently
+ * contains a symbol table that describes code & data allocated by other means.
+ * Its current use is to describe the root COM32 module to the rest of the
+ * module subsystem.
+ */
+extern int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * The function checks to see whether the module can be safely removed, then
+ * it releases all the associated memory. This function can be applied both
+ * for standard modules and for shallow modules.
+ *
+ * A module can be safely removed from the system when no other modules reference
+ * symbols from it.
+ */
+extern int module_unload(struct elf_module *module);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * This function returns the type of module we're dealing with
+ * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
+ * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
+ * if the module has its main_func set ( in which case it's an executable ). In case
+ * it doesn't it then checks to see if init_func is set ( in which case it's a
+ * library module. If this isn't the case either we don't know what it is so bail out
+ */
+extern int get_module_type(struct elf_module *module);
+
+/**
+ * module_unloadable - checks whether the given module can be unloaded.
+ * @module: the module descriptor structure
+ *
+ * A module can be unloaded from the system when no other modules depend on it,
+ * that is, no symbols are referenced from it.
+ */
+extern int module_unloadable(struct elf_module *module);
+
+/**
+ * module_find - searches for a module by its name.
+ * @name: the name of the module, as it was specified in module_alloc.
+ *
+ * The function returns a pointer to the module descriptor, if found, or
+ * NULL otherwise.
+ */
+extern struct elf_module *module_find(const char *name);
+
+/**
+ * module_find_symbol - searches for a symbol definition in a given module.
+ * @name: the name of the symbol to be found.
+ * @module: the module descriptor structure.
+ *
+ * The function searches the module symbol table for a symbol matching exactly
+ * the name provided. The operation uses the following search algorithms, in this
+ * order:
+ * - If a GNU hash table is present in the module, it is used to find the symbol.
+ * - If the symbol cannot be found with the first method (either the hash table
+ * is not present or the symbol is not found) and if a regular (SysV) hash table
+ * is present, a search is performed on the SysV hash table. If the symbol is not
+ * found, NULL is returned.
+ * - If the second method cannot be applied, a linear search is performed by
+ * inspecting every symbol in the symbol table.
+ *
+ * If the symbol is found, a pointer to its descriptor structure is returned, and
+ * NULL otherwise.
+ */
+extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module);
+
+/**
+ * global_find_symbol - searches for a symbol definition in the entire module namespace.
+ * @name: the name of the symbol to be found.
+ * @module: an optional (may be NULL) pointer to a module descriptor variable that
+ * will hold the module where the symbol was found.
+ *
+ * The function search for the given symbol name in all the modules currently
+ * loaded in the system, in the reverse module loading order. That is, the most
+ * recently loaded module is searched first, followed by the previous one, until
+ * the first loaded module is reached.
+ *
+ * If no module contains the symbol, NULL is returned, otherwise the return value is
+ * a pointer to the symbol descriptor structure. If the module parameter is not NULL,
+ * it is filled with the address of the module descriptor where the symbol is defined.
+ */
+extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module);
+
+/**
+ * module_get_absolute - converts an memory address relative to a module base address
+ * to its absolute value in RAM.
+ * @addr: the relative address to convert.
+ * @module: the module whose base address is used for the conversion.
+ *
+ * The function returns a pointer to the absolute memory address.
+ */
+static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) {
+ return (void*)(module->base_addr + addr);
+}
+
+/**
+ * syslinux_current - get the current module process
+ */
+extern struct elf_module *__syslinux_current;
+static inline const struct elf_module *syslinux_current(void)
+{
+ return __syslinux_current;
+}
+
+
+#endif // DYNAMIC_MODULE
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
index fb72c4bc..7fcd00a5 100644
--- a/com32/include/sys/module.h
+++ b/com32/include/sys/module.h
@@ -4,371 +4,15 @@
* Dynamic ELF modules definitions and services.
*/
-
#ifndef MODULE_H_
#define MODULE_H_
-#include <stdio.h>
-#include <elf.h>
-#include <stdint.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <linux/list.h>
-
-/*
- * The maximum length of the module file name (including path), stored
- * in the struct module descriptor.
- */
-#define MODULE_NAME_SIZE 256
-
-/*
- * Some common information about what kind of modules we're dealing with
- */
-#define UNKNOWN_MODULE -1
-#define EXEC_MODULE 0
-#define LIB_MODULE 1
-
-/*
- * Initialization and finalization function signatures
- */
-
-
-/**
- * module_init_t - pointer to a initialization routine
- *
- * The initialization routine is called after all module constructors were invoked.
- * It takes no parameters and returns 0 if the module was initialized successfully,
- * or a non-zero value if errors have occurred.
- */
-typedef int (*module_init_t)(void);
-
-/**
- * module_exit_t - pointer to a finalization routine
- *
- * The finalization routine is called before the module destructors are to be invoked.
- * It simply executes some cleanup code, without error reporting.
- */
-typedef void (*module_exit_t)(void);
-
-/**
- * module_main_t - pointer to an entry routine
- *
- * The entry routine is present only in executable modules, and represents
- * the entry point for the program.
- */
-typedef int (*module_main_t)(int, char**);
-
-
-/**
- * struct elf_module - structure encapsulating a module loaded in memory.
- *
- * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
- * that keeps track of memory allocations, symbol information, and various other
- * resources needed by the module itself or by other modules that depend on it.
- *
- * There are two types of modules:
- * - regular modules, which are actual memory images of a loaded & linked shared
- * object (ELF file). Memory is reserved for the struct elf_module structure itself
- * and for the object loadable sections read from the file.
- * - shallow modules, which are not associated with an ELF shared object, but contain
- * metainformation about a memory region already present and containing the
- * actual code and data. One particular usage of shallow modules is to access
- * symbol information from the root COM32 module loaded by the SYSLINUX core.
- * As their name suggests, memory is reserved only for the elf_module structure
- * itself and optionally for a usually small memory region containing metainformation
- * (symbol information).
- *
- * Module descriptors are related to each other through dependency information. A module
- * can depend on symbols from other modules, and in turn it can provide symbols used
- * by other dependant modules. This relationship can be described as a directed
- * acyclic graph (DAG). The graph is stored using double linked lists of
- * predecessors and successors. There is also a global linked list containing all
- * the modules currently loaded.
- */
-struct atexit;
-struct elf_module {
- char name[MODULE_NAME_SIZE]; // The module name
-
- bool shallow; // Whether the module contains any code
-
- struct list_head required; // Head of the required modules list
- struct list_head dependants; // Head of module dependants list
- struct list_head list; // The list entry in the module list
-
- module_init_t *init_func; // The initialization entry point
- module_exit_t *exit_func; // The module finalization code
- module_main_t main_func; // The main function (for executable modules)
-
-
- void *module_addr; // The module location in the memory
- Elf32_Addr base_addr; // The base address of the module
- Elf32_Word module_size; // The module size in memory
-
- Elf32_Word *hash_table; // The symbol hash table
- Elf32_Word *ghash_table; // The GNU style hash table
- char *str_table; // The string table
- void *sym_table; // The symbol table
- void *got; // The Global Offset Table
- Elf32_Dyn *dyn_table; // Dynamic loading information table
-
- Elf32_Word strtable_size; // The size of the string table
- Elf32_Word syment_size; // The size of a symbol entry
- Elf32_Word symtable_size; // The size of the symbol table
-
-
- union {
- // Transient - Data available while the module is loading
- struct {
- FILE *_file; // The file object of the open file
- Elf32_Off _cr_offset; // The current offset in the open file
- } l;
-
- // Process execution data
- struct {
- jmp_buf process_exit; // Exit state
- struct atexit *atexit_list; // atexit() chain
- } x;
- } u;
-
-};
-
-static inline void dump_elf_module(struct elf_module *module)
-{
- /*
- dprintf("module name = %s", module->name);
- printf("base_addr = 0x%p, module_size = %d\n", module->base_addr, module->module_size);
- printf("hash tlb = 0x%p, ghash tbl = 0x%p\n", module->hash_table, module->ghash_table);
- printf("str tbl = 0x%p, size = %d\n", module->str_table, module->strtable_size);
- printf("sym tbl = 0x%p, entry = %d, size = %d\n", module->sym_table, module->syment_size, module->symtable_size);
- printf("init: %p", module->init_func);
- printf("main: %p", module->main_func);
- printf("exit: %p", module->exit_func);
- printf("", module->base_addr);
- printf("", module->base_addr);
- printf("", module->base_addr);
- */
-}
-
-/**
- * struct module_dep - structure encapsulating a module dependency need
- *
- * This structure represents an item in a double linked list of predecessors or
- * successors. The item contents is a pointer to the corresponding module descriptor.
- */
-struct module_dep {
- struct list_head list; // The list entry in the dependency list
-
- struct elf_module *module; // The target module descriptor
-};
-
-
-
-#ifdef DYNAMIC_MODULE
-
-/*
- * This portion is included by dynamic (ELF) module source files.
- */
-
-#define MODULE_INIT(fn) static module_init_t __module_init \
- __used __attribute__((section(".ctors_modinit"))) = fn
-
-#define MODULE_EXIT(fn) static module_exit_t __module_exit \
- __used __attribute__((section(".dtors_modexit"))) = fn
-
+#if __SIZEOF_POINTER__ == 4
+#include <i386/module.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/module.h>
#else
+#error "unsupported architecture"
+#endif
-/*
- * This portion is included by the core COM32 module.
- */
-
-/*
- * Accepted values for various ELF header parameters found in an ELF dynamic
- * object.
- */
-#define MODULE_ELF_CLASS ELFCLASS32 // 32-bit modules
-#define MODULE_ELF_CLASS_SIZE 32 // Size of a word value
-#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess
-#define MODULE_ELF_VERSION EV_CURRENT // Object version
-#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
-#define MODULE_ELF_MACHINE EM_386 // Target architecture
-
-/**
- * Names of symbols with special meaning (treated as special cases at linking)
- */
-#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
-#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
-#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
-
-/**
- * modules_head - A global linked list containing all the loaded modules.
- */
-extern struct list_head modules_head;
-
-
-/**
- * for_each_module - iterator loop through the list of loaded modules.
- */
-#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
-
-/**
- * modules_init - initialize the module subsystem.
- *
- * This function must be called before any module operation is to be performed.
- */
-extern int modules_init(void);
-
-
-/**
- * modules_term - releases all resources pertaining to the module subsystem.
- *
- * This function should be called after all module operations.
- */
-extern void modules_term(void);
-
-
-/**
- * module_alloc - reserves space for a new module descriptor.
- * @name: the file name of the module to be loaded.
- *
- * The function simply allocates a new module descriptor and initializes its fields
- * in order to be used by subsequent loading operations.
- */
-extern struct elf_module *module_alloc(const char *name);
-
-
-/**
- * module_load - loads a regular ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a
- * valid structure, then loads into memory the code and the data and performs
- * any symbol relocations. A module dependency is created automatically when the
- * relocated symbol is defined in a different module.
- *
- * The function returns 0 if the operation is completed successfully, and
- * a non-zero value if an error occurs. Possible errors include invalid module
- * structure, missing symbol definitions (unsatisfied dependencies) and memory
- * allocation issues.
- */
-extern int module_load(struct elf_module *module);
-
-
-/**
- * module_load_shallow - loads a shallow ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a valid
- * structure, then loads into memory the module metadata. The metadata currently
- * contains a symbol table that describes code & data allocated by other means.
- * Its current use is to describe the root COM32 module to the rest of the
- * module subsystem.
- */
-extern int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * The function checks to see whether the module can be safely removed, then
- * it releases all the associated memory. This function can be applied both
- * for standard modules and for shallow modules.
- *
- * A module can be safely removed from the system when no other modules reference
- * symbols from it.
- */
-extern int module_unload(struct elf_module *module);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * This function returns the type of module we're dealing with
- * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
- * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
- * if the module has its main_func set ( in which case it's an executable ). In case
- * it doesn't it then checks to see if init_func is set ( in which case it's a
- * library module. If this isn't the case either we don't know what it is so bail out
- */
-extern int get_module_type(struct elf_module *module);
-
-/**
- * module_unloadable - checks whether the given module can be unloaded.
- * @module: the module descriptor structure
- *
- * A module can be unloaded from the system when no other modules depend on it,
- * that is, no symbols are referenced from it.
- */
-extern int module_unloadable(struct elf_module *module);
-
-/**
- * module_find - searches for a module by its name.
- * @name: the name of the module, as it was specified in module_alloc.
- *
- * The function returns a pointer to the module descriptor, if found, or
- * NULL otherwise.
- */
-extern struct elf_module *module_find(const char *name);
-
-/**
- * module_find_symbol - searches for a symbol definition in a given module.
- * @name: the name of the symbol to be found.
- * @module: the module descriptor structure.
- *
- * The function searches the module symbol table for a symbol matching exactly
- * the name provided. The operation uses the following search algorithms, in this
- * order:
- * - If a GNU hash table is present in the module, it is used to find the symbol.
- * - If the symbol cannot be found with the first method (either the hash table
- * is not present or the symbol is not found) and if a regular (SysV) hash table
- * is present, a search is performed on the SysV hash table. If the symbol is not
- * found, NULL is returned.
- * - If the second method cannot be applied, a linear search is performed by
- * inspecting every symbol in the symbol table.
- *
- * If the symbol is found, a pointer to its descriptor structure is returned, and
- * NULL otherwise.
- */
-extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module);
-
-/**
- * global_find_symbol - searches for a symbol definition in the entire module namespace.
- * @name: the name of the symbol to be found.
- * @module: an optional (may be NULL) pointer to a module descriptor variable that
- * will hold the module where the symbol was found.
- *
- * The function search for the given symbol name in all the modules currently
- * loaded in the system, in the reverse module loading order. That is, the most
- * recently loaded module is searched first, followed by the previous one, until
- * the first loaded module is reached.
- *
- * If no module contains the symbol, NULL is returned, otherwise the return value is
- * a pointer to the symbol descriptor structure. If the module parameter is not NULL,
- * it is filled with the address of the module descriptor where the symbol is defined.
- */
-extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module);
-
-/**
- * module_get_absolute - converts an memory address relative to a module base address
- * to its absolute value in RAM.
- * @addr: the relative address to convert.
- * @module: the module whose base address is used for the conversion.
- *
- * The function returns a pointer to the absolute memory address.
- */
-static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) {
- return (void*)(module->base_addr + addr);
-}
-
-/**
- * syslinux_current - get the current module process
- */
-extern struct elf_module *__syslinux_current;
-static inline const struct elf_module *syslinux_current(void)
-{
- return __syslinux_current;
-}
-
-
-#endif // DYNAMIC_MODULE
-
-#endif // MODULE_H_
+#endif
diff --git a/com32/include/sys/x86_64/module.h b/com32/include/sys/x86_64/module.h
new file mode 100644
index 00000000..032fd549
--- /dev/null
+++ b/com32/include/sys/x86_64/module.h
@@ -0,0 +1,369 @@
+/**
+ * syslinux/module.h
+ *
+ * Dynamic ELF64 modules definitions and services.
+ */
+
+
+#include <stdio.h>
+#include <elf.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <linux/list.h>
+
+/*
+ * The maximum length of the module file name (including path), stored
+ * in the struct module descriptor.
+ */
+#define MODULE_NAME_SIZE 256
+
+/*
+ * Some common information about what kind of modules we're dealing with
+ */
+#define UNKNOWN_MODULE -1
+#define EXEC_MODULE 0
+#define LIB_MODULE 1
+
+/*
+ * Initialization and finalization function signatures
+ */
+
+
+/**
+ * module_init_t - pointer to a initialization routine
+ *
+ * The initialization routine is called after all module constructors were invoked.
+ * It takes no parameters and returns 0 if the module was initialized successfully,
+ * or a non-zero value if errors have occurred.
+ */
+typedef int64_t (*module_init_t)(void);
+
+/**
+ * module_exit_t - pointer to a finalization routine
+ *
+ * The finalization routine is called before the module destructors are to be invoked.
+ * It simply executes some cleanup code, without error reporting.
+ */
+typedef void (*module_exit_t)(void);
+
+/**
+ * module_main_t - pointer to an entry routine
+ *
+ * The entry routine is present only in executable modules, and represents
+ * the entry point for the program.
+ */
+typedef int64_t (*module_main_t)(int, char**);
+
+
+/**
+ * struct elf_module - structure encapsulating a module loaded in memory.
+ *
+ * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
+ * that keeps track of memory allocations, symbol information, and various other
+ * resources needed by the module itself or by other modules that depend on it.
+ *
+ * There are two types of modules:
+ * - regular modules, which are actual memory images of a loaded & linked shared
+ * object (ELF file). Memory is reserved for the struct elf_module structure itself
+ * and for the object loadable sections read from the file.
+ * - shallow modules, which are not associated with an ELF shared object, but contain
+ * metainformation about a memory region already present and containing the
+ * actual code and data. One particular usage of shallow modules is to access
+ * symbol information from the root COM32 module loaded by the SYSLINUX core.
+ * As their name suggests, memory is reserved only for the elf_module structure
+ * itself and optionally for a usually small memory region containing metainformation
+ * (symbol information).
+ *
+ * Module descriptors are related to each other through dependency information. A module
+ * can depend on symbols from other modules, and in turn it can provide symbols used
+ * by other dependant modules. This relationship can be described as a directed
+ * acyclic graph (DAG). The graph is stored using double linked lists of
+ * predecessors and successors. There is also a global linked list containing all
+ * the modules currently loaded.
+ */
+struct atexit;
+struct elf_module {
+ char name[MODULE_NAME_SIZE]; // The module name
+
+ bool shallow; // Whether the module contains any code
+
+ struct list_head required; // Head of the required modules list
+ struct list_head dependants; // Head of module dependants list
+ struct list_head list; // The list entry in the module list
+
+ module_init_t *init_func; // The initialization entry point
+ module_exit_t *exit_func; // The module finalization code
+ module_main_t main_func; // The main function (for executable modules)
+
+
+ void *module_addr; // The module location in the memory
+ Elf64_Addr base_addr; // The base address of the module
+ Elf64_Word module_size; // The module size in memory
+
+ Elf64_Word *hash_table; // The symbol hash table
+ Elf64_Word *ghash_table; // The GNU style hash table
+ char *str_table; // The string table
+ void *sym_table; // The symbol table
+ void *got; // The Global Offset Table
+ Elf64_Dyn *dyn_table; // Dynamic loading information table
+
+ Elf64_Word strtable_size; // The size of the string table
+ Elf64_Word syment_size; // The size of a symbol entry
+ Elf64_Word symtable_size; // The size of the symbol table
+
+
+ union {
+ // Transient - Data available while the module is loading
+ struct {
+ FILE *_file; // The file object of the open file
+ Elf64_Off _cr_offset; // The current offset in the open file
+ } l;
+
+ // Process execution data
+ struct {
+ jmp_buf process_exit; // Exit state
+ struct atexit *atexit_list; // atexit() chain
+ } x;
+ } u;
+
+};
+
+static inline void dump_elf_module(struct elf_module *module)
+{
+ /*
+ dprintf("module name = %s", module->name);
+ printf("base_addr = 0x%p, module_size = %d\n", module->base_addr, module->module_size);
+ printf("hash tlb = 0x%p, ghash tbl = 0x%p\n", module->hash_table, module->ghash_table);
+ printf("str tbl = 0x%p, size = %d\n", module->str_table, module->strtable_size);
+ printf("sym tbl = 0x%p, entry = %d, size = %d\n", module->sym_table, module->syment_size, module->symtable_size);
+ printf("init: %p", module->init_func);
+ printf("main: %p", module->main_func);
+ printf("exit: %p", module->exit_func);
+ printf("", module->base_addr);
+ printf("", module->base_addr);
+ printf("", module->base_addr);
+ */
+}
+
+/**
+ * struct module_dep - structure encapsulating a module dependency need
+ *
+ * This structure represents an item in a double linked list of predecessors or
+ * successors. The item contents is a pointer to the corresponding module descriptor.
+ */
+struct module_dep {
+ struct list_head list; // The list entry in the dependency list
+
+ struct elf_module *module; // The target module descriptor
+};
+
+
+
+#ifdef DYNAMIC_MODULE
+
+/*
+ * This portion is included by dynamic (ELF) module source files.
+ */
+
+#define MODULE_INIT(fn) static module_init_t __module_init \
+ __used __attribute__((section(".ctors_modinit"))) = fn
+
+#define MODULE_EXIT(fn) static module_exit_t __module_exit \
+ __used __attribute__((section(".dtors_modexit"))) = fn
+
+#else
+
+/*
+ * This portion is included by the core COM32 module.
+ */
+
+/*
+ * Accepted values for various ELF header parameters found in an ELF dynamic
+ * object.
+ */
+#define MODULE_ELF_CLASS ELFCLASS64 // 64-bit modules
+#define MODULE_ELF_CLASS_SIZE 64 // Size of a word value
+#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess
+#define MODULE_ELF_VERSION EV_CURRENT // Object version
+#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
+#define MODULE_ELF_MACHINE EM_X86_64 // Target architecture
+
+/**
+ * Names of symbols with special meaning (treated as special cases at linking)
+ */
+#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
+#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
+#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
+
+/**
+ * modules_head - A global linked list containing all the loaded modules.
+ */
+extern struct list_head modules_head;
+
+
+/**
+ * for_each_module - iterator loop through the list of loaded modules.
+ */
+#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
+
+/**
+ * modules_init - initialize the module subsystem.
+ *
+ * This function must be called before any module operation is to be performed.
+ */
+extern int modules_init(void);
+
+
+/**
+ * modules_term - releases all resources pertaining to the module subsystem.
+ *
+ * This function should be called after all module operations.
+ */
+extern void modules_term(void);
+
+
+/**
+ * module_alloc - reserves space for a new module descriptor.
+ * @name: the file name of the module to be loaded.
+ *
+ * The function simply allocates a new module descriptor and initializes its fields
+ * in order to be used by subsequent loading operations.
+ */
+extern struct elf_module *module_alloc(const char *name);
+
+
+/**
+ * module_load - loads a regular ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a
+ * valid structure, then loads into memory the code and the data and performs
+ * any symbol relocations. A module dependency is created automatically when the
+ * relocated symbol is defined in a different module.
+ *
+ * The function returns 0 if the operation is completed successfully, and
+ * a non-zero value if an error occurs. Possible errors include invalid module
+ * structure, missing symbol definitions (unsatisfied dependencies) and memory
+ * allocation issues.
+ */
+extern int module_load(struct elf_module *module);
+
+
+/**
+ * module_load_shallow - loads a shallow ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a valid
+ * structure, then loads into memory the module metadata. The metadata currently
+ * contains a symbol table that describes code & data allocated by other means.
+ * Its current use is to describe the root COM32 module to the rest of the
+ * module subsystem.
+ */
+extern int module_load_shallow(struct elf_module *module, Elf64_Addr base_addr);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * The function checks to see whether the module can be safely removed, then
+ * it releases all the associated memory. This function can be applied both
+ * for standard modules and for shallow modules.
+ *
+ * A module can be safely removed from the system when no other modules reference
+ * symbols from it.
+ */
+extern int module_unload(struct elf_module *module);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * This function returns the type of module we're dealing with
+ * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
+ * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
+ * if the module has its main_func set ( in which case it's an executable ). In case
+ * it doesn't it then checks to see if init_func is set ( in which case it's a
+ * library module. If this isn't the case either we don't know what it is so bail out
+ */
+extern int get_module_type(struct elf_module *module);
+
+/**
+ * module_unloadable - checks whether the given module can be unloaded.
+ * @module: the module descriptor structure
+ *
+ * A module can be unloaded from the system when no other modules depend on it,
+ * that is, no symbols are referenced from it.
+ */
+extern int module_unloadable(struct elf_module *module);
+
+/**
+ * module_find - searches for a module by its name.
+ * @name: the name of the module, as it was specified in module_alloc.
+ *
+ * The function returns a pointer to the module descriptor, if found, or
+ * NULL otherwise.
+ */
+extern struct elf_module *module_find(const char *name);
+
+/**
+ * module_find_symbol - searches for a symbol definition in a given module.
+ * @name: the name of the symbol to be found.
+ * @module: the module descriptor structure.
+ *
+ * The function searches the module symbol table for a symbol matching exactly
+ * the name provided. The operation uses the following search algorithms, in this
+ * order:
+ * - If a GNU hash table is present in the module, it is used to find the symbol.
+ * - If the symbol cannot be found with the first method (either the hash table
+ * is not present or the symbol is not found) and if a regular (SysV) hash table
+ * is present, a search is performed on the SysV hash table. If the symbol is not
+ * found, NULL is returned.
+ * - If the second method cannot be applied, a linear search is performed by
+ * inspecting every symbol in the symbol table.
+ *
+ * If the symbol is found, a pointer to its descriptor structure is returned, and
+ * NULL otherwise.
+ */
+extern Elf64_Sym *module_find_symbol(const char *name, struct elf_module *module);
+
+/**
+ * global_find_symbol - searches for a symbol definition in the entire module namespace.
+ * @name: the name of the symbol to be found.
+ * @module: an optional (may be NULL) pointer to a module descriptor variable that
+ * will hold the module where the symbol was found.
+ *
+ * The function search for the given symbol name in all the modules currently
+ * loaded in the system, in the reverse module loading order. That is, the most
+ * recently loaded module is searched first, followed by the previous one, until
+ * the first loaded module is reached.
+ *
+ * If no module contains the symbol, NULL is returned, otherwise the return value is
+ * a pointer to the symbol descriptor structure. If the module parameter is not NULL,
+ * it is filled with the address of the module descriptor where the symbol is defined.
+ */
+extern Elf64_Sym *global_find_symbol(const char *name, struct elf_module **module);
+
+/**
+ * module_get_absolute - converts an memory address relative to a module base address
+ * to its absolute value in RAM.
+ * @addr: the relative address to convert.
+ * @module: the module whose base address is used for the conversion.
+ *
+ * The function returns a pointer to the absolute memory address.
+ */
+static inline void *module_get_absolute(Elf64_Addr addr, struct elf_module *module) {
+ return (void*)(module->base_addr + addr);
+}
+
+/**
+ * syslinux_current - get the current module process
+ */
+extern struct elf_module *__syslinux_current;
+static inline const struct elf_module *syslinux_current(void)
+{
+ return __syslinux_current;
+}
+
+
+#endif // DYNAMIC_MODULE
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 71ee0f03..1e33db8e 100644
--- a/com32/lib/sys/module/common.c
+++ b/com32/lib/sys/module/common.c
@@ -219,6 +219,11 @@ struct elf_module *module_find(const char *name) {
}
+// Mouli: This is checking the header for 32bit machine
+// Support 64bit architecture as well.
+// Parts of the ELF header checked are common to both ELF32 and ELF64
+// Adding simple checks for both 32bit and 64bit should work (hopefully)
+//
// Performs verifications on ELF header to assure that the open file is a
// valid SYSLINUX ELF module.
int check_header_common(Elf32_Ehdr *elf_hdr) {
@@ -232,7 +237,8 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
+ if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 ||
+ elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) {
DBG_PRINT("Invalid ELF class code\n");
return -1;
}
@@ -248,10 +254,10 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
+ if (elf_hdr->e_machine != EM_386 ||
+ elf_hdr->e_machine != EM_X86_64) {
DBG_PRINT("Invalid ELF architecture\n");
return -1;
- }
return 0;
}
diff --git a/com32/lib/sys/module/common.h b/com32/lib/sys/module/common.h
index 6259df51..928fe139 100644
--- a/com32/lib/sys/module/common.h
+++ b/com32/lib/sys/module/common.h
@@ -15,7 +15,6 @@
#include "elfutils.h"
-
// Performs an operation and jumps to a given label if an error occurs
#define CHECKED(res, expr, error) \
do { \
diff --git a/com32/lib/sys/module/elfutils.h b/com32/lib/sys/module/elfutils.h
index b18968f3..b6750ae7 100644
--- a/com32/lib/sys/module/elfutils.h
+++ b/com32/lib/sys/module/elfutils.h
@@ -1,64 +1,7 @@
-#ifndef ELF_UTILS_H_
-#define ELF_UTILS_H_
-
-#include <elf.h>
-#include <stdlib.h>
-
-/**
- * elf_get_header - Returns a pointer to the ELF header structure.
- * @elf_image: pointer to the ELF file image in memory
- */
-static inline Elf32_Ehdr *elf_get_header(void *elf_image) {
- return (Elf32_Ehdr*)elf_image;
-}
-
-/**
- * elf_get_pht - Returns a pointer to the first entry in the PHT.
- * @elf_image: pointer to the ELF file image in memory
- */
-static inline Elf32_Phdr *elf_get_pht(void *elf_image) {
- Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
-
- return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff);
-}
-
-//
-/**
- * elf_get_ph - Returns the element with the given index in the PTH
- * @elf_image: pointer to the ELF file image in memory
- * @index: the index of the PHT entry to look for
- */
-static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index) {
- Elf32_Phdr *elf_pht = elf_get_pht(elf_image);
- Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
-
- return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize);
-}
-
-/**
- * elf_hash - Returns the index in a SysV hash table for the symbol name.
- * @name: the name of the symbol to look for
- */
-extern unsigned long elf_hash(const unsigned char *name);
-
-/**
- * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
- * @name: the name of the symbol to look for
- */
-extern unsigned long elf_gnu_hash(const unsigned char *name);
-
-/**
- * elf_malloc - Allocates memory to be used by ELF module contents.
- * @memptr: pointer to a variable to hold the address of the allocated block.
- * @alignment: alignment constraints of the block
- * @size: the required size of the block
- */
-extern int elf_malloc(void **memptr, size_t alignment, size_t size);
-
-/**
- * elf_free - Releases memory previously allocated by elf_malloc.
- * @memptr: the address of the allocated block
- */
-extern void elf_free(void *memptr);
-
-#endif /*ELF_UTILS_H_*/
+#if __SIZEOF_POINTER__ == 4
+#include <i386/elfutils.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/elfutils.h>
+#else
+#error "unsupported architecture"
+#endif
diff --git a/com32/lib/sys/module/i386/common.c b/com32/lib/sys/module/i386/common.c
new file mode 100644
index 00000000..41e71e83
--- /dev/null
+++ b/com32/lib/sys/module/i386/common.c
@@ -0,0 +1,571 @@
+/*
+ * common.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <stdio.h>
+#include <elf.h>
+#include <string.h>
+#include <fs.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+
+#include "elfutils.h"
+#include "common.h"
+
+/**
+ * The one and only list of loaded modules
+ */
+LIST_HEAD(modules_head);
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+void print_elf_ehdr(Elf32_Ehdr *ehdr) {
+ int i;
+
+ fprintf(stderr, "Identification:\t");
+ for (i=0; i < EI_NIDENT; i++) {
+ printf("%d ", ehdr->e_ident[i]);
+ }
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
+ fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
+ fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
+ fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
+ fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
+ fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
+ //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
+ //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf32_Ehdr));
+ fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
+ ehdr->e_shnum);
+}
+
+void print_elf_symbols(struct elf_module *module) {
+ unsigned int i;
+ Elf32_Sym *crt_sym;
+
+ for (i = 1; i < module->symtable_size; i++)
+ {
+ crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+
+ fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
+
+ }
+}
+#endif //ELF_DEBUG
+
+static FILE *findpath(char *name)
+{
+ char path[FILENAME_MAX];
+ FILE *f;
+ char *p, *n;
+ int i;
+
+ p = PATH;
+again:
+ memset(path, '\0', sizeof(path));
+ i = 0;
+ while (*p && *p != ':' && i < FILENAME_MAX) {
+ path[i++] = *p++;
+ }
+ //path[i] = '\0'; // without null the strcmp will fail
+
+ if (*p == ':')
+ p++;
+
+ if (!strcmp(path, ".")) {
+ if (!core_getcwd(path, sizeof(path))) {
+ DBG_PRINT("Could not get cwd\n");
+ return NULL;
+ }
+ i = strlen(path);
+ }
+
+ n = name;
+ while (*n && i < FILENAME_MAX)
+ path[i++] = *n++;
+ path[i] = '\0';
+
+ f = fopen(path, "rb");
+ if (f)
+ return f;
+
+ if (p >= PATH && p < PATH + strlen(PATH))
+ goto again;
+
+ return NULL;
+}
+
+/*
+ * Image files manipulation routines
+ */
+
+int image_load(struct elf_module *module)
+{
+ module->u.l._file = findpath(module->name);
+
+ if (module->u.l._file == NULL) {
+ DBG_PRINT("Could not open object file '%s'\n", module->name);
+ goto error;
+ }
+
+ module->u.l._cr_offset = 0;
+
+ return 0;
+
+error:
+ if (module->u.l._file != NULL) {
+ fclose(module->u.l._file);
+ module->u.l._file = NULL;
+ }
+
+ return -1;
+}
+
+
+int image_unload(struct elf_module *module) {
+ if (module->u.l._file != NULL) {
+ fclose(module->u.l._file);
+ module->u.l._file = NULL;
+
+ }
+ module->u.l._cr_offset = 0;
+
+ return 0;
+}
+
+int image_read(void *buff, size_t size, struct elf_module *module) {
+ size_t result = fread(buff, size, 1, module->u.l._file);
+
+ if (result < 1)
+ return -1;
+
+ module->u.l._cr_offset += size;
+ return 0;
+}
+
+int image_skip(size_t size, struct elf_module *module) {
+ void *skip_buff = NULL;
+ size_t result;
+
+ if (size == 0)
+ return 0;
+
+ skip_buff = malloc(size);
+ result = fread(skip_buff, size, 1, module->u.l._file);
+ free(skip_buff);
+
+ if (result < 1)
+ return -1;
+
+ module->u.l._cr_offset += size;
+ return 0;
+}
+
+int image_seek(Elf32_Off offset, struct elf_module *module) {
+ if (offset < module->u.l._cr_offset) // Cannot seek backwards
+ return -1;
+
+ return image_skip(offset - module->u.l._cr_offset, module);
+}
+
+
+// Initialization of the module subsystem
+int modules_init(void) {
+ return 0;
+}
+
+// Termination of the module subsystem
+void modules_term(void) {
+
+}
+
+// Allocates the structure for a new module
+struct elf_module *module_alloc(const char *name) {
+ struct elf_module *result = malloc(sizeof(struct elf_module));
+
+ memset(result, 0, sizeof(struct elf_module));
+
+ INIT_LIST_HEAD(&result->list);
+ INIT_LIST_HEAD(&result->required);
+ INIT_LIST_HEAD(&result->dependants);
+
+ strncpy(result->name, name, MODULE_NAME_SIZE);
+
+ return result;
+}
+
+struct module_dep *module_dep_alloc(struct elf_module *module) {
+ struct module_dep *result = malloc(sizeof(struct module_dep));
+
+ INIT_LIST_HEAD (&result->list);
+
+ result->module = module;
+
+ return result;
+}
+
+struct elf_module *module_find(const char *name) {
+ struct elf_module *cr_module;
+
+ for_each_module(cr_module) {
+ if (strcmp(cr_module->name, name) == 0)
+ return cr_module;
+ }
+
+ return NULL;
+}
+
+
+// Performs verifications on ELF header to assure that the open file is a
+// valid SYSLINUX ELF module.
+int check_header_common(Elf32_Ehdr *elf_hdr) {
+ // Check the header magic
+ if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
+
+ DBG_PRINT("The file is not an ELF object\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
+ DBG_PRINT("Invalid ELF class code\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
+ DBG_PRINT("Invalid ELF data encoding\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
+ elf_hdr->e_version != MODULE_ELF_VERSION) {
+ DBG_PRINT("Invalid ELF file version\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
+ DBG_PRINT("Invalid ELF architecture\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
+ struct module_dep *crt_dep;
+ struct module_dep *new_dep;
+
+ list_for_each_entry(crt_dep, &req->dependants, list) {
+ if (crt_dep->module == dep) {
+ // The dependency is already enforced
+ return 0;
+ }
+ }
+
+ new_dep = module_dep_alloc(req);
+ list_add(&new_dep->list, &dep->required);
+
+ new_dep = module_dep_alloc(dep);
+ list_add(&new_dep->list, &req->dependants);
+
+ return 0;
+}
+
+int clear_dependency(struct elf_module *req, struct elf_module *dep) {
+ struct module_dep *crt_dep = NULL;
+ int found = 0;
+
+ list_for_each_entry(crt_dep, &req->dependants, list) {
+ if (crt_dep->module == dep) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ list_del(&crt_dep->list);
+ free(crt_dep);
+ }
+
+ found = 0;
+
+ list_for_each_entry(crt_dep, &dep->required, list) {
+ if (crt_dep->module == req) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ list_del(&crt_dep->list);
+ free(crt_dep);
+ }
+
+ return 0;
+}
+
+int check_symbols(struct elf_module *module)
+{
+ unsigned int i;
+ Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
+ char *crt_name;
+ struct elf_module *crt_module;
+
+ int strong_count;
+ int weak_count;
+
+ for(i = 1; i < module->symtable_size; i++)
+ {
+ crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size);
+ crt_name = module->str_table + crt_sym->st_name;
+
+ strong_count = 0;
+ weak_count = 0;
+
+ for_each_module(crt_module)
+ {
+ ref_sym = module_find_symbol(crt_name, crt_module);
+
+ // If we found a definition for our symbol...
+ if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
+ {
+ switch (ELF32_ST_BIND(ref_sym->st_info))
+ {
+ case STB_GLOBAL:
+ strong_count++;
+ break;
+ case STB_WEAK:
+ weak_count++;
+ break;
+ }
+ }
+ }
+
+ if (crt_sym->st_shndx == SHN_UNDEF)
+ {
+ // We have an undefined symbol
+ if (strong_count == 0 && weak_count == 0)
+ {
+ DBG_PRINT("Symbol %s is undefined\n", crt_name);
+ //printf("Undef symbol FAIL: %s\n",crt_name);
+ return -1;
+ }
+ }
+ else
+ {
+ if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
+ {
+ // It's not an error - at relocation, the most recent symbol
+ // will be considered
+ DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name);
+ }
+ }
+ //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
+ }
+
+ return 0;
+}
+
+int module_unloadable(struct elf_module *module) {
+ if (!list_empty(&module->dependants))
+ return 0;
+
+ return 1;
+}
+
+
+// Unloads the module from the system and releases all the associated memory
+int module_unload(struct elf_module *module) {
+ struct module_dep *crt_dep, *tmp;
+ // Make sure nobody needs us
+ if (!module_unloadable(module)) {
+ DBG_PRINT("Module is required by other modules.\n");
+ return -1;
+ }
+
+ // Remove any dependency information
+ list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
+ clear_dependency(crt_dep->module, module);
+ }
+
+ // Remove the module from the module list
+ list_del_init(&module->list);
+
+ // Release the loaded segments or sections
+ if (module->module_addr != NULL) {
+ elf_free(module->module_addr);
+
+ DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
+ module->name);
+ }
+ // Release the module structure
+ free(module);
+
+ return 0;
+}
+
+
+static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
+ unsigned long h = elf_hash((const unsigned char*)name);
+ Elf32_Word *cr_word = module->hash_table;
+
+ Elf32_Word nbucket = *cr_word++;
+ cr_word++; // Skip nchain
+
+ Elf32_Word *bkt = cr_word;
+ Elf32_Word *chn = cr_word + nbucket;
+
+ Elf32_Word crt_index = bkt[h % module->hash_table[0]];
+ Elf32_Sym *crt_sym;
+
+
+ while (crt_index != STN_UNDEF) {
+ crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size);
+
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
+ return crt_sym;
+
+ crt_index = chn[crt_index];
+ }
+
+ return NULL;
+}
+
+static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
+ unsigned long h = elf_gnu_hash((const unsigned char*)name);
+
+ // Setup code (TODO: Optimize this by computing only once)
+ Elf32_Word *cr_word = module->ghash_table;
+ Elf32_Word nbucket = *cr_word++;
+ Elf32_Word symbias = *cr_word++;
+ Elf32_Word bitmask_nwords = *cr_word++;
+
+
+ if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
+ DBG_PRINT("Invalid GNU Hash structure\n");
+ return NULL;
+ }
+
+ Elf32_Word gnu_shift = *cr_word++;
+
+ Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
+ cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
+
+ Elf32_Word *gnu_buckets = cr_word;
+ cr_word += nbucket;
+
+ Elf32_Word *gnu_chain_zero = cr_word - symbias;
+
+ // Computations
+ Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
+ (bitmask_nwords - 1)];
+
+ unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
+ unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
+
+ if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
+ unsigned long rem;
+ Elf32_Word bucket;
+
+ rem = h % nbucket;
+
+ bucket = gnu_buckets[rem];
+
+ if (bucket != 0) {
+ const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
+
+ do {
+ if (((*hasharr ^ h ) >> 1) == 0) {
+ Elf32_Sym *crt_sym = (Elf32_Sym*)(module->sym_table +
+ (hasharr - gnu_chain_zero) * module->syment_size);
+
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
+ return crt_sym;
+ }
+ }
+ } while ((*hasharr++ & 1u) == 0);
+ }
+ }
+
+ return NULL;
+}
+
+static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
+{
+
+ unsigned int i;
+ Elf32_Sym *crt_sym;
+
+ for (i=1; i < module->symtable_size; i++)
+ {
+ crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
+ {
+ return crt_sym;
+ }
+ }
+
+ return NULL;
+}
+
+Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
+ Elf32_Sym *result = NULL;
+
+
+ if (module->ghash_table != NULL)
+ result = module_find_symbol_gnu(name, module);
+
+ if (result == NULL)
+ {
+ if (module->hash_table != NULL)
+ {
+ //printf("Attempting SYSV Symbol search\n");
+ result = module_find_symbol_sysv(name, module);
+ }
+ else
+ {
+ //printf("Attempting Iterative Symbol search\n");
+ result = module_find_symbol_iterate(name, module);
+ }
+ }
+
+ return result;
+}
+
+Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
+ struct elf_module *crt_module;
+ Elf32_Sym *crt_sym = NULL;
+ Elf32_Sym *result = NULL;
+
+ for_each_module(crt_module) {
+ crt_sym = module_find_symbol(name, crt_module);
+
+ if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
+ switch (ELF32_ST_BIND(crt_sym->st_info)) {
+ case STB_GLOBAL:
+ if (module != NULL) {
+ *module = crt_module;
+ }
+ return crt_sym;
+ case STB_WEAK:
+ // Consider only the first weak symbol
+ if (result == NULL) {
+ if (module != NULL) {
+ *module = crt_module;
+ }
+ result = crt_sym;
+ }
+ break;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/com32/lib/sys/module/i386/common.h b/com32/lib/sys/module/i386/common.h
new file mode 100644
index 00000000..6259df51
--- /dev/null
+++ b/com32/lib/sys/module/i386/common.h
@@ -0,0 +1,65 @@
+/*
+ * common.h - Common internal operations performed by the module subsystem
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include <stdio.h>
+
+#include <sys/module.h>
+#include <linux/list.h>
+
+#include "elfutils.h"
+
+
+// Performs an operation and jumps to a given label if an error occurs
+#define CHECKED(res, expr, error) \
+ do { \
+ (res) = (expr); \
+ if ((res) < 0) \
+ goto error; \
+ } while (0)
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+//#define ELF_DEBUG
+
+#ifdef ELF_DEBUG
+#define DBG_PRINT(fmt, args...) fprintf(stderr, "[ELF] " fmt, ##args)
+#else
+#define DBG_PRINT(fmt, args...) // Expand to nothing
+#endif
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+extern void print_elf_ehdr(Elf32_Ehdr *ehdr);
+extern void print_elf_symbols(struct elf_module *module);
+#endif //ELF_DEBUG
+
+
+/*
+ * Image files manipulation routines
+ */
+
+extern int image_load(struct elf_module *module);
+extern int image_unload(struct elf_module *module);
+extern int image_read(void *buff, size_t size, struct elf_module *module);
+extern int image_skip(size_t size, struct elf_module *module);
+extern int image_seek(Elf32_Off offset, struct elf_module *module);
+
+extern struct module_dep *module_dep_alloc(struct elf_module *module);
+
+extern int check_header_common(Elf32_Ehdr *elf_hdr);
+
+extern int enforce_dependency(struct elf_module *req, struct elf_module *dep);
+extern int clear_dependency(struct elf_module *req, struct elf_module *dep);
+
+extern int check_symbols(struct elf_module *module);
+
+
+#endif /* COMMON_H_ */
diff --git a/com32/lib/sys/module/i386/elf_module.c b/com32/lib/sys/module/i386/elf_module.c
new file mode 100644
index 00000000..864344a7
--- /dev/null
+++ b/com32/lib/sys/module/i386/elf_module.c
@@ -0,0 +1,555 @@
+/*
+ * elf_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+#include <dprintf.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+
+#include "elfutils.h"
+#include "common.h"
+
+#define MAX_NR_DEPS 64
+
+static int check_header(Elf32_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_type != MODULE_ELF_TYPE) {
+ DBG_PRINT("The ELF file must be a shared object\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_phoff == 0x00000000) {
+ DBG_PRINT("PHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * The implementation assumes that the loadable segments are present
+ * in the PHT sorted by their offsets, so that only forward seeks would
+ * be necessary.
+ */
+static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ void *pht = NULL;
+ Elf32_Phdr *cr_pht;
+
+ Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr
+ Elf32_Addr max_addr = 0x00000000; // Max. ELF vaddr
+ Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign()
+ Elf32_Addr min_alloc, max_alloc; // Min. and max. aligned allocables
+
+ Elf32_Addr dyn_addr = 0x00000000;
+
+ // Get to the PHT
+ image_seek(elf_hdr->e_phoff, module);
+
+ // Load the PHT
+ pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
+ image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
+
+ // Compute the memory needings of the module
+ for (i=0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ switch (cr_pht->p_type) {
+ case PT_LOAD:
+ if (i == 0) {
+ min_addr = cr_pht->p_vaddr;
+ } else {
+ min_addr = MIN(min_addr, cr_pht->p_vaddr);
+ }
+
+ max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
+ max_align = MAX(max_align, cr_pht->p_align);
+ break;
+ case PT_DYNAMIC:
+ dyn_addr = cr_pht->p_vaddr;
+ break;
+ default:
+ // Unsupported - ignore
+ break;
+ }
+ }
+
+ if (max_addr - min_addr == 0) {
+ // No loadable segments
+ DBG_PRINT("No loadable segments found\n");
+ goto out;
+ }
+
+ if (dyn_addr == 0) {
+ DBG_PRINT("No dynamic information segment found\n");
+ goto out;
+ }
+
+ // The minimum address that should be allocated
+ min_alloc = min_addr - (min_addr % max_align);
+
+ // The maximum address that should be allocated
+ max_alloc = max_addr - (max_addr % max_align);
+ if (max_addr % max_align > 0)
+ max_alloc += max_align;
+
+
+ if (elf_malloc(&module->module_addr,
+ max_align,
+ max_alloc-min_alloc) != 0) {
+
+ DBG_PRINT("Could not allocate segments\n");
+ goto out;
+ }
+
+ module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc;
+ module->module_size = max_alloc - min_alloc;
+
+ // Zero-initialize the memory
+ memset(module->module_addr, 0, module->module_size);
+
+ for (i = 0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ if (cr_pht->p_type == PT_LOAD) {
+ // Copy the segment at its destination
+ if (cr_pht->p_offset < module->u.l._cr_offset) {
+ // The segment contains data before the current offset
+ // It can be discarded without worry - it would contain only
+ // headers
+ Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
+
+ if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+ cr_pht->p_filesz - aux_off, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ } else {
+ if (image_seek(cr_pht->p_offset, module) < 0) {
+ res = -1;
+ goto out;
+ }
+
+ if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
+ cr_pht->p_filesz, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ }
+
+ /*
+ DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
+ cr_pht->p_filesz,
+ cr_pht->p_vaddr,
+ (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
+ */
+ }
+ }
+
+ // Setup dynamic segment location
+ module->dyn_table = module_get_absolute(dyn_addr, module);
+
+ /*
+ DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
+ max_align);
+ DBG_PRINT("Module size: 0x%08x\n", module->module_size);
+ */
+
+out:
+ // Free up allocated memory
+ if (pht != NULL)
+ free(pht);
+
+ return res;
+}
+
+static int nr_needed;
+static Elf32_Word needed[MAX_NR_DEPS];;
+
+static int prepare_dynlinking(struct elf_module *module) {
+ Elf32_Dyn *dyn_entry = module->dyn_table;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch (dyn_entry->d_tag) {
+ case DT_NEEDED:
+ /*
+ * It's unlikely there'll be more than
+ * MAX_NR_DEPS DT_NEEDED entries but if there
+ * are then inform the user that we ran out of
+ * space.
+ */
+ if (nr_needed < MAX_NR_DEPS)
+ needed[nr_needed++] = dyn_entry->d_un.d_ptr;
+ else {
+ printf("Too many dependencies!\n");
+ return -1;
+ }
+ break;
+ case DT_HASH:
+ module->hash_table =
+ (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_GNU_HASH:
+ module->ghash_table =
+ (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRTAB:
+ module->str_table =
+ (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_SYMTAB:
+ module->sym_table =
+ module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRSZ:
+ module->strtable_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_SYMENT:
+ module->syment_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTGOT: // The first entry in the GOT
+ module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ // Now compute the number of symbols in the symbol table
+ if (module->ghash_table != NULL) {
+ module->symtable_size = module->ghash_table[1];
+ } else {
+ module->symtable_size = module->hash_table[1];
+ }
+
+ return 0;
+}
+
+
+static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
+ Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
+
+ // The symbol reference index
+ Elf32_Word sym = ELF32_R_SYM(rel->r_info);
+ unsigned char type = ELF32_R_TYPE(rel->r_info);
+
+ // The symbol definition (if applicable)
+ Elf32_Sym *sym_def = NULL;
+ struct elf_module *sym_module = NULL;
+ Elf32_Addr sym_addr = 0x0;
+
+ if (sym > 0) {
+ // Find out details about the symbol
+
+ // The symbol reference
+ Elf32_Sym *sym_ref =
+ (Elf32_Sym*)(module->sym_table + sym * module->syment_size);
+
+ // The symbol definition
+ sym_def =
+ global_find_symbol(module->str_table + sym_ref->st_name,
+ &sym_module);
+
+ if (sym_def == NULL) {
+ // This should never happen
+ DBG_PRINT("Cannot perform relocation for symbol %s\n",
+ module->str_table + sym_ref->st_name);
+
+ /*
+ printf("Cannot perform relocation for symbol %s\n",
+ module->str_table + sym_ref->st_name);
+ */
+ return -1;
+ }
+
+ // Compute the absolute symbol virtual address
+ sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module);
+
+ if (sym_module != module) {
+ // Create a dependency
+ enforce_dependency(sym_module, module);
+ }
+ }
+
+ switch (type) {
+ case R_386_NONE:
+ // Do nothing
+ break;
+ case R_386_32:
+ *dest += sym_addr;
+ break;
+ case R_386_PC32:
+ *dest += sym_addr - (Elf32_Addr)dest;
+ break;
+ case R_386_COPY:
+ if (sym_addr > 0) {
+ memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
+ }
+ break;
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ // Maybe TODO: Keep track of the GOT entries allocations
+ *dest = sym_addr;
+ break;
+ case R_386_RELATIVE:
+ *dest += module->base_addr;
+ break;
+ default:
+ DBG_PRINT("Relocation type %d not supported\n", type);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int resolve_symbols(struct elf_module *module) {
+ Elf32_Dyn *dyn_entry = module->dyn_table;
+ unsigned int i;
+ int res;
+
+ Elf32_Word plt_rel_size = 0;
+ void *plt_rel = NULL;
+
+ void *rel = NULL;
+ Elf32_Word rel_size = 0;
+ Elf32_Word rel_entry = 0;
+
+ // The current relocation
+ Elf32_Rel *crt_rel;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch(dyn_entry->d_tag) {
+
+ // PLT relocation information
+ case DT_PLTRELSZ:
+ plt_rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTREL:
+ if (dyn_entry->d_un.d_val != DT_REL) {
+ DBG_PRINT("Unsupported PLT relocation\n");
+ return -1;
+ }
+ //break; // mouli: wasn't there before
+ case DT_JMPREL:
+ plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+
+ // Standard relocation information
+ case DT_REL:
+ rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_RELSZ:
+ rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELENT:
+ rel_entry = dyn_entry->d_un.d_val;
+ break;
+
+ // Module initialization and termination
+ case DT_INIT:
+ // TODO Implement initialization functions
+ break;
+ case DT_FINI:
+ // TODO Implement finalization functions
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ if (rel_size > 0) {
+ // Process standard relocations
+ for (i = 0; i < rel_size/rel_entry; i++) {
+ crt_rel = (Elf32_Rel*)(rel + i*rel_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+
+ }
+
+ if (plt_rel_size > 0) {
+ // TODO: Permit this lazily
+ // Process PLT relocations
+ for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) {
+ crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel));
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+
+
+static int extract_operations(struct elf_module *module) {
+ Elf32_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
+ Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
+ Elf32_Sym *main_sym = module_find_symbol("main", module);
+
+ if (init_sym) {
+ module->init_func = (module_init_t*)module_get_absolute(
+ init_sym->st_value, module);
+ if (*(module->init_func) == NULL) {
+ module->init_func = NULL;
+ }
+ }
+
+ if (exit_sym) {
+ module->exit_func = (module_exit_t*)module_get_absolute(
+ exit_sym->st_value, module);
+ if (*(module->exit_func) == NULL) {
+ module->exit_func = NULL;
+ }
+ }
+
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
+ return 0;
+}
+
+// Loads the module into the system
+int module_load(struct elf_module *module) {
+ int res;
+ Elf32_Ehdr elf_hdr;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module %s is already loaded.\n", module->name);
+ return -1;
+ }
+
+ // Get a mapping/copy of the ELF file in memory
+ res = image_load(module);
+
+ if (res < 0) {
+ return res;
+ }
+
+ // The module is a fully featured dynamic library
+ module->shallow = 0;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
+ //printf("check... 1\n");
+
+ //print_elf_ehdr(&elf_hdr);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header(&elf_hdr), error);
+ //printf("check... 2\n");
+
+ // Load the segments in the memory
+ CHECKED(res, load_segments(module, &elf_hdr), error);
+ //printf("bleah... 3\n");
+ // Obtain dynamic linking information
+ nr_needed = 0;
+ CHECKED(res, prepare_dynlinking(module), error);
+ //printf("check... 4\n");
+ //
+ //dump_elf_module(module);
+
+ /* Find modules we need to load as dependencies */
+ if (module->str_table) {
+ int i, n;
+
+ /*
+ * nr_needed can be modified by recursive calls to
+ * module_load() so keep a local copy on the stack.
+ */
+ n = nr_needed;
+ for (i = 0; i < n; i++) {
+ size_t len, j;
+ char *dep, *p;
+
+ dep = module->str_table + needed[i];
+
+ /* strip everything but the last component */
+ j = len = strlen(dep);
+ if (!len)
+ continue;
+
+ p = dep + len - 1;
+ while (j > 0 && *p && *p != '/') {
+ p--;
+ j--;
+ }
+
+ if (*p++ == '/') {
+ char argv[2] = { p, NULL };
+ spawn_load(p, 1, argv);
+ }
+ }
+ }
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+ //printf("check... 5\n");
+
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+ //printf("check... 6\n");
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // Perform the relocations
+ resolve_symbols(module);
+
+ //dprintf("module->symtable_size = %d\n", module->symtable_size);
+
+ //print_elf_symbols(module);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ /*
+ DBG_PRINT("MODULE %s LOADED SUCCESSFULLY (main@%p, init@%p, exit@%p)\n",
+ module->name,
+ (module->main_func == NULL) ? NULL : *(module->main_func),
+ (module->init_func == NULL) ? NULL : *(module->init_func),
+ (module->exit_func == NULL) ? NULL : *(module->exit_func));
+ */
+ return 0;
+
+error:
+ // Remove the module from the module list (if applicable)
+ list_del_init(&module->list);
+
+ if (module->module_addr != NULL) {
+ elf_free(module->module_addr);
+ module->module_addr = NULL;
+ }
+
+ image_unload(module);
+
+ // Clear the execution part of the module buffer
+ memset(&module->u, 0, sizeof module->u);
+
+ return res;
+}
+
diff --git a/com32/lib/sys/module/i386/elfutils.h b/com32/lib/sys/module/i386/elfutils.h
new file mode 100644
index 00000000..b18968f3
--- /dev/null
+++ b/com32/lib/sys/module/i386/elfutils.h
@@ -0,0 +1,64 @@
+#ifndef ELF_UTILS_H_
+#define ELF_UTILS_H_
+
+#include <elf.h>
+#include <stdlib.h>
+
+/**
+ * elf_get_header - Returns a pointer to the ELF header structure.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf32_Ehdr *elf_get_header(void *elf_image) {
+ return (Elf32_Ehdr*)elf_image;
+}
+
+/**
+ * elf_get_pht - Returns a pointer to the first entry in the PHT.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf32_Phdr *elf_get_pht(void *elf_image) {
+ Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff);
+}
+
+//
+/**
+ * elf_get_ph - Returns the element with the given index in the PTH
+ * @elf_image: pointer to the ELF file image in memory
+ * @index: the index of the PHT entry to look for
+ */
+static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index) {
+ Elf32_Phdr *elf_pht = elf_get_pht(elf_image);
+ Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize);
+}
+
+/**
+ * elf_hash - Returns the index in a SysV hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_hash(const unsigned char *name);
+
+/**
+ * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_gnu_hash(const unsigned char *name);
+
+/**
+ * elf_malloc - Allocates memory to be used by ELF module contents.
+ * @memptr: pointer to a variable to hold the address of the allocated block.
+ * @alignment: alignment constraints of the block
+ * @size: the required size of the block
+ */
+extern int elf_malloc(void **memptr, size_t alignment, size_t size);
+
+/**
+ * elf_free - Releases memory previously allocated by elf_malloc.
+ * @memptr: the address of the allocated block
+ */
+extern void elf_free(void *memptr);
+
+#endif /*ELF_UTILS_H_*/
diff --git a/com32/lib/sys/module/i386/shallow_module.c b/com32/lib/sys/module/i386/shallow_module.c
new file mode 100644
index 00000000..fbcf781b
--- /dev/null
+++ b/com32/lib/sys/module/i386/shallow_module.c
@@ -0,0 +1,161 @@
+/*
+ * shallow_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+
+#include <string.h>
+#include <sys/module.h>
+
+#include "common.h"
+#include "elfutils.h"
+
+
+static int check_header_shallow(Elf32_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_shoff == 0x00000000) {
+ DBG_PRINT("SHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ void *sht = NULL;
+ void *buffer = NULL;
+ Elf32_Shdr *crt_sht;
+ Elf32_Off buff_offset;
+
+ Elf32_Off min_offset = 0xFFFFFFFF;
+ Elf32_Off max_offset = 0x00000000;
+ Elf32_Word max_align = 0x1;
+
+ Elf32_Off sym_offset = 0xFFFFFFFF;
+ Elf32_Off str_offset = 0xFFFFFFFF;
+
+
+ char *sh_strtable;
+
+ // We buffer the data up to the SHT
+ buff_offset = module->u.l._cr_offset;
+
+ buffer = malloc(elf_hdr->e_shoff - buff_offset);
+ // Get to the SHT
+ image_read(buffer, elf_hdr->e_shoff - buff_offset, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Get the string table of the section names
+ crt_sht = (Elf32_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize);
+ sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset));
+
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ crt_sht = (Elf32_Shdr*)(sht + i*elf_hdr->e_shentsize);
+
+ if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the symbol table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ sym_offset = crt_sht->sh_offset;
+
+ module->syment_size = crt_sht->sh_entsize;
+ module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize;
+ }
+ if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the string table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ str_offset = crt_sht->sh_offset;
+
+ module->strtable_size = crt_sht->sh_size;
+ }
+ }
+
+ if (elf_malloc(&module->module_addr, max_align,
+ max_offset - min_offset) != 0) {
+ DBG_PRINT("Could not allocate sections\n");
+ goto out;
+ }
+
+ // Copy the data
+ image_seek(min_offset, module);
+ image_read(module->module_addr, max_offset - min_offset, module);
+
+ // Setup module information
+ module->module_size = max_offset - min_offset;
+ module->str_table = (char*)(module->module_addr + (str_offset - min_offset));
+ module->sym_table = module->module_addr + (sym_offset - min_offset);
+
+out:
+ // Release the SHT
+ if (sht != NULL)
+ free(sht);
+
+ // Release the buffer
+ if (buffer != NULL)
+ free(buffer);
+
+ return res;
+}
+
+
+int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr) {
+ int res;
+ Elf32_Ehdr elf_hdr;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module already loaded.\n");
+ return -1;
+ }
+
+ res = image_load(module);
+
+ if (res < 0)
+ return res;
+
+ module->shallow = 1;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header_shallow(&elf_hdr), error);
+
+ CHECKED(res, load_shallow_sections(module, &elf_hdr), error);
+ module->base_addr = base_addr;
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name);
+
+ return 0;
+
+error:
+ image_unload(module);
+
+ return res;
+}
diff --git a/com32/lib/sys/module/x86_64/common.c b/com32/lib/sys/module/x86_64/common.c
new file mode 100644
index 00000000..ba4dbedc
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/common.c
@@ -0,0 +1,567 @@
+/*
+ * common.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <stdio.h>
+#include <elf.h>
+#include <string.h>
+#include <fs.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+
+#include "elfutils.h"
+#include "common.h"
+
+/**
+ * The one and only list of loaded modules
+ */
+LIST_HEAD(modules_head);
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+void print_elf_ehdr(Elf64_Ehdr *ehdr) {
+ int i;
+
+ fprintf(stderr, "Identification:\t");
+ for (i=0; i < EI_NIDENT; i++) {
+ printf("%d ", ehdr->e_ident[i]);
+ }
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
+ fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
+ fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
+ fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
+ fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
+ fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
+ //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
+ //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf64_Ehdr));
+ fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
+ ehdr->e_shnum);
+}
+
+void print_elf_symbols(struct elf_module *module) {
+ unsigned int i;
+ Elf64_Sym *crt_sym;
+
+ for (i = 1; i < module->symtable_size; i++)
+ {
+ crt_sym = (Elf64_Sym*)(module->sym_table + i*module->syment_size);
+
+ fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
+
+ }
+}
+#endif //ELF_DEBUG
+
+static FILE *findpath(char *name)
+{
+ char path[FILENAME_MAX];
+ FILE *f;
+ char *p, *n;
+ int i;
+
+ p = PATH;
+again:
+ memset(path, '\0', sizeof(path));
+ i = 0;
+ while (*p && *p != ':' && i < FILENAME_MAX) {
+ path[i++] = *p++;
+ }
+
+ if (*p == ':')
+ p++;
+
+ if (!strcmp(path, ".")) {
+ if (!core_getcwd(path, sizeof(path))) {
+ DBG_PRINT("Could not get cwd\n");
+ return NULL;
+ }
+ i = strlen(path);
+ }
+
+ n = name;
+ while (*n && i < FILENAME_MAX)
+ path[i++] = *n++;
+ path[i] = '\0';
+
+ f = fopen(path, "rb");
+ if (f)
+ return f;
+
+ if (p >= PATH && p < PATH + strlen(PATH))
+ goto again;
+
+ return NULL;
+}
+
+/*
+ * Image files manipulation routines
+ */
+
+int image_load(struct elf_module *module)
+{
+ module->u.l._file = findpath(module->name);
+
+ if (module->u.l._file == NULL) {
+ DBG_PRINT("Could not open object file '%s'\n", module->name);
+ goto error;
+ }
+
+ module->u.l._cr_offset = 0;
+
+ return 0;
+
+error:
+ if (module->u.l._file != NULL) {
+ fclose(module->u.l._file);
+ module->u.l._file = NULL;
+ }
+
+ return -1;
+}
+
+
+int image_unload(struct elf_module *module) {
+ if (module->u.l._file != NULL) {
+ fclose(module->u.l._file);
+ module->u.l._file = NULL;
+
+ }
+ module->u.l._cr_offset = 0;
+
+ return 0;
+}
+
+int image_read(void *buff, size_t size, struct elf_module *module) {
+ size_t result = fread(buff, size, 1, module->u.l._file);
+
+ if (result < 1)
+ return -1;
+
+ module->u.l._cr_offset += size;
+ return 0;
+}
+
+int image_skip(size_t size, struct elf_module *module) {
+ void *skip_buff = NULL;
+ size_t result;
+
+ if (size == 0)
+ return 0;
+
+ skip_buff = malloc(size);
+ result = fread(skip_buff, size, 1, module->u.l._file);
+ free(skip_buff);
+
+ if (result < 1)
+ return -1;
+
+ module->u.l._cr_offset += size;
+ return 0;
+}
+
+int image_seek(Elf64_Off offset, struct elf_module *module) {
+ if (offset < module->u.l._cr_offset) // Cannot seek backwards
+ return -1;
+
+ return image_skip(offset - module->u.l._cr_offset, module);
+}
+
+
+// Initialization of the module subsystem
+int modules_init(void) {
+ return 0;
+}
+
+// Termination of the module subsystem
+void modules_term(void) {
+
+}
+
+// Allocates the structure for a new module
+struct elf_module *module_alloc(const char *name) {
+ struct elf_module *result = malloc(sizeof(struct elf_module));
+
+ memset(result, 0, sizeof(struct elf_module));
+
+ INIT_LIST_HEAD(&result->list);
+ INIT_LIST_HEAD(&result->required);
+ INIT_LIST_HEAD(&result->dependants);
+
+ strncpy(result->name, name, MODULE_NAME_SIZE);
+
+ return result;
+}
+
+struct module_dep *module_dep_alloc(struct elf_module *module) {
+ struct module_dep *result = malloc(sizeof(struct module_dep));
+
+ INIT_LIST_HEAD (&result->list);
+
+ result->module = module;
+
+ return result;
+}
+
+struct elf_module *module_find(const char *name) {
+ struct elf_module *cr_module;
+
+ for_each_module(cr_module) {
+ if (strcmp(cr_module->name, name) == 0)
+ return cr_module;
+ }
+
+ return NULL;
+}
+
+
+// Performs verifications on ELF header to assure that the open file is a
+// valid SYSLINUX ELF module.
+int check_header_common(Elf64_Ehdr *elf_hdr) {
+ // Check the header magic
+ if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
+
+ DBG_PRINT("The file is not an ELF object\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
+ DBG_PRINT("Invalid ELF class code\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
+ DBG_PRINT("Invalid ELF data encoding\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
+ elf_hdr->e_version != MODULE_ELF_VERSION) {
+ DBG_PRINT("Invalid ELF file version\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
+ DBG_PRINT("Invalid ELF architecture\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
+ struct module_dep *crt_dep;
+ struct module_dep *new_dep;
+
+ list_for_each_entry(crt_dep, &req->dependants, list) {
+ if (crt_dep->module == dep) {
+ // The dependency is already enforced
+ return 0;
+ }
+ }
+
+ new_dep = module_dep_alloc(req);
+ list_add(&new_dep->list, &dep->required);
+
+ new_dep = module_dep_alloc(dep);
+ list_add(&new_dep->list, &req->dependants);
+
+ return 0;
+}
+
+int clear_dependency(struct elf_module *req, struct elf_module *dep) {
+ struct module_dep *crt_dep = NULL;
+ int found = 0;
+
+ list_for_each_entry(crt_dep, &req->dependants, list) {
+ if (crt_dep->module == dep) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ list_del(&crt_dep->list);
+ free(crt_dep);
+ }
+
+ found = 0;
+
+ list_for_each_entry(crt_dep, &dep->required, list) {
+ if (crt_dep->module == req) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ list_del(&crt_dep->list);
+ free(crt_dep);
+ }
+
+ return 0;
+}
+
+int check_symbols(struct elf_module *module)
+{
+ unsigned int i;
+ Elf64_Sym *crt_sym = NULL, *ref_sym = NULL;
+ char *crt_name;
+ struct elf_module *crt_module;
+
+ int strong_count;
+ int weak_count;
+
+ for(i = 1; i < module->symtable_size; i++)
+ {
+ crt_sym = (Elf64_Sym*)(module->sym_table + i * module->syment_size);
+ crt_name = module->str_table + crt_sym->st_name;
+
+ strong_count = 0;
+ weak_count = 0;
+
+ for_each_module(crt_module)
+ {
+ ref_sym = module_find_symbol(crt_name, crt_module);
+
+ // If we found a definition for our symbol...
+ if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
+ {
+ switch (ELF64_ST_BIND(ref_sym->st_info))
+ {
+ case STB_GLOBAL:
+ strong_count++;
+ break;
+ case STB_WEAK:
+ weak_count++;
+ break;
+ }
+ }
+ }
+
+ if (crt_sym->st_shndx == SHN_UNDEF)
+ {
+ // We have an undefined symbol
+ if (strong_count == 0 && weak_count == 0)
+ {
+ DBG_PRINT("Symbol %s is undefined\n", crt_name);
+ //printf("Undef symbol FAIL: %s\n",crt_name);
+ return -1;
+ }
+ }
+ else
+ {
+ if (strong_count > 0 && ELF64_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
+ {
+ // It's not an error - at relocation, the most recent symbol
+ // will be considered
+ DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name);
+ }
+ }
+ //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
+ }
+
+ return 0;
+}
+
+int module_unloadable(struct elf_module *module) {
+ if (!list_empty(&module->dependants))
+ return 0;
+
+ return 1;
+}
+
+
+// Unloads the module from the system and releases all the associated memory
+int module_unload(struct elf_module *module) {
+ struct module_dep *crt_dep, *tmp;
+ // Make sure nobody needs us
+ if (!module_unloadable(module)) {
+ DBG_PRINT("Module is required by other modules.\n");
+ return -1;
+ }
+
+ // Remove any dependency information
+ list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
+ clear_dependency(crt_dep->module, module);
+ }
+
+ // Remove the module from the module list
+ list_del_init(&module->list);
+
+ // Release the loaded segments or sections
+ if (module->module_addr != NULL) {
+ elf_free(module->module_addr);
+
+ DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
+ module->name);
+ }
+ // Release the module structure
+ free(module);
+
+ return 0;
+}
+
+
+static Elf64_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
+ unsigned long h = elf_hash((const unsigned char*)name);
+ Elf64_Word *cr_word = module->hash_table;
+
+ Elf64_Word nbucket = *cr_word++;
+ cr_word++; // Skip nchain
+
+ Elf64_Word *bkt = cr_word;
+ Elf64_Word *chn = cr_word + nbucket;
+
+ Elf64_Word crt_index = bkt[h % module->hash_table[0]];
+ Elf64_Sym *crt_sym;
+
+
+ while (crt_index != STN_UNDEF) {
+ crt_sym = (Elf64_Sym*)(module->sym_table + crt_index*module->syment_size);
+
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
+ return crt_sym;
+
+ crt_index = chn[crt_index];
+ }
+
+ return NULL;
+}
+
+static Elf64_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
+ unsigned long h = elf_gnu_hash((const unsigned char*)name);
+
+ // Setup code (TODO: Optimize this by computing only once)
+ Elf64_Word *cr_word = module->ghash_table;
+ Elf64_Word nbucket = *cr_word++;
+ Elf64_Word symbias = *cr_word++;
+ Elf64_Word bitmask_nwords = *cr_word++;
+
+ if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
+ DBG_PRINT("Invalid GNU Hash structure\n");
+ return NULL;
+ }
+
+ Elf64_Word gnu_shift = *cr_word++;
+
+ Elf64_Addr *gnu_bitmask = cr_word;
+ cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
+
+ Elf64_Word *gnu_buckets = cr_word;
+ cr_word += nbucket;
+
+ Elf64_Word *gnu_chain_zero = cr_word - symbias;
+
+ // Computations
+ /* bitask words are 64bit for ELFCLASS64 modules */
+ Elf64_Xword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
+ (bitmask_nwords - 1)];
+
+ unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
+ unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
+
+ if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
+ unsigned long rem;
+ Elf64_Word bucket;
+
+ rem = h % nbucket;
+
+ bucket = gnu_buckets[rem];
+
+ if (bucket != 0) {
+ const Elf64_Word* hasharr = &gnu_chain_zero[bucket];
+
+ do {
+ if (((*hasharr ^ h ) >> 1) == 0) {
+ Elf64_Sym *crt_sym = (Elf64_Sym*)(module->sym_table +
+ (hasharr - gnu_chain_zero) * module->syment_size);
+
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
+ return crt_sym;
+ }
+ }
+ } while ((*hasharr++ & 1u) == 0);
+ }
+ }
+
+ return NULL;
+}
+
+static Elf64_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
+{
+
+ unsigned int i;
+ Elf64_Sym *crt_sym;
+
+ for (i=1; i < module->symtable_size; i++)
+ {
+ crt_sym = (Elf64_Sym*)(module->sym_table + i*module->syment_size);
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
+ {
+ return crt_sym;
+ }
+ }
+
+ return NULL;
+}
+
+Elf64_Sym *module_find_symbol(const char *name, struct elf_module *module) {
+ Elf64_Sym *result = NULL;
+
+ if (module->ghash_table != NULL)
+ result = module_find_symbol_gnu(name, module);
+
+ if (result == NULL)
+ {
+ if (module->hash_table != NULL)
+ {
+ result = module_find_symbol_sysv(name, module);
+ }
+ else
+ {
+ result = module_find_symbol_iterate(name, module);
+ }
+ }
+
+ return result;
+}
+
+Elf64_Sym *global_find_symbol(const char *name, struct elf_module **module) {
+ struct elf_module *crt_module;
+ Elf64_Sym *crt_sym = NULL;
+ Elf64_Sym *result = NULL;
+
+ for_each_module(crt_module) {
+ crt_sym = module_find_symbol(name, crt_module);
+
+ if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
+ switch (ELF64_ST_BIND(crt_sym->st_info)) {
+ case STB_GLOBAL:
+ if (module != NULL) {
+ *module = crt_module;
+ }
+ return crt_sym;
+ case STB_WEAK:
+ // Consider only the first weak symbol
+ if (result == NULL) {
+ if (module != NULL) {
+ *module = crt_module;
+ }
+ result = crt_sym;
+ }
+ break;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/com32/lib/sys/module/x86_64/common.h b/com32/lib/sys/module/x86_64/common.h
new file mode 100644
index 00000000..e7946f91
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/common.h
@@ -0,0 +1,64 @@
+/*
+ * common.h - Common internal operations performed by the module subsystem
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include <stdio.h>
+
+#include <sys/module.h>
+#include <linux/list.h>
+
+#include "elfutils.h"
+
+// Performs an operation and jumps to a given label if an error occurs
+#define CHECKED(res, expr, error) \
+ do { \
+ (res) = (expr); \
+ if ((res) < 0) \
+ goto error; \
+ } while (0)
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+//#define ELF_DEBUG
+
+#ifdef ELF_DEBUG
+#define DBG_PRINT(fmt, args...) fprintf(stderr, "[ELF] " fmt, ##args)
+#else
+#define DBG_PRINT(fmt, args...) // Expand to nothing
+#endif
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+extern void print_elf_ehdr(Elf64_Ehdr *ehdr);
+extern void print_elf_symbols(struct elf_module *module);
+#endif //ELF_DEBUG
+
+
+/*
+ * Image files manipulation routines
+ */
+
+extern int image_load(struct elf_module *module);
+extern int image_unload(struct elf_module *module);
+extern int image_read(void *buff, size_t size, struct elf_module *module);
+extern int image_skip(size_t size, struct elf_module *module);
+extern int image_seek(Elf64_Off offset, struct elf_module *module);
+
+extern struct module_dep *module_dep_alloc(struct elf_module *module);
+
+extern int check_header_common(Elf64_Ehdr *elf_hdr);
+
+extern int enforce_dependency(struct elf_module *req, struct elf_module *dep);
+extern int clear_dependency(struct elf_module *req, struct elf_module *dep);
+
+extern int check_symbols(struct elf_module *module);
+
+
+#endif /* COMMON_H_ */
diff --git a/com32/lib/sys/module/x86_64/elf_module.c b/com32/lib/sys/module/x86_64/elf_module.c
new file mode 100644
index 00000000..2ff2e20b
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/elf_module.c
@@ -0,0 +1,603 @@
+/*
+ * elf_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+#include <dprintf.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+
+#include "elfutils.h"
+#include "common.h"
+
+#define MAX_NR_DEPS 64
+
+static int check_header(Elf64_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_type != MODULE_ELF_TYPE) {
+ DBG_PRINT("The ELF file must be a shared object\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_phoff == 0x00000000) {
+ DBG_PRINT("PHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * The implementation assumes that the loadable segments are present
+ * in the PHT sorted by their offsets, so that only forward seeks would
+ * be necessary.
+ */
+static int load_segments(struct elf_module *module, Elf64_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ void *pht = NULL;
+ Elf64_Phdr *cr_pht;
+
+ Elf64_Addr min_addr = 0x0000000000000000; // Min. ELF vaddr
+ Elf64_Addr max_addr = 0x0000000000000000; // Max. ELF vaddr
+ Elf64_Word max_align = sizeof(void*); // Min. align of posix_memalign()
+ Elf64_Addr min_alloc, max_alloc; // Min. and max. aligned allocables
+
+ Elf64_Addr dyn_addr = 0x0000000000000000;
+
+ // Get to the PHT
+ image_seek(elf_hdr->e_phoff, module);
+
+ // Load the PHT
+ pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
+ image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
+
+ // Compute the memory needings of the module
+ for (i=0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf64_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ switch (cr_pht->p_type) {
+ case PT_LOAD:
+ if (i == 0) {
+ min_addr = cr_pht->p_vaddr;
+ } else {
+ min_addr = MIN(min_addr, cr_pht->p_vaddr);
+ }
+
+ max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
+ max_align = MAX(max_align, cr_pht->p_align);
+ break;
+ case PT_DYNAMIC:
+ dyn_addr = cr_pht->p_vaddr;
+ break;
+ default:
+ // Unsupported - ignore
+ break;
+ }
+ }
+
+ if (max_addr - min_addr == 0) {
+ // No loadable segments
+ DBG_PRINT("No loadable segments found\n");
+ goto out;
+ }
+
+ if (dyn_addr == 0) {
+ DBG_PRINT("No dynamic information segment found\n");
+ goto out;
+ }
+
+ // The minimum address that should be allocated
+ min_alloc = min_addr - (min_addr % max_align);
+
+ // The maximum address that should be allocated
+ max_alloc = max_addr - (max_addr % max_align);
+ if (max_addr % max_align > 0)
+ max_alloc += max_align;
+
+
+ if (elf_malloc(&module->module_addr,
+ max_align,
+ max_alloc-min_alloc) != 0) {
+
+ DBG_PRINT("Could not allocate segments\n");
+ goto out;
+ }
+
+ module->base_addr = (Elf64_Addr)(module->module_addr) - min_alloc;
+ module->module_size = max_alloc - min_alloc;
+
+ // Zero-initialize the memory
+ memset(module->module_addr, 0, module->module_size);
+
+ for (i = 0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf64_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ if (cr_pht->p_type == PT_LOAD) {
+ // Copy the segment at its destination
+ if (cr_pht->p_offset < module->u.l._cr_offset) {
+ // The segment contains data before the current offset
+ // It can be discarded without worry - it would contain only
+ // headers
+ Elf64_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
+
+ if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+ cr_pht->p_filesz - aux_off, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ } else {
+ if (image_seek(cr_pht->p_offset, module) < 0) {
+ res = -1;
+ goto out;
+ }
+
+ if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
+ cr_pht->p_filesz, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ }
+
+ /*
+ DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
+ cr_pht->p_filesz,
+ cr_pht->p_vaddr,
+ (Elf64_Addr)module_get_absolute(cr_pht->p_vaddr, module));
+ */
+ }
+ }
+
+ // Setup dynamic segment location
+ module->dyn_table = module_get_absolute(dyn_addr, module);
+
+ /*
+ DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
+ max_align);
+ DBG_PRINT("Module size: 0x%08x\n", module->module_size);
+ */
+
+out:
+ // Free up allocated memory
+ if (pht != NULL)
+ free(pht);
+
+ return res;
+}
+
+static int nr_needed;
+static Elf64_Word needed[MAX_NR_DEPS];;
+
+static int prepare_dynlinking(struct elf_module *module) {
+ Elf64_Dyn *dyn_entry = module->dyn_table;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch (dyn_entry->d_tag) {
+ case DT_NEEDED:
+ /*
+ * It's unlikely there'll be more than
+ * MAX_NR_DEPS DT_NEEDED entries but if there
+ * are then inform the user that we ran out of
+ * space.
+ */
+ if (nr_needed < MAX_NR_DEPS)
+ needed[nr_needed++] = dyn_entry->d_un.d_ptr;
+ else {
+ printf("Too many dependencies!\n");
+ return -1;
+ }
+ break;
+ case DT_HASH:
+ module->hash_table =
+ (Elf64_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_GNU_HASH:
+ module->ghash_table =
+ (Elf64_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRTAB:
+ module->str_table =
+ (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_SYMTAB:
+ module->sym_table =
+ module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRSZ:
+ module->strtable_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_SYMENT:
+ module->syment_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTGOT: // The first entry in the GOT
+ module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ // Now compute the number of symbols in the symbol table
+ if (module->ghash_table != NULL) {
+ module->symtable_size = module->ghash_table[1];
+ } else {
+ module->symtable_size = module->hash_table[1];
+ }
+
+ return 0;
+}
+
+
+static int perform_relocation(struct elf_module *module, Elf64_Rel *rel) {
+ Elf64_Xword *dest = module_get_absolute(rel->r_offset, module);
+
+ // The symbol reference index
+ Elf64_Word sym = ELF64_R_SYM(rel->r_info);
+ unsigned char type = ELF64_R_TYPE(rel->r_info);
+
+ // The symbol definition (if applicable)
+ Elf64_Sym *sym_def = NULL;
+ struct elf_module *sym_module = NULL;
+ Elf64_Addr sym_addr = 0x0;
+
+ if (sym > 0) {
+ // Find out details about the symbol
+
+ // The symbol reference
+ Elf64_Sym *sym_ref =
+ (Elf64_Sym*)(module->sym_table + sym * module->syment_size);
+
+ // The symbol definition
+ sym_def =
+ global_find_symbol(module->str_table + sym_ref->st_name,
+ &sym_module);
+
+ if (sym_def == NULL) {
+ // This should never happen
+ DBG_PRINT("Cannot perform relocation for symbol %s\n",
+ module->str_table + sym_ref->st_name);
+
+ return -1;
+ }
+
+ // Compute the absolute symbol virtual address
+ sym_addr = (Elf64_Addr)module_get_absolute(sym_def->st_value, sym_module);
+
+ if (sym_module != module) {
+ // Create a dependency
+ enforce_dependency(sym_module, module);
+ }
+ }
+
+ switch (type) {
+ case R_X86_64_NONE:
+ // Do nothing
+ break;
+ case R_X86_64_64:
+ *dest += sym_addr;
+ break;
+ case R_X86_64_PC32:
+ *dest += sym_addr - (Elf32_Addr)dest;
+ break;
+ case R_X86_64_COPY:
+ if (sym_addr > 0) {
+ memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
+ }
+ break;
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_JUMP_SLOT:
+ //Maybe TODO: Keep track of the GOT entries allocations
+ *dest = sym_addr;
+ break;
+ case R_X86_64_RELATIVE:
+ *dest += module->base_addr;
+ break;
+ default:
+ DBG_PRINT("Relocation type %d not supported\n", type);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int resolve_symbols(struct elf_module *module) {
+ Elf64_Dyn *dyn_entry = module->dyn_table;
+ unsigned int i;
+ int res;
+
+ Elf64_Word plt_rel_size = 0;
+ void *plt_rel = NULL;
+
+ void *rel = NULL;
+ Elf64_Word rel_size = 0;
+ Elf64_Word rel_entry = 0;
+ Elf64_Xword rela_size = 0;
+ Elf64_Xword rela_entry = 0;
+ Elf64_Xword sym_ent = 0;
+
+ // The current relocation
+ Elf64_Rel *crt_rel;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch(dyn_entry->d_tag) {
+
+ // PLT relocation information
+ case DT_PLTRELSZ:
+ plt_rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTREL:
+ if (dyn_entry->d_un.d_val != DT_REL && dyn_entry->d_un.d_val != DT_RELA) {
+ DBG_PRINT("Unsupported PLT relocation\n");
+ return -1;
+ }
+ //break;
+ case DT_JMPREL:
+ plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+
+ // Standard relocation information
+ case DT_REL:
+ rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_RELA:
+ rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_RELSZ:
+ rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELASZ:
+ rela_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELENT:
+ rel_entry = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELAENT:
+ rela_entry = dyn_entry->d_un.d_val;
+ break;
+ /* FIXME: We may need to rely upon SYMENT if DT_RELAENT is missing in the object file */
+ case DT_SYMENT:
+ sym_ent = dyn_entry->d_un.d_val;
+ break;
+
+ // Module initialization and termination
+ case DT_INIT:
+ // TODO Implement initialization functions
+ break;
+ case DT_FINI:
+ // TODO Implement finalization functions
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ if (rel_size > 0) {
+ // Process standard relocations
+ for (i = 0; i < rel_size/rel_entry; i++) {
+ crt_rel = (Elf64_Rel*)(rel + i*rel_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+
+ }
+
+ if (rela_size > 0) {
+ // Process standard relocations
+ for (i = 0; i < rela_size/rela_entry; i++) {
+ crt_rel = (Elf64_Rel*)(rel + i*rela_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+ }
+ if (plt_rel_size > 0) {
+ // TODO: Permit this lazily
+ // Process PLT relocations
+ /* some modules do not have DT_SYMENT, set it sym_ent in such cases */
+ if (!rela_entry) rela_entry = sym_ent;
+ //for (i = 0; i < plt_rel_size/sizeof(Elf64_Rel); i++) {
+ for (i = 0; i < plt_rel_size/rela_entry; i++) {
+ //crt_rel = (Elf64_Rel*)(plt_rel + i*sizeof(Elf64_Rel));
+ crt_rel = (Elf64_Rel*)(plt_rel + i*rela_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0) {
+ return res;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+static int extract_operations(struct elf_module *module) {
+ Elf64_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
+ Elf64_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
+ Elf64_Sym *main_sym = module_find_symbol("main", module);
+
+ if (init_sym) {
+ module->init_func = (module_init_t*)module_get_absolute(
+ init_sym->st_value, module);
+ if (*(module->init_func) == NULL) {
+ module->init_func = NULL;
+ }
+ }
+
+ if (exit_sym) {
+ module->exit_func = (module_exit_t*)module_get_absolute(
+ exit_sym->st_value, module);
+ if (*(module->exit_func) == NULL) {
+ module->exit_func = NULL;
+ }
+ }
+
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
+ return 0;
+}
+
+void print_elf_ehdr(Elf64_Ehdr *ehdr) {
+ int i;
+
+ printf("Identification:\t");
+ for (i=0; i < EI_NIDENT; i++) {
+ printf("%d ", ehdr->e_ident[i]);
+ }
+ printf("\n");
+ printf("Type:\t\t%u\n", ehdr->e_type);
+ printf("Machine:\t%u\n", ehdr->e_machine);
+ printf("Version:\t%u\n", ehdr->e_version);
+ printf("Entry:\t\t0x%08x\n", ehdr->e_entry);
+ printf("PHT Offset:\t0x%08x\n", ehdr->e_phoff);
+ printf("SHT Offset:\t0x%08x\n", ehdr->e_shoff);
+ //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
+ //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf64_Ehdr));
+ printf("phnum: %d shnum: %d\n", ehdr->e_phnum,
+ ehdr->e_shnum);
+}
+// Loads the module into the system
+int module_load(struct elf_module *module) {
+ int res;
+ Elf64_Ehdr elf_hdr;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module %s is already loaded.\n", module->name);
+ return -1;
+ }
+
+ // Get a mapping/copy of the ELF file in memory
+ res = image_load(module);
+
+ if (res < 0) {
+ return res;
+ }
+
+ // The module is a fully featured dynamic library
+ module->shallow = 0;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf64_Ehdr), module), error);
+ //printf("check... 1\n");
+
+ //print_elf_ehdr(&elf_hdr);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header(&elf_hdr), error);
+ //printf("check... 2\n");
+
+ // Load the segments in the memory
+ CHECKED(res, load_segments(module, &elf_hdr), error);
+ //!!!!! Passed load_segments....
+ //printf("bleah... 3\n");
+ // Obtain dynamic linking information
+ nr_needed = 0;
+ CHECKED(res, prepare_dynlinking(module), error);
+ //printf("check... 4\n");
+ //
+ //dump_elf_module(module);
+
+ /* Find modules we need to load as dependencies */
+ if (module->str_table) {
+ int i, n;
+
+ /*
+ * nr_needed can be modified by recursive calls to
+ * module_load() so keep a local copy on the stack.
+ */
+ n = nr_needed;
+ for (i = 0; i < n; i++) {
+ size_t len, j;
+ char *dep, *p;
+
+ dep = module->str_table + needed[i];
+
+ /* strip everything but the last component */
+ j = len = strlen(dep);
+ if (!len)
+ continue;
+
+ p = dep + len - 1;
+ while (j > 0 && *p && *p != '/') {
+ p--;
+ j--;
+ }
+
+ if (*p++ == '/') {
+ char argv[2] = { p, NULL };
+ spawn_load(p, 1, argv);
+ }
+ }
+ }
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+ //printf("check... 5\n");
+
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+ //printf("check... 6\n");
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // Perform the relocations
+ resolve_symbols(module);
+
+ //dprintf("module->symtable_size = %d\n", module->symtable_size);
+
+ //print_elf_symbols(module);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ /*
+ DBG_PRINT("MODULE %s LOADED SUCCESSFULLY (main@%p, init@%p, exit@%p)\n",
+ module->name,
+ (module->main_func == NULL) ? NULL : *(module->main_func),
+ (module->init_func == NULL) ? NULL : *(module->init_func),
+ (module->exit_func == NULL) ? NULL : *(module->exit_func));
+ */
+ return 0;
+
+error:
+ // Remove the module from the module list (if applicable)
+ list_del_init(&module->list);
+
+ if (module->module_addr != NULL) {
+ elf_free(module->module_addr);
+ module->module_addr = NULL;
+ }
+
+ image_unload(module);
+
+ // Clear the execution part of the module buffer
+ memset(&module->u, 0, sizeof module->u);
+
+ return res;
+}
+
diff --git a/com32/lib/sys/module/x86_64/elfutils.h b/com32/lib/sys/module/x86_64/elfutils.h
new file mode 100644
index 00000000..dbfc7608
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/elfutils.h
@@ -0,0 +1,64 @@
+#ifndef ELF_UTILS_H_
+#define ELF_UTILS_H_
+
+#include <elf.h>
+#include <stdlib.h>
+
+/**
+ * elf_get_header - Returns a pointer to the ELF header structure.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf64_Ehdr *elf_get_header(void *elf_image) {
+ return (Elf64_Ehdr*)elf_image;
+}
+
+/**
+ * elf_get_pht - Returns a pointer to the first entry in the PHT.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf64_Phdr *elf_get_pht(void *elf_image) {
+ Elf64_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf64_Phdr*)((Elf64_Off)elf_hdr + elf_hdr->e_phoff);
+}
+
+//
+/**
+ * elf_get_ph - Returns the element with the given index in the PTH
+ * @elf_image: pointer to the ELF file image in memory
+ * @index: the index of the PHT entry to look for
+ */
+static inline Elf64_Phdr *elf_get_ph(void *elf_image, int index) {
+ Elf64_Phdr *elf_pht = elf_get_pht(elf_image);
+ Elf64_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf64_Phdr*)((Elf64_Off)elf_pht + index * elf_hdr->e_phentsize);
+}
+
+/**
+ * elf_hash - Returns the index in a SysV hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_hash(const unsigned char *name);
+
+/**
+ * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_gnu_hash(const unsigned char *name);
+
+/**
+ * elf_malloc - Allocates memory to be used by ELF module contents.
+ * @memptr: pointer to a variable to hold the address of the allocated block.
+ * @alignment: alignment constraints of the block
+ * @size: the required size of the block
+ */
+extern int elf_malloc(void **memptr, size_t alignment, size_t size);
+
+/**
+ * elf_free - Releases memory previously allocated by elf_malloc.
+ * @memptr: the address of the allocated block
+ */
+extern void elf_free(void *memptr);
+
+#endif /*ELF_UTILS_H_*/
diff --git a/com32/lib/sys/module/x86_64/shallow_module.c b/com32/lib/sys/module/x86_64/shallow_module.c
new file mode 100644
index 00000000..b7248150
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/shallow_module.c
@@ -0,0 +1,161 @@
+/*
+ * shallow_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+
+#include <string.h>
+#include <sys/module.h>
+
+#include "common.h"
+#include "elfutils.h"
+
+
+static int check_header_shallow(Elf64_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_shoff == 0x00000000) {
+ DBG_PRINT("SHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int load_shallow_sections(struct elf_module *module, Elf64_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ void *sht = NULL;
+ void *buffer = NULL;
+ Elf64_Shdr *crt_sht;
+ Elf64_Off buff_offset;
+
+ Elf64_Off min_offset = 0xFFFFFFFFFFFFFFFF;
+ Elf64_Off max_offset = 0x0000000000000000;
+ Elf64_Word max_align = 0x1;
+
+ Elf64_Off sym_offset = 0xFFFFFFFFFFFFFFFF;
+ Elf64_Off str_offset = 0xFFFFFFFFFFFFFFFF;
+
+
+ char *sh_strtable;
+
+ // We buffer the data up to the SHT
+ buff_offset = module->u.l._cr_offset;
+
+ buffer = malloc(elf_hdr->e_shoff - buff_offset);
+ // Get to the SHT
+ image_read(buffer, elf_hdr->e_shoff - buff_offset, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Get the string table of the section names
+ crt_sht = (Elf64_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize);
+ sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset));
+
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ crt_sht = (Elf64_Shdr*)(sht + i*elf_hdr->e_shentsize);
+
+ if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the symbol table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ sym_offset = crt_sht->sh_offset;
+
+ module->syment_size = crt_sht->sh_entsize;
+ module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize;
+ }
+ if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the string table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ str_offset = crt_sht->sh_offset;
+
+ module->strtable_size = crt_sht->sh_size;
+ }
+ }
+
+ if (elf_malloc(&module->module_addr, max_align,
+ max_offset - min_offset) != 0) {
+ DBG_PRINT("Could not allocate sections\n");
+ goto out;
+ }
+
+ // Copy the data
+ image_seek(min_offset, module);
+ image_read(module->module_addr, max_offset - min_offset, module);
+
+ // Setup module information
+ module->module_size = max_offset - min_offset;
+ module->str_table = (char*)(module->module_addr + (str_offset - min_offset));
+ module->sym_table = module->module_addr + (sym_offset - min_offset);
+
+out:
+ // Release the SHT
+ if (sht != NULL)
+ free(sht);
+
+ // Release the buffer
+ if (buffer != NULL)
+ free(buffer);
+
+ return res;
+}
+
+
+int module_load_shallow(struct elf_module *module, Elf64_Addr base_addr) {
+ int res;
+ Elf64_Ehdr elf_hdr;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module already loaded.\n");
+ return -1;
+ }
+
+ res = image_load(module);
+
+ if (res < 0)
+ return res;
+
+ module->shallow = 1;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf64_Ehdr), module), error);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header_shallow(&elf_hdr), error);
+
+ CHECKED(res, load_shallow_sections(module, &elf_hdr), error);
+ module->base_addr = base_addr;
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name);
+
+ return 0;
+
+error:
+ image_unload(module);
+
+ return res;
+}
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index c2e0767e..d1c21b95 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -24,6 +24,21 @@
#define LDLINUX "ldlinux.c32"
+#if __SIZEOF_POINTER__ == 4
+typedef Elf32_Dyn Elf_Dyn;
+typedef Elf32_Word Elf_Word;
+typedef Elf32_Addr Elf_Addr;
+#define ELF_SYMENT_SIZE sizeof(Elf32_Sym)
+#define ELF_MOD_SYS "32 bit"
+#elif __SIZEOF_POINTER__ == 8
+typedef Elf64_Dyn Elf_Dyn;
+typedef Elf64_Word Elf_Word;
+typedef Elf64_Addr Elf_Addr;
+#define ELF_SYMENT_SIZE sizeof(Elf64_Sym)
+#define ELF_MOD_SYS "64 bit"
+#else
+#error "unsupported architecture"
+#endif
typedef void (*constructor_t) (void);
constructor_t __ctors_start[], __ctors_end[];
@@ -31,8 +46,8 @@ extern char __dynstr_start[];
extern char __dynstr_end[], __dynsym_end[];
extern char __dynsym_start[];
extern char __got_start[];
-extern Elf32_Dyn __dynamic_start[];
-extern Elf32_Word __gnu_hash_start[];
+extern Elf_Dyn __dynamic_start[];
+extern Elf_Word __gnu_hash_start[];
extern char __module_start[];
struct elf_module core_module = {
@@ -47,7 +62,7 @@ struct elf_module core_module = {
.sym_table = __dynsym_start,
.got = __got_start,
.dyn_table = __dynamic_start,
- .syment_size = sizeof(Elf32_Sym),
+ .syment_size = ELF_SYMENT_SIZE,
};
/*
@@ -91,14 +106,14 @@ void load_env32(com32sys_t * regs)
NULL
};
- dprintf("Starting 32 bit elf module subsystem...\n");
+ dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
call_constr();
size = (size_t)__dynstr_end - (size_t)__dynstr_start;
core_module.strtable_size = size;
size = (size_t)__dynsym_end - (size_t)__dynsym_start;
core_module.symtable_size = size;
- core_module.base_addr = (Elf32_Addr)__module_start;
+ core_module.base_addr = (Elf_Addr)__module_start;
init_module_subsystem(&core_module);