/* Dynamically-loadable-modules API Copyright (C) 2000 Andrew Zabolotny Partly based on work by Charles Sandmann and DJ Delorie. Usage of this library is not restricted in any way. The full license text can be found in the file dxe.txt. */ #ifndef __DXE2_H__ #define __DXE2_H__ #ifdef __cplusplus extern "C" { # define EXTERN_C extern "C" #else # define EXTERN_C extern #endif #if 0 -------------------------------------------------------------------------------- The overall structure of the DXE2 file: < header > (see the dxe2_header structure) < exported symbols table > { /* The section starts at dxe2_header.sym_f_offset offset. Between header and exported symbols table a zero-terminated string is put containing a description of the module */ long offset; /* symbol offset */ char symbol_name []; /* symbol name */ } [dxe2_header.n_exp_syms]; < unresolved symbols table > { unsigned short relative_reloc_count; /* number of relative relocs */ unsigned short absolute_reloc_count; /* number of absolute relocs */ char symbol_name []; /* symbol name */ long relative_relocs [relative_reloc_count]; /* the offsets at which we should add the absolute value of the symbol */ long absolute_relocs [absolute_reloc_count]; /* the offsets at which we should add the relative value of the symbol */ } [dxe2_header.n_unres_symsunres] < relocations > { long offset; /* the offset at which we should add the base address of .text section */ } [dxe2_header.n_relocs]; < .text, .data, .bss > { /* this is the actual code, data and uninitialized data of the module. all the offsets above (in relocation records) are relative to the beginning of this section. The offset within the module of this section is defined by dxe2_header.sec_offset field. */ /* the file can be actually shorter than sec_offset + sec_size -- in this case the missing data is zeroed. this is used to shorten the DXE file by removing unused zeros at the end of file. */ } ------------------------------------------------------------------------------*/ #endif typedef struct { long magic; /* Magic number */ long sec_size; /* Size of combined code+data+bss section */ long sec_f_size; /* The size of code+data+bss section in file (the rest is zeroed) */ long sec_f_offset; /* Relative (to header) file offset of the code+data+bss section */ long sym_f_offset; /* Relative (to header) file offset to exported symbols table */ long n_exp_syms; /* Number of exported symbols */ long n_unres_syms; /* Number of unresolved symbols */ long n_relocs; /* Number of relocations */ } __attribute__((packed)) dxe2_header; #define DXE2_MAGIC 0x32455844 #ifndef __DXE2_INTERNAL_API__ /* A handle to a dynamic module */ typedef void *dxe_h; #endif typedef struct { const char *name; /* Symbol name ("printf", "strlen" and so on */ void *offset; /* Symbol offset */ } dxe_symbol_table; /* Register (yet another) table of symbols to be exported into the loaded modules. You can register any number of such tables. When a module with unresolved external symbols is loaded, all these tables are searched for the respective symbol. If no one is found, the last-resort handler is called. If even the last-resort handler cannot return an address, an error condition is raised. */ int dlregsym (dxe_symbol_table *symtab); /* Unregister the respective symbol table. */ int dlunregsym (dxe_symbol_table *symtab); /* Set the last-resort handler called when a unresolved symbol cannot be found in all the symbol tables that the dynamic loader have at his disposition. The handler should return NULL to rise a error condition, otherwise it should return a valid address */ void dlsetres (void *(*errh) (const char *)); /* The following variable contains a pointer to a function that is being called when static linking fails because of missing module. Note that due to delayed nature of static linkage, the error can pop up very late! If you want to check it at startup, call the "load_MODULENAME" function explicitly. The function should never return. */ extern void (*dlerrstatmod) (const char *module); /* The following variable contains a pointer to a function that is being called when during static linking the dynamic loader finds that some symbol is missing from dynamic module. The function should never return. */ extern void (*dlerrstatsym) (const char *module, const char *symbol); /* Use the following macros to build a table of symbols that are exported to dynamically loaded modules. This table should be passed to dlregsym(). Usage example: DXE_EXPORT_TABLE (st) DXE_EXPORT (printf) DXE_EXPORT (strlen) DXE_EXPORT (strchr) DXE_EXPORT_END dlregsym (st); dxe_h h = dlopen ("my.dxe", RTLD_GLOBAL); if (!h) { fprintf (stderr, "my.dxe: %s\n", dlerror ()); abort (); } The DXE_EXPORT_TABLE_AUTO macro can be used to register the table with the dynamic loader automatically during startup. To use it, just use DXE_EXPORT_TABLE_AUTO instead of DXE_EXPORT_TABLE. */ #define DXE_EXPORT_TABLE(name) dxe_symbol_table name [] = { #define DXE_EXPORT_TABLE_AUTO(name) \ extern dxe_symbol_table name []; \ __attribute__((constructor)) void name##_auto_register () \ { dlregsym (name); } \ dxe_symbol_table name [] = { #define DXE_EXPORT(symbol) { #symbol, (void *)&symbol }, #define DXE_EXPORT_END { NULL }}; /* Use the following macros to declare the load-on-demand and unload-on-demand functions for a statically-linked dynamic module. Usage example: DECLARE_STATIC_DXE (MYDXE); somefunc() { load_MYDXE (); ... unload_MYDXE (); } */ #define DECLARE_STATIC_DXE(name) \ EXTERN_C void load_##name (); \ EXTERN_C void unload_##name (); #ifdef __cplusplus } #endif #endif /* __DXE2_H__ */