diff options
Diffstat (limited to 'dln.c')
| -rw-r--r-- | dln.c | 1520 |
1 files changed, 308 insertions, 1212 deletions
@@ -15,23 +15,23 @@ #define dln_memerror rb_memerror #define dln_exit rb_exit #define dln_loaderror rb_loaderror +#define dln_fatalerror rb_fatal #else #define dln_notimplement --->>> dln not implemented <<<--- #define dln_memerror abort #define dln_exit exit static void dln_loaderror(const char *format, ...); +#define dln_fatalerror dln_loaderror #endif #include "dln.h" #include "internal.h" +#include "internal/box.h" +#include "internal/compilers.h" #ifdef HAVE_STDLIB_H # include <stdlib.h> #endif -#ifdef USE_DLN_A_OUT -char *dln_argv0; -#endif - #if defined(HAVE_ALLOCA_H) #include <alloca.h> #endif @@ -42,6 +42,10 @@ char *dln_argv0; # include <strings.h> #endif +#if defined __APPLE__ +# include <AvailabilityMacros.h> +#endif + #ifndef xmalloc void *xmalloc(); void *xcalloc(); @@ -59,7 +63,7 @@ void *xrealloc(); #include <sys/stat.h> #ifndef S_ISDIR -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif #ifdef HAVE_SYS_PARAM_H @@ -73,17 +77,8 @@ void *xrealloc(); # include <unistd.h> #endif -#ifndef _WIN32 -char *getenv(); -#endif - -#ifdef __APPLE__ -# if defined(HAVE_DLOPEN) - /* Mac OS X with dlopen (10.3 or later) */ -# define MACOSX_DLOPEN -# else -# define MACOSX_DYLD -# endif +#ifndef UNREACHABLE_RETURN +# define UNREACHABLE_RETURN(x) return (x) #endif #ifndef dln_loaderror @@ -98,12 +93,12 @@ dln_loaderror(const char *format, ...) } #endif -#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP) +#if defined(HAVE_DLOPEN) && !defined(_AIX) && !defined(_UNICOSMP) /* dynamic load with dlopen() */ # define USE_DLN_DLOPEN #endif -#if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT) || defined(MACOSX_DYLD) +#if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(NeXT) # define EXTERNAL_PREFIX "_" #else # define EXTERNAL_PREFIX "" @@ -116,983 +111,52 @@ dln_loaderror(const char *format, ...) #define isdirsep(x) ((x) == '/') #endif -static size_t -init_funcname_len(const char **file) +#if defined(_WIN32) || defined(USE_DLN_DLOPEN) +struct string_part { + const char *ptr; + size_t len; +}; + +static struct string_part +init_funcname_len(const char *file) { - const char *p = *file, *base, *dot = NULL; + const char *p = file, *base, *dot = NULL; /* Load the file as an object one */ for (base = p; *p; p++) { /* Find position of last '/' */ - if (*p == '.' && !dot) dot = p; - if (isdirsep(*p)) base = p+1, dot = NULL; + if (*p == '.' && !dot) dot = p; + if (isdirsep(*p)) base = p+1, dot = NULL; } - *file = base; /* Delete suffix if it exists */ - return (dot ? dot : p) - base; -} - -static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX; - -#define init_funcname(buf, file) do {\ - const char *base = (file);\ - const size_t flen = init_funcname_len(&base);\ - const size_t plen = sizeof(funcname_prefix);\ - char *const tmp = ALLOCA_N(char, plen+flen+1);\ - if (!tmp) {\ - dln_memerror();\ - }\ - memcpy(tmp, funcname_prefix, plen);\ - memcpy(tmp+plen, base, flen);\ - tmp[plen+flen] = '\0';\ - *(buf) = tmp;\ -} while (0) - -#ifdef USE_DLN_A_OUT - -#ifndef LIBC_NAME -# define LIBC_NAME "libc.a" -#endif - -#ifndef DLN_DEFAULT_LIB_PATH -# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:." -#endif - -#include <errno.h> - -static int dln_errno; - -#define DLN_ENOEXEC ENOEXEC /* Exec format error */ -#define DLN_ECONFL 1201 /* Symbol name conflict */ -#define DLN_ENOINIT 1202 /* No initializer given */ -#define DLN_EUNDEF 1203 /* Undefine symbol remains */ -#define DLN_ENOTLIB 1204 /* Not a library file */ -#define DLN_EBADLIB 1205 /* Malformed library file */ -#define DLN_EINIT 1206 /* Not initialized */ - -static int dln_init_p = 0; - -#include <ar.h> -#include <a.out.h> -#ifndef N_COMM -# define N_COMM 0x12 -#endif -#ifndef N_MAGIC -# define N_MAGIC(x) (x).a_magic -#endif - -#define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC) - -#include "ruby/util.h" -#include "ruby/st.h" - -static st_table *sym_tbl; -static st_table *undef_tbl; - -static int load_lib(); - -static int -load_header(int fd, struct exec *hdrp, long disp) -{ - int size; - - lseek(fd, disp, 0); - size = read(fd, hdrp, sizeof(struct exec)); - if (size == -1) { - dln_errno = errno; - return -1; - } - if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) { - dln_errno = DLN_ENOEXEC; - return -1; - } - return 0; -} - -#if defined(sequent) -#define RELOC_SYMBOL(r) ((r)->r_symbolnum) -#define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr) -#define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr) -#define RELOC_TARGET_SIZE(r) ((r)->r_length) -#endif - -/* Default macros */ -#ifndef RELOC_ADDRESS -#define RELOC_ADDRESS(r) ((r)->r_address) -#define RELOC_EXTERN_P(r) ((r)->r_extern) -#define RELOC_SYMBOL(r) ((r)->r_symbolnum) -#define RELOC_MEMORY_SUB_P(r) 0 -#define RELOC_PCREL_P(r) ((r)->r_pcrel) -#define RELOC_TARGET_SIZE(r) ((r)->r_length) -#endif - -#if defined(__sun) && defined(__sparc) -/* Sparc (Sun 4) macros */ -# undef relocation_info -# define relocation_info reloc_info_sparc -# define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type]) -# define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type]) -# define R_LENGTH(r) (reloc_r_length[(r)->r_type]) -static const int reloc_r_rightshift[] = { - 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0, -}; -static const int reloc_r_bitsize[] = { - 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16, -}; -static const int reloc_r_length[] = { - 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -}; -# define R_PCREL(r) \ - ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) -# define R_SYMBOL(r) ((r)->r_index) -#endif - -#if defined(sequent) -#define R_SYMBOL(r) ((r)->r_symbolnum) -#define R_MEMORY_SUB(r) ((r)->r_bsr) -#define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr) -#define R_LENGTH(r) ((r)->r_length) -#endif - -#ifndef R_SYMBOL -# define R_SYMBOL(r) ((r)->r_symbolnum) -# define R_MEMORY_SUB(r) 0 -# define R_PCREL(r) ((r)->r_pcrel) -# define R_LENGTH(r) ((r)->r_length) -#endif - -static struct relocation_info * -load_reloc(int fd, struct exec *hdrp, long disp) -{ - struct relocation_info *reloc; - int size; - - lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0); - size = hdrp->a_trsize + hdrp->a_drsize; - reloc = (struct relocation_info*)xmalloc(size); - if (reloc == NULL) { - dln_errno = errno; - return NULL; - } - - if (read(fd, reloc, size) != size) { - dln_errno = errno; - free(reloc); - return NULL; - } - - return reloc; -} - -static struct nlist * -load_sym(int fd, struct exec *hdrp, long disp) -{ - struct nlist * buffer; - struct nlist * sym; - struct nlist * end; - long displ; - int size; - - lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0); - if (read(fd, &size, sizeof(int)) != sizeof(int)) { - goto err_noexec; - } - - buffer = (struct nlist*)xmalloc(hdrp->a_syms + size); - if (buffer == NULL) { - dln_errno = errno; - return NULL; - } - - lseek(fd, disp + N_SYMOFF(*hdrp), 0); - if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) { - free(buffer); - goto err_noexec; - } - - sym = buffer; - end = sym + hdrp->a_syms / sizeof(struct nlist); - displ = (long)buffer + (long)(hdrp->a_syms); - - while (sym < end) { - sym->n_un.n_name = (char*)sym->n_un.n_strx + displ; - sym++; - } - return buffer; - - err_noexec: - dln_errno = DLN_ENOEXEC; - return NULL; + const size_t len = (dot ? dot : p) - base; + return (struct string_part){base, len}; } -static st_table * -sym_hash(struct exec *hdrp, struct nlist *syms) +static inline char * +concat_funcname(char *buf, const char *prefix, size_t plen, const struct string_part base) { - st_table *tbl; - struct nlist *sym = syms; - struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist)); - - tbl = st_init_strtable(); - if (tbl == NULL) { - dln_errno = errno; - return NULL; - } - - while (sym < end) { - st_insert(tbl, sym->n_un.n_name, sym); - sym++; + if (!buf) { + dln_memerror(); } - return tbl; + memcpy(buf, prefix, plen); + memcpy(buf + plen, base.ptr, base.len); + buf[plen + base.len] = '\0'; + return buf; } -static int -dln_init(const char *prog) -{ - char *file, fbuf[MAXPATHLEN]; - int fd; - struct exec hdr; - struct nlist *syms; - - if (dln_init_p == 1) return 0; - - file = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)); - if (file == NULL || (fd = open(file, O_RDONLY)) < 0) { - dln_errno = errno; - return -1; - } - - if (load_header(fd, &hdr, 0) == -1) return -1; - syms = load_sym(fd, &hdr, 0); - if (syms == NULL) { - close(fd); - return -1; - } - sym_tbl = sym_hash(&hdr, syms); - if (sym_tbl == NULL) { /* file may be start with #! */ - char c = '\0'; - char buf[MAXPATHLEN]; - char *p; - - free(syms); - lseek(fd, 0L, 0); - if (read(fd, &c, 1) == -1) { - dln_errno = errno; - return -1; - } - if (c != '#') goto err_noexec; - if (read(fd, &c, 1) == -1) { - dln_errno = errno; - return -1; - } - if (c != '!') goto err_noexec; - - p = buf; - /* skip forwarding spaces */ - while (read(fd, &c, 1) == 1) { - if (c == '\n') goto err_noexec; - if (c != '\t' && c != ' ') { - *p++ = c; - break; - } - } - /* read in command name */ - while (read(fd, p, 1) == 1) { - if (*p == '\n' || *p == '\t' || *p == ' ') break; - p++; - if (p-buf >= MAXPATHLEN) { - dln_errno = ENAMETOOLONG; - return -1; - } - } - *p = '\0'; - - return dln_init(buf); - } - dln_init_p = 1; - undef_tbl = st_init_strtable(); - close(fd); - return 0; - - err_noexec: - close(fd); - dln_errno = DLN_ENOEXEC; - return -1; -} - -static long -load_text_data(int fd, struct exec *hdrp, int bss, long disp) -{ - int size; - unsigned char* addr; - - lseek(fd, disp + N_TXTOFF(*hdrp), 0); - size = hdrp->a_text + hdrp->a_data; - - if (bss == -1) size += hdrp->a_bss; - else if (bss > 1) size += bss; - - addr = (unsigned char*)xmalloc(size); - if (addr == NULL) { - dln_errno = errno; - return 0; - } - - if (read(fd, addr, size) != size) { - dln_errno = errno; - free(addr); - return 0; - } - - if (bss == -1) { - memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss); - } - else if (bss > 0) { - memset(addr + hdrp->a_text + hdrp->a_data, 0, bss); - } - - return (long)addr; -} - -static int -undef_print(char *key, char *value) -{ - fprintf(stderr, " %s\n", key); - return ST_CONTINUE; -} - -static void -dln_print_undef(void) -{ - fprintf(stderr, " Undefined symbols:\n"); - st_foreach(undef_tbl, undef_print, NULL); -} - -static void -dln_undefined(void) -{ - if (undef_tbl->num_entries > 0) { - fprintf(stderr, "dln: Calling undefined function\n"); - dln_print_undef(); - dln_exit(1); - } -} - -struct undef { - char *name; - struct relocation_info reloc; - long base; - char *addr; - union { - char c; - short s; - long l; - } u; -}; - -static st_table *reloc_tbl = NULL; -static void -link_undef(const char *name, long base, struct relocation_info *reloc) -{ - static int u_no = 0; - struct undef *obj; - char *addr = (char*)(reloc->r_address + base); - - obj = (struct undef*)xmalloc(sizeof(struct undef)); - obj->name = strdup(name); - obj->reloc = *reloc; - obj->base = base; - switch (R_LENGTH(reloc)) { - case 0: /* byte */ - obj->u.c = *addr; - break; - case 1: /* word */ - obj->u.s = *(short*)addr; - break; - case 2: /* long */ - obj->u.l = *(long*)addr; - break; - } - if (reloc_tbl == NULL) { - reloc_tbl = st_init_numtable(); - } - st_insert(reloc_tbl, u_no++, obj); -} - -struct reloc_arg { - const char *name; - long value; -}; - -static int -reloc_undef(int no, struct undef *undef, struct reloc_arg *arg) -{ - int datum; - char *address; -#if defined(__sun) && defined(__sparc) - unsigned int mask = 0; -#endif - - if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE; - address = (char*)(undef->base + undef->reloc.r_address); - datum = arg->value; - - if (R_PCREL(&(undef->reloc))) datum -= undef->base; -#if defined(__sun) && defined(__sparc) - datum += undef->reloc.r_addend; - datum >>= R_RIGHTSHIFT(&(undef->reloc)); - mask = (1 << R_BITSIZE(&(undef->reloc))) - 1; - mask |= mask -1; - datum &= mask; - switch (R_LENGTH(&(undef->reloc))) { - case 0: - *address = undef->u.c; - *address &= ~mask; - *address |= datum; - break; - case 1: - *(short *)address = undef->u.s; - *(short *)address &= ~mask; - *(short *)address |= datum; - break; - case 2: - *(long *)address = undef->u.l; - *(long *)address &= ~mask; - *(long *)address |= datum; - break; - } -#else - switch (R_LENGTH(&(undef->reloc))) { - case 0: /* byte */ - if (R_MEMORY_SUB(&(undef->reloc))) - *address = datum - *address; - else *address = undef->u.c + datum; - break; - case 1: /* word */ - if (R_MEMORY_SUB(&(undef->reloc))) - *(short*)address = datum - *(short*)address; - else *(short*)address = undef->u.s + datum; - break; - case 2: /* long */ - if (R_MEMORY_SUB(&(undef->reloc))) - *(long*)address = datum - *(long*)address; - else *(long*)address = undef->u.l + datum; - break; - } -#endif - free(undef->name); - free(undef); - return ST_DELETE; -} - -static void -unlink_undef(const char *name, long value) -{ - struct reloc_arg arg; - - arg.name = name; - arg.value = value; - st_foreach(reloc_tbl, reloc_undef, &arg); -} - -#ifdef N_INDR -struct indr_data { - char *name0, *name1; -}; - -static int -reloc_repl(int no, struct undef *undef, struct indr_data *data) -{ - if (strcmp(data->name0, undef->name) == 0) { - free(undef->name); - undef->name = strdup(data->name1); - } - return ST_CONTINUE; -} -#endif - -static int -load_1(int fd, long disp, const char *need_init) -{ - static const char *libc = LIBC_NAME; - struct exec hdr; - struct relocation_info *reloc = NULL; - long block = 0; - long new_common = 0; /* Length of new common */ - struct nlist *syms = NULL; - struct nlist *sym; - struct nlist *end; - int init_p = 0; - - if (load_header(fd, &hdr, disp) == -1) return -1; - if (INVALID_OBJECT(hdr)) { - dln_errno = DLN_ENOEXEC; - return -1; - } - reloc = load_reloc(fd, &hdr, disp); - if (reloc == NULL) return -1; - - syms = load_sym(fd, &hdr, disp); - if (syms == NULL) { - free(reloc); - return -1; - } - - sym = syms; - end = syms + (hdr.a_syms / sizeof(struct nlist)); - while (sym < end) { - struct nlist *old_sym; - int value = sym->n_value; - -#ifdef N_INDR - if (sym->n_type == (N_INDR | N_EXT)) { - char *key = sym->n_un.n_name; - - if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) { - if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { - unlink_undef(key, old_sym->n_value); - free(key); - } - } - else { - struct indr_data data; - - data.name0 = sym->n_un.n_name; - data.name1 = sym[1].n_un.n_name; - st_foreach(reloc_tbl, reloc_repl, &data); - - st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL); - if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { - free(key); - } - } - sym += 2; - continue; - } -#endif - if (sym->n_type == (N_UNDF | N_EXT)) { - if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) { - old_sym = NULL; - } - - if (value) { - if (old_sym) { - sym->n_type = N_EXT | N_COMM; - sym->n_value = old_sym->n_value; - } - else { - int rnd = - value >= sizeof(double) ? sizeof(double) - 1 - : value >= sizeof(long) ? sizeof(long) - 1 - : sizeof(short) - 1; - - sym->n_type = N_COMM; - new_common += rnd; - new_common &= ~(long)rnd; - sym->n_value = new_common; - new_common += value; - } - } - else { - if (old_sym) { - sym->n_type = N_EXT | N_COMM; - sym->n_value = old_sym->n_value; - } - else { - sym->n_value = (long)dln_undefined; - st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL); - } - } - } - sym++; - } - - block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp); - if (block == 0) goto err_exit; - - sym = syms; - while (sym < end) { - struct nlist *new_sym; - char *key; - - switch (sym->n_type) { - case N_COMM: - sym->n_value += hdr.a_text + hdr.a_data; - case N_TEXT|N_EXT: - case N_DATA|N_EXT: - - sym->n_value += block; - - if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0 - && new_sym->n_value != (long)dln_undefined) { - dln_errno = DLN_ECONFL; - goto err_exit; - } - - key = sym->n_un.n_name; - if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) { - unlink_undef(key, sym->n_value); - free(key); - } - - new_sym = (struct nlist*)xmalloc(sizeof(struct nlist)); - *new_sym = *sym; - new_sym->n_un.n_name = strdup(sym->n_un.n_name); - st_insert(sym_tbl, new_sym->n_un.n_name, new_sym); - break; - - case N_TEXT: - case N_DATA: - sym->n_value += block; - break; - } - sym++; - } - - /* - * First comes the text-relocation - */ - { - struct relocation_info * rel = reloc; - struct relocation_info * rel_beg = reloc + - (hdr.a_trsize/sizeof(struct relocation_info)); - struct relocation_info * rel_end = reloc + - (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info); - - while (rel < rel_end) { - char *address = (char*)(rel->r_address + block); - long datum = 0; -#if defined(__sun) && defined(__sparc) - unsigned int mask = 0; -#endif +#define build_funcname(prefix, buf, file) do {\ + const struct string_part f = init_funcname_len(file);\ + const size_t plen = sizeof(prefix "") - 1;\ + *(buf) = concat_funcname(ALLOCA_N(char, plen+f.len+1), prefix, plen, f);\ +} while (0) - if (rel >= rel_beg) - address += hdr.a_text; - - if (rel->r_extern) { /* Look it up in symbol-table */ - sym = &(syms[R_SYMBOL(rel)]); - switch (sym->n_type) { - case N_EXT|N_UNDF: - link_undef(sym->n_un.n_name, block, rel); - case N_EXT|N_COMM: - case N_COMM: - datum = sym->n_value; - break; - default: - goto err_exit; - } - } /* end.. look it up */ - else { /* is static */ - switch (R_SYMBOL(rel)) { - case N_TEXT: - case N_DATA: - datum = block; - break; - case N_BSS: - datum = block + new_common; - break; - case N_ABS: - break; - } - } /* end .. is static */ - if (R_PCREL(rel)) datum -= block; - -#if defined(__sun) && defined(__sparc) - datum += rel->r_addend; - datum >>= R_RIGHTSHIFT(rel); - mask = (1 << R_BITSIZE(rel)) - 1; - mask |= mask -1; - datum &= mask; - - switch (R_LENGTH(rel)) { - case 0: - *address &= ~mask; - *address |= datum; - break; - case 1: - *(short *)address &= ~mask; - *(short *)address |= datum; - break; - case 2: - *(long *)address &= ~mask; - *(long *)address |= datum; - break; - } -#else - switch (R_LENGTH(rel)) { - case 0: /* byte */ - if (datum < -128 || datum > 127) goto err_exit; - *address += datum; - break; - case 1: /* word */ - *(short *)address += datum; - break; - case 2: /* long */ - *(long *)address += datum; - break; - } +#define init_funcname(buf, file) build_funcname(FUNCNAME_PREFIX, buf, file) #endif - rel++; - } - } - - if (need_init) { - int len; - char **libs_to_be_linked = 0; - char *buf; - - if (undef_tbl->num_entries > 0) { - if (load_lib(libc) == -1) goto err_exit; - } - - init_funcname(&buf, need_init); - len = strlen(buf); - - for (sym = syms; sym<end; sym++) { - char *name = sym->n_un.n_name; - if (name[0] == '_' && sym->n_value >= block) { - if (strcmp(name+1, "dln_libs_to_be_linked") == 0) { - libs_to_be_linked = (char**)sym->n_value; - } - else if (strcmp(name+1, buf) == 0) { - init_p = 1; - ((int (*)())sym->n_value)(); - } - } - } - if (libs_to_be_linked && undef_tbl->num_entries > 0) { - while (*libs_to_be_linked) { - load_lib(*libs_to_be_linked); - libs_to_be_linked++; - } - } - } - free(reloc); - free(syms); - if (need_init) { - if (init_p == 0) { - dln_errno = DLN_ENOINIT; - return -1; - } - if (undef_tbl->num_entries > 0) { - if (load_lib(libc) == -1) goto err_exit; - if (undef_tbl->num_entries > 0) { - dln_errno = DLN_EUNDEF; - return -1; - } - } - } - return 0; - - err_exit: - if (syms) free(syms); - if (reloc) free(reloc); - if (block) free((char*)block); - return -1; -} - -static int target_offset; -static int -search_undef(const char *key, int value, st_table *lib_tbl) -{ - long offset; - - if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE; - target_offset = offset; - return ST_STOP; -} - -struct symdef { - int rb_str_index; - int lib_offset; -}; - -const char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH; - -static int -load_lib(const char *lib) -{ - char *path, *file, fbuf[MAXPATHLEN]; - char *envpath = 0; - char armagic[SARMAG]; - int fd, size; - struct ar_hdr ahdr; - st_table *lib_tbl = NULL; - int *data, nsym; - struct symdef *base; - char *name_base; - - if (dln_init_p == 0) { - dln_errno = DLN_ENOINIT; - return -1; - } - - if (undef_tbl->num_entries == 0) return 0; - dln_errno = DLN_EBADLIB; - - if (lib[0] == '-' && lib[1] == 'l') { - long len = strlen(lib) + 4; - char *p = alloca(len); - snprintf(p, len, "lib%s.a", lib+2); - lib = p; - } - - /* library search path: */ - /* look for environment variable DLN_LIBRARY_PATH first. */ - /* then variable dln_librrb_ary_path. */ - /* if path is still NULL, use "." for path. */ - path = getenv("DLN_LIBRARY_PATH"); - if (path == NULL) path = dln_librrb_ary_path; - else path = envpath = strdup(path); - - file = dln_find_file_r(lib, path, fbuf, sizeof(fbuf)); - if (envpath) free(envpath); - fd = open(file, O_RDONLY); - if (fd == -1) goto syserr; - size = read(fd, armagic, SARMAG); - if (size == -1) goto syserr; - - if (size != SARMAG) { - dln_errno = DLN_ENOTLIB; - goto badlib; - } - size = read(fd, &ahdr, sizeof(ahdr)); - if (size == -1) goto syserr; - if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) { - goto badlib; - } - - if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) { - /* make hash table from __.SYMDEF */ - - lib_tbl = st_init_strtable(); - data = (int*)xmalloc(size); - if (data == NULL) goto syserr; - size = read(fd, data, size); - nsym = *data / sizeof(struct symdef); - base = (struct symdef*)(data + 1); - name_base = (char*)(base + nsym) + sizeof(int); - while (nsym > 0) { - char *name = name_base + base->rb_str_index; - - st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr)); - nsym--; - base++; - } - for (;;) { - target_offset = -1; - st_foreach(undef_tbl, search_undef, lib_tbl); - if (target_offset == -1) break; - if (load_1(fd, target_offset, 0) == -1) { - st_free_table(lib_tbl); - free(data); - goto badlib; - } - if (undef_tbl->num_entries == 0) break; - } - free(data); - st_free_table(lib_tbl); - } - else { - /* linear library, need to scan (FUTURE) */ - - for (;;) { - int offset = SARMAG; - int found = 0; - struct exec hdr; - struct nlist *syms, *sym, *end; - - while (undef_tbl->num_entries > 0) { - found = 0; - lseek(fd, offset, 0); - size = read(fd, &ahdr, sizeof(ahdr)); - if (size == -1) goto syserr; - if (size == 0) break; - if (size != sizeof(ahdr) - || sscanf(ahdr.ar_size, "%d", &size) != 1) { - goto badlib; - } - offset += sizeof(ahdr); - if (load_header(fd, &hdr, offset) == -1) - goto badlib; - syms = load_sym(fd, &hdr, offset); - if (syms == NULL) goto badlib; - sym = syms; - end = syms + (hdr.a_syms / sizeof(struct nlist)); - while (sym < end) { - if (sym->n_type == N_EXT|N_TEXT - && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) { - break; - } - sym++; - } - if (sym < end) { - found++; - free(syms); - if (load_1(fd, offset, 0) == -1) { - goto badlib; - } - } - offset += size; - if (offset & 1) offset++; - } - if (found) break; - } - } - close(fd); - return 0; - - syserr: - dln_errno = errno; - badlib: - if (fd >= 0) close(fd); - return -1; -} - -static int -load(const char *file) -{ - int fd; - int result; - - if (dln_init_p == 0) { - if (dln_init(dln_argv0) == -1) return -1; - } - result = strlen(file); - if (file[result-1] == 'a') { - return load_lib(file); - } - - fd = open(file, O_RDONLY); - if (fd == -1) { - dln_errno = errno; - return -1; - } - result = load_1(fd, 0, file); - close(fd); - - return result; -} - -void* -dln_sym(const char *name) -{ - struct nlist *sym; - - if (st_lookup(sym_tbl, name, &sym)) - return (void*)sym->n_value; - return NULL; -} - -#endif /* USE_DLN_A_OUT */ #ifdef USE_DLN_DLOPEN # include <dlfcn.h> #endif -#ifdef __hpux -#include <errno.h> -#include "dl.h" -#endif - #if defined(_AIX) #include <ctype.h> /* for isdigit() */ #include <errno.h> /* for global errno */ @@ -1108,10 +172,6 @@ dln_sym(const char *name) #define NSLINKMODULE_OPTION_BINDNOW 1 #endif #endif -#else -#ifdef MACOSX_DYLD -#include <mach-o/dyld.h> -#endif #endif #ifdef _WIN32 @@ -1128,46 +188,23 @@ dln_strerror(char *message, size_t size) size_t len = snprintf(message, size, "%d: ", error); #define format_message(sublang) FormatMessage(\ - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \ - NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \ - message + len, size - len, NULL) + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \ + NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \ + message + len, size - len, NULL) if (format_message(SUBLANG_ENGLISH_US) == 0) - format_message(SUBLANG_DEFAULT); + format_message(SUBLANG_DEFAULT); for (p = message + len; *p; p++) { - if (*p == '\n' || *p == '\r') - *p = ' '; + if (*p == '\n' || *p == '\r') + *p = ' '; } return message; } #define dln_strerror() dln_strerror(message, sizeof message) -#elif ! defined _AIX +#elif defined USE_DLN_DLOPEN static const char * dln_strerror(void) { -#ifdef USE_DLN_A_OUT - char *strerror(); - - switch (dln_errno) { - case DLN_ECONFL: - return "Symbol name conflict"; - case DLN_ENOINIT: - return "No initializer given"; - case DLN_EUNDEF: - return "Unresolved symbols"; - case DLN_ENOTLIB: - return "Not a library file"; - case DLN_EBADLIB: - return "Malformed library file"; - case DLN_EINIT: - return "Not initialized"; - default: - return strerror(dln_errno); - } -#endif - -#ifdef USE_DLN_DLOPEN return (char*)dlerror(); -#endif } #endif @@ -1181,18 +218,18 @@ aix_loaderror(const char *pathname) snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname); if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) { - ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t"); - ERRBUF_APPEND("/usr/sbin/execerror ruby "); - for (i=0; message[i]; i++) { - ERRBUF_APPEND("\""); - ERRBUF_APPEND(message[i]); - ERRBUF_APPEND("\" "); - } - ERRBUF_APPEND("\n"); + ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t"); + ERRBUF_APPEND("/usr/sbin/execerror ruby "); + for (i=0; message[i]; i++) { + ERRBUF_APPEND("\""); + ERRBUF_APPEND(message[i]); + ERRBUF_APPEND("\" "); + } + ERRBUF_APPEND("\n"); } else { - ERRBUF_APPEND(strerror(errno)); - ERRBUF_APPEND("[loadquery failed]"); + ERRBUF_APPEND(strerror(errno)); + ERRBUF_APPEND("[loadquery failed]"); } dln_loaderror("%s", errbuf); } @@ -1210,22 +247,22 @@ rb_w32_check_imported(HMODULE ext, HMODULE mine) desc = ImageDirectoryEntryToData(ext, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size); if (!desc) return 0; while (desc->Name) { - PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics); - PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk); - for (; piat->u1.Function; piat++, pint++) { - static const char prefix[] = "rb_"; - PIMAGE_IMPORT_BY_NAME pii; - const char *name; - - if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue; - pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData); - name = (const char *)pii->Name; - if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) { - FARPROC addr = GetProcAddress(mine, name); - if (addr) return (FARPROC)piat->u1.Function == addr; - } - } - desc++; + PIMAGE_THUNK_DATA pint = (PIMAGE_THUNK_DATA)((char *)ext + desc->Characteristics); + PIMAGE_THUNK_DATA piat = (PIMAGE_THUNK_DATA)((char *)ext + desc->FirstThunk); + for (; piat->u1.Function; piat++, pint++) { + static const char prefix[] = "rb_"; + PIMAGE_IMPORT_BY_NAME pii; + const char *name; + + if (IMAGE_SNAP_BY_ORDINAL(pint->u1.Ordinal)) continue; + pii = (PIMAGE_IMPORT_BY_NAME)((char *)ext + (size_t)pint->u1.AddressOfData); + name = (const char *)pii->Name; + if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) { + FARPROC addr = GetProcAddress(mine, name); + if (addr) return (FARPROC)piat->u1.Function == addr; + } + } + desc++; } return 1; } @@ -1233,11 +270,11 @@ rb_w32_check_imported(HMODULE ext, HMODULE mine) #if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR #define translit_separator(src) do { \ - char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \ - do { \ - *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \ - } while (c); \ - (src) = tmp; \ + char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \ + do { \ + *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \ + } while (c); \ + (src) = tmp; \ } while (0) #else #define translit_separator(str) (void)(str) @@ -1246,44 +283,82 @@ rb_w32_check_imported(HMODULE ext, HMODULE mine) #ifdef USE_DLN_DLOPEN # include "ruby/internal/stdbool.h" # include "internal/warnings.h" +static bool +dln_incompatible_func(void *handle, const char *funcname, void *const fp, const char **libname) +{ + void *ex = dlsym(handle, funcname); + if (!ex) return false; + if (ex == fp) return false; +# if defined(HAVE_DLADDR) && !defined(__CYGWIN__) + Dl_info dli; + if (dladdr(ex, &dli)) { + *libname = dli.dli_fname; + } +# endif + return true; +} + COMPILER_WARNING_PUSH #if defined(__clang__) || GCC_VERSION_SINCE(4, 2, 0) COMPILER_WARNING_IGNORED(-Wpedantic) #endif static bool -dln_incompatible_library_p(void *handle) +dln_incompatible_library_p(void *handle, const char **libname) { - void *ex = dlsym(handle, EXTERNAL_PREFIX"ruby_xmalloc"); - void *const fp = (void *)ruby_xmalloc; - return ex && ex != fp; +#define check_func(func) \ + if (dln_incompatible_func(handle, EXTERNAL_PREFIX #func, (void *)&func, libname)) \ + return true + check_func(ruby_xmalloc); + return false; } COMPILER_WARNING_POP #endif -void* -dln_load(const char *file) +#if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) +/* assume others than old Mac OS X have no problem */ +# define dln_disable_dlclose() false + +#elif !defined(MAC_OS_X_VERSION_10_11) || \ + (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11) +/* targeting older versions only */ +# define dln_disable_dlclose() true + +#elif MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11 +/* targeting newer versions only */ +# define dln_disable_dlclose() false + +#else +/* support both versions, and check at runtime */ +# include <sys/sysctl.h> + +static bool +dln_disable_dlclose(void) { -#if (defined _WIN32 || defined USE_DLN_DLOPEN) && defined RUBY_EXPORT - static const char incompatible[] = "incompatible library version"; -#endif -#if !defined(_AIX) && !defined(NeXT) - const char *error = 0; + int mib[] = {CTL_KERN, KERN_OSREV}; + int32_t rev; + size_t size = sizeof(rev); + if (sysctl(mib, numberof(mib), &rev, &size, NULL, 0)) return true; + if (rev < MAC_OS_X_VERSION_10_11) return true; + return false; +} #endif -#if defined _WIN32 - HINSTANCE handle; - WCHAR *winfile; - char message[1024]; - void (*init_fct)(); - char *buf; +#if defined(_WIN32) || defined(USE_DLN_DLOPEN) +static void * +dln_open(const char *file) +{ + static const char incompatible[] = "incompatible library version"; + const char *error = NULL; + void *handle; - /* Load the file as an object one */ - init_funcname(&buf, file); +#if defined(_WIN32) +# define DLN_DEFINED + char message[1024]; /* Convert the file path to wide char */ - winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL); + WCHAR *winfile = rb_w32_mbstr_to_wstr(CP_UTF8, file, -1, NULL); if (!winfile) { - dln_memerror(); + dln_memerror(); } /* Load file */ @@ -1291,184 +366,205 @@ dln_load(const char *file) free(winfile); if (!handle) { - error = dln_strerror(); - goto failed; + error = dln_strerror(); + goto failed; } -#if defined _WIN32 && defined RUBY_EXPORT +# if defined(RUBY_EXPORT) if (!rb_w32_check_imported(handle, rb_libruby_handle())) { - FreeLibrary(handle); - error = incompatible; - goto failed; + FreeLibrary(handle); + error = incompatible; + goto failed; } -#endif +# endif + +#elif defined(USE_DLN_DLOPEN) +# define DLN_DEFINED - if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) { - dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file); +# ifndef RTLD_LAZY +# define RTLD_LAZY 1 +# endif +# ifdef __INTERIX +# undef RTLD_GLOBAL +# endif +# ifndef RTLD_GLOBAL +# define RTLD_GLOBAL 0 +# endif +# ifndef RTLD_LOCAL +# define RTLD_LOCAL 0 /* TODO: 0??? some systems (including libc) use 0x00100 for RTLD_GLOBAL, 0x00000 for RTLD_LOCAL */ +# endif + + /* Load file */ + int mode = rb_box_available() ? RTLD_LAZY|RTLD_LOCAL : RTLD_LAZY|RTLD_GLOBAL; + handle = dlopen(file, mode); + if (handle == NULL) { + error = dln_strerror(); + goto failed; } - /* Call the init code */ - (*init_fct)(); - return handle; -#else -#ifdef USE_DLN_A_OUT - if (load(file) == -1) { - error = dln_strerror(); - goto failed; +# if defined(RUBY_EXPORT) + { + const char *libruby_name = NULL; + if (dln_incompatible_library_p(handle, &libruby_name)) { + if (dln_disable_dlclose()) { + /* dlclose() segfaults */ + if (libruby_name) { + dln_fatalerror("linked to incompatible %s - %s", libruby_name, file); + } + dln_fatalerror("%s - %s", incompatible, file); + } + else { + if (libruby_name) { + const size_t len = strlen(libruby_name); + char *const tmp = ALLOCA_N(char, len + 1); + if (tmp) memcpy(tmp, libruby_name, len + 1); + libruby_name = tmp; + } + dlclose(handle); + if (libruby_name) { + dln_loaderror("linked to incompatible %s - %s", libruby_name, file); + } + error = incompatible; + goto failed; + } + } } - return 0; -#else +# endif +#endif - char *buf; - /* Load the file as an object one */ - init_funcname(&buf, file); - translit_separator(file); + return handle; -#ifdef USE_DLN_DLOPEN -#define DLN_DEFINED - { - void *handle; - void (*init_fct)(); + failed: + dln_loaderror("%s - %s", error, file); +} -#ifndef RTLD_LAZY -# define RTLD_LAZY 1 -#endif -#ifdef __INTERIX -# undef RTLD_GLOBAL -#endif -#ifndef RTLD_GLOBAL -# define RTLD_GLOBAL 0 +static void * +dln_sym(void *handle, const char *symbol) +{ +#if defined(_WIN32) + return GetProcAddress(handle, symbol); +#elif defined(USE_DLN_DLOPEN) + return dlsym(handle, symbol); #endif +} - /* Load file */ - if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) { - error = dln_strerror(); - goto failed; - } -# if defined RUBY_EXPORT - { - if (dln_incompatible_library_p(handle)) { - -# if defined __APPLE__ && \ - defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ - (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11) - /* dlclose() segfaults */ - rb_fatal("%s - %s", incompatible, file); -# else - dlclose(handle); - error = incompatible; - goto failed; -# endif - } - } -# endif +static uintptr_t +dln_sym_func(void *handle, const char *symbol) +{ + void *func = dln_sym(handle, symbol); - init_fct = (void(*)())(VALUE)dlsym(handle, buf); - if (init_fct == NULL) { - const size_t errlen = strlen(error = dln_strerror()) + 1; - error = memcpy(ALLOCA_N(char, errlen), error, errlen); - dlclose(handle); - goto failed; - } - /* Call the init code */ - (*init_fct)(); - - return handle; + if (func == NULL) { + const char *error; +#if defined(_WIN32) + char message[1024]; + error = dln_strerror(); +#elif defined(USE_DLN_DLOPEN) + const size_t errlen = strlen(error = dln_strerror()) + 1; + error = memcpy(ALLOCA_N(char, errlen), error, errlen); +#endif + dln_loaderror("%s - %s", error, symbol); } -#endif /* USE_DLN_DLOPEN */ + return (uintptr_t)func; +} -#ifdef __hpux -#define DLN_DEFINED - { - shl_t lib = NULL; - int flags; - void (*init_fct)(); - - flags = BIND_DEFERRED; - lib = shl_load(file, flags, 0); - if (lib == NULL) { - extern int errno; - dln_loaderror("%s - %s", strerror(errno), file); - } - shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct); - if (init_fct == NULL) { - shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct); - if (init_fct == NULL) { - errno = ENOSYM; - dln_loaderror("%s - %s", strerror(ENOSYM), file); - } - } - (*init_fct)(); - return (void*)lib; - } -#endif /* hpux */ +#define dln_sym_callable(rettype, argtype, handle, symbol) \ + (*(rettype (*)argtype)dln_sym_func(handle, symbol)) +#endif -#if defined(_AIX) -#define DLN_DEFINED - { - void (*init_fct)(); - - init_fct = (void(*)())load((char*)file, 1, 0); - if (init_fct == NULL) { - aix_loaderror(file); - } - if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) { - aix_loaderror(file); - } - (*init_fct)(); - return (void*)init_fct; +void * +dln_symbol(void *handle, const char *symbol) +{ +#if defined(_WIN32) || defined(USE_DLN_DLOPEN) + if (EXTERNAL_PREFIX[0]) { + const size_t symlen = strlen(symbol); + char *const tmp = ALLOCA_N(char, symlen + sizeof(EXTERNAL_PREFIX)); + if (!tmp) dln_memerror(); + memcpy(tmp, EXTERNAL_PREFIX, sizeof(EXTERNAL_PREFIX) - 1); + memcpy(tmp + sizeof(EXTERNAL_PREFIX) - 1, symbol, symlen + 1); + symbol = tmp; + } + if (handle == NULL) { +# if defined(USE_DLN_DLOPEN) + handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); +# elif defined(_WIN32) + handle = rb_libruby_handle(); +# else + return NULL; +# endif } -#endif /* _AIX */ - -#if defined(MACOSX_DYLD) -#define DLN_DEFINED -/*---------------------------------------------------- - By SHIROYAMA Takayuki Psi@fortune.nest.or.jp - - Special Thanks... - Yu tomoak-i@is.aist-nara.ac.jp, - Mi hisho@tasihara.nest.or.jp, - sunshine@sunshineco.com, - and... Miss ARAI Akino(^^;) - ----------------------------------------------------*/ - { - int dyld_result; - NSObjectFileImage obj_file; /* handle, but not use it */ - /* "file" is module file name . - "buf" is pointer to initial function name with "_" . */ + return dln_sym(handle, symbol); +#else + return NULL; +#endif +} - void (*init_fct)(); +#if defined(RUBY_DLN_CHECK_ABI) && defined(USE_DLN_DLOPEN) +static bool +abi_check_enabled_p(void) +{ + const char *val = getenv("RUBY_ABI_CHECK"); + return val == NULL || !(val[0] == '0' && val[1] == '\0'); +} +#endif - dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file); +static void * +dln_load_and_init(const char *file, const char *init_fct_name) +{ +#if defined(DLN_DEFINED) + void *handle = dln_open(file); - if (dyld_result != NSObjectFileImageSuccess) { - dln_loaderror("Failed to load %.200s", file); - } +#ifdef RUBY_DLN_CHECK_ABI + typedef unsigned long long abi_version_number; + abi_version_number binary_abi_version = + dln_sym_callable(abi_version_number, (void), handle, EXTERNAL_PREFIX "ruby_abi_version")(); + if (binary_abi_version != RUBY_ABI_VERSION && abi_check_enabled_p()) { + dln_loaderror("incompatible ABI version of binary - %s", file); + } +#endif - NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW); + /* Call the init code */ + dln_sym_callable(void, (void), handle, init_fct_name)(); - /* lookup the initial function */ - if (!NSIsSymbolNameDefined(buf)) { - dln_loaderror("Failed to lookup Init function %.200s",file); - } - init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf)); - (*init_fct)(); + return handle; - return (void*)init_fct; +#elif defined(_AIX) +# define DLN_DEFINED + { + void (*init_fct)(void); + + /* TODO: check - AIX's load system call will return the first/last symbol/function? */ + init_fct = (void(*)(void))load((char*)file, 1, 0); + if (init_fct == NULL) { + aix_loaderror(file); + } + if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) { + aix_loaderror(file); + } + (*init_fct)(); + return (void*)init_fct; } -#endif - -#ifndef DLN_DEFINED +#else dln_notimplement(); + UNREACHABLE_RETURN(0); #endif +} -#endif /* USE_DLN_A_OUT */ -#endif -#if !defined(_AIX) && !defined(NeXT) - failed: - dln_loaderror("%s - %s", error, file); -#endif +void * +dln_load(const char *file) +{ + return dln_load_feature(file, file); +} - return 0; /* dummy return */ +void * +dln_load_feature(const char *file, const char *fname) +{ +#if defined(DLN_DEFINED) + char *init_fct_name; + init_funcname(&init_fct_name, fname); + return dln_load_and_init(file, init_fct_name); +#else + dln_notimplement(); + UNREACHABLE_RETURN(0); +#endif } |
