home *** CD-ROM | disk | FTP | other *** search
- /*
- ** #include <a.out.h>
- ** #include "assoc.h"
- ** #include "dyna_link.h
- **
- **
- ** lk_get_header(fd, hdrp, offset) /@ reads an a.out header into memory @/
- ** int fd; /@ an open file-descriptor @/
- ** struct exec *hdrp; /@ pointer to memory for a.out header @/
- ** long offset; /@ displacement of file (for archives)@/
- **
- ** lk_get_symbols(fd, hdrp, offset) /@ Reads symbols into memory @/
- ** int fd; /@ an open file-descriptor @/
- ** struct exec *hdrp; /@ pointer to previously initialized header @/
- ** long offset; /@ displacement of file (for archives) @/
- **
- ** assoc_mem
- ** lk_sym_hash(hdrp, syms); /@ Creates lookup-table for symbols @/
- ** struct exec *hdrp; /@ pointer to previously initialized header @/
- ** struct nlist *syms; /@ pointer to previously initialized symbols @/
- **
- ** func_ptr
- ** lk_dynaload(codep, hdrp, hash_table, filename) /@ loads named file @/
- ** int* codep; /@ pointer to memory for return-code @/
- ** struct exec* hdrp; /@ pointer to previously initialized header @/
- ** assoc_mem hash_table; /@ previously initialized lookup-table @/
- ** char* filename;
- **
- ** func_ptr /@ loads a file, given by file-descriptor and offset. @/
- ** lk_dynaload_fd(codep, hdrp, hash_tab, fd, offset)
- ** int *codep; /@ pointer to memory for return-code @/
- ** struct exec *hdrp; /@ pointer to previously initialized header @/
- ** assoc_mem hash_tab; /@ previously initialized lookup-table @/
- ** int fd; /@ an open file-descriptor @/
- ** long disp; /@ displacement of file (for archives) @/
- **
- ** This library furnishes routines for doing a dynamic load of an executable
- ** segment ( .o file).
- **
- ** The caller first must build a lookup-table for the symbols
- ** of the executing program. (See assoc.doc for description
- ** of lookup-table routines.)
- **
- ** Once the lookup-table has been made, the program may repeatedly call
- ** lk_dynaload() or lk_dynaload_fd() to load segments.
- ** Loaded segments may be freed using free().
- **
- ** The routines to be used for building the lookup-table are
- ** lk_get_header(), lk_get_symbols(), and lk_sym_hash(). These are
- ** also potentially useful for other link-editor applications, and
- ** for that reason are parameterized so that they may be used on
- ** archive members, as well as on individual a.out files.
- **
- ** lk_get_header() returns 0 on success, -1 on failure. Sets errno.
- **
- ** lk_get_symbols() returns a buffer from malloc() on success, null
- ** on failure. Sets errno.
- **
- ** lk_sym_hash() returns an assoc_mem on success (see assoc.doc), null
- ** on failure. Sets errno.
- **
- ** lk_dynaload() and lk_dynaload_fd() return a pointer to the entry-point
- ** of the .o file on success, null on failure. Sets *codep (see
- ** parameters). The values for *codep are defined in dyna_link.h:
- **
- ** #define lk_ok 0
- ** #define lk_undefd 1
- ** #define lk_bad_format 2
- ** #define lk_perror -1
- **
- ** lk_ok means "okay."
- ** lk_undefd means that one or more symbols required by the .o file
- ** are not defined in the lookup-table. In this case the char**
- ** lk_undefined will have been set to point to a vector containing
- ** the undefined symbols.
- ** lk_bad_format means that the .o file is not formatted occording
- ** to the a.out file conventions.
- ** lk_perror means that errno has been set.
- **
- **
- ** Tutorial example:
- **
- ** main(argc, argv)
- ** char** argv;
- ** {
- ** char* me = (char*) which(argv[0]);
- ** char* prog = (char*)(argv[1]);
- ** func_ptr entry_point;
- ** assoc_mem hash_tab;
- ** struct exec main_hdr;
- ** struct nlist * main_syms;
- ** int code;
- ** int fd = open( me, O_RDONLY );
- **
- ** lk_get_header(fd, &main_hdr, 0 );
- ** main_syms = lk_get_symbols(fd, &main_hdr, 0 );
- ** close(fd);
- ** hash_tab = lk_sym_hash(&main_hdr, main_syms);
- **
- ** (func_ptr) entry_point
- ** = lk_dynaload( &code, &main_hdr, hash_tab, prog );
- ** if(entry_point)
- ** (*(func_ptr) entry_point)();
- ** else
- ** switch(code)
- ** {
- ** case lk_undefd:
- ** { char** undef = lk_undefined;
- ** printf("undefined:\n");
- ** while(*undef) printf("%s\n", *undef++);
- ** }
- ** break;
- ** case lk_perror:
- ** perror(prog);
- ** break;
- ** case lk_bad_format:
- ** printf("bad format\n");
- ** break;
- ** }
- ** }
- ** }
- ** exit(0);
- ** }
- **
- */
-
-
- #include <stdio.h>
- #include <a.out.h>
- #include <sys/file.h>
- #include <sys/types.h>
- #include <errno.h>
- #include <sys/stat.h>
- #include <ctype.h>
-
- #include "assoc.h"
- #include "dyna_link.h"
-
- lk_get_header(fd, hdrp, disp)
- int fd;
- struct exec *hdrp;
- long disp;
- {
- lseek(fd, disp, 0);
- if (read(fd, hdrp, sizeof(struct exec)) != sizeof(struct exec))
- {hdrp->a_magic = 0; return -1; }
- return 0;
- }
-
- /* This routine buffers up the symbols and strings from a file. */
- /* Converts file-displacements of strings to pointers. */
- struct nlist *
- lk_get_symbols(fd, hdrp, disp)
- int fd;
- struct exec *hdrp;
- long disp;
- {
- struct nlist * buffer;
- unsigned long size;
-
- if(N_BADMAG(*hdrp))
- { errno = ENOEXEC;
- return 0;
- }
-
- lseek(fd, disp + N_SYMOFF(*hdrp) + hdrp->a_syms, 0);
- if(read(fd, &size, 4) != 4)
- return 0;
-
- buffer = (struct nlist*) malloc(hdrp->a_syms + size);
- if(buffer == 0) return 0;
-
- lseek(fd, disp + N_SYMOFF(*hdrp), 0);
- if(read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size)
- { free(buffer);
- return 0;
- }
-
- {
- struct nlist * sym = buffer;
- struct nlist * end = sym + hdrp->a_syms / sizeof(struct nlist);
- long 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;
-
- }
- static file_size;
-
- /* Buffers up relocation info */
- struct relocation_info *
- lk_get_reloc(fd, hdrp, disp)
- int fd;
- struct exec *hdrp;
- long disp;
- {
- struct relocation_info * buffer;
- int size;
-
-
- if(N_BADMAG(*hdrp))
- { errno = ENOEXEC;
- return 0;
- }
-
- lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
-
- size = hdrp->a_trsize + hdrp->a_drsize;
- buffer = (struct relocation_info*) malloc( size );
-
- if(buffer == 0) return 0;
-
- if(read(fd, buffer, size) != size)
- { free(buffer);
- return 0;
- }
-
- return buffer;
-
- }
-
- /* Buffers up text and data */
- static
- unsigned char *
- lk_get_text_and_data(fd, hdrp, bss, disp )
- int fd;
- struct exec *hdrp;
- int bss; /* -1 iff we should allocate hdrp->a_bss extra space,
- ** larger numbers indicate extra space to allocate
- */
- long disp;
- {
- unsigned char * buffer;
- int size;
-
- if(N_BADMAG(*hdrp))
- {
- errno = ENOEXEC;
- return 0;
- }
-
- 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;
-
- buffer = (unsigned char*) malloc( size );
-
- if(buffer == 0) return 0;
-
- if(read(fd, buffer, size) != size)
- { free(buffer);
- return 0;
- }
-
- if(bss == -1)
- bzero(buffer + hdrp->a_text + hdrp->a_data, hdrp->a_bss);
- else if(bss > 0)
- bzero(buffer + hdrp->a_text + hdrp->a_data, bss );
-
- return buffer;
-
- }
-
- char** lk_undefined = 0;
-
- func_ptr
- lk_dynaload_fd(codep, hdrp, hash_tab, fd, disp)
- int *codep;
- struct exec *hdrp;
- assoc_mem hash_tab;
- int fd;
- long disp;
- {
- func_ptr retval = 0;
- unsigned char* text_data_bss;
- struct exec header;
- struct nlist * symbols = 0;
- struct relocation_info * reloc = 0;
- long new_common = 0; /* Length of new common */
- assoc_mem lk_sym_hash();
- int undefineds = 0;
- char*** argv_h = 0;
-
- *codep = 0;
-
- if(fd < 0) { *codep = lk_perror; goto end; }
-
- if( lk_get_header(fd, &header, 0) != 0
- ||(reloc = lk_get_reloc(fd, &header, 0)) == 0
- ||(symbols = lk_get_symbols(fd, &header, 0 )) == 0
- )
- { *codep = lk_perror; goto end; }
-
-
- if( header.a_magic != 0x107 )
- { *codep = lk_bad_format; goto end; }
-
- /* First we will buzz through the new symbols, resolving them.
- */
- { struct nlist * symbol = symbols;
- struct nlist * endp = symbols + (header.a_syms / sizeof(struct nlist));
- long last_value = new_common;
- while(symbol < endp)
- { int type;
- int value;
- struct nlist * old_symbol = 0;
- struct nlist ** old_symbol_p = 0;
-
- type = symbol->n_type;
- value = symbol->n_value;
-
- if(type == N_EXT + N_UNDF )
- { /* is not defined here yet. */
- old_symbol_p = (struct nlist **)
- assoc_lookup(symbol->n_un.n_name, hash_tab);
-
- if(old_symbol_p) old_symbol = *old_symbol_p;
-
- if(value != 0)
- { /* is common */
- if(old_symbol == 0)
- { /* is new common */
- int rnd =
- value >= sizeof(double) ? sizeof(double) - 1
- : value >= sizeof(long) ? sizeof(long) - 1
- : sizeof(short) - 1;
-
- symbol->n_type = N_COMM;
- new_common += rnd;
- new_common &= ~(long)rnd;
- symbol->n_value = new_common;
- new_common += value;
- }
- else
- { /* Is old common */
-
- symbol->n_type = N_EXT + N_COMM;
- symbol->n_value = old_symbol -> n_value;
- }
- last_value = symbol->n_value;
- } /* end .. is common */
- else
- { /* is extern */
- if(old_symbol == 0)
- { /* symbol is unresolved. Sigh. */
- /* But will will keep on going, looking for others. */
- if(argv_h == 0)
- argv_h = (char***) argv_new();
- argv_put(argv_h, symbol->n_un.n_name);
- undefineds = 1;
- }
- else
- {
- symbol->n_type = N_EXT + N_COMM;
- symbol->n_value = old_symbol -> n_value;
- last_value = symbol->n_value;
- }
- }
- } /* end.. is undefined */
-
- # ifdef do_stabs
- if(type&N_EXT && type&N_TYPE == N_UNDF && type&N_STAB)
- {
- symbol->n_value = last_value;
- symbol->n_type = (type&N_STAB) | (N_EXT+N_COMM);
- }
- # endif
- symbol++;
- }
- } /* end buzz */
-
- if(undefineds) { goto end; }
- retval = (func_ptr)lk_get_text_and_data(fd, &header, header.a_bss + new_common, 0 );
-
-
- /* Now zip through relocation data, doing our stuff.
- ** First comes the text-relocation
- */
- {
- struct relocation_info * rel = reloc;
- struct relocation_info * first_data =
- reloc +
- (header.a_trsize / sizeof(struct relocation_info));
-
- struct relocation_info * endp =
- reloc +
- (header.a_trsize + header.a_drsize )/ sizeof(struct relocation_info);
-
- while(rel < endp )
- {
-
- char *address =
- (char*) (rel->r_address + (long)retval);
-
- long datum;
-
- if(rel >= first_data)
- address += header.a_text;
-
- switch (rel->r_length)
- {
- case 0: /* byte */
- datum = *address;
- break;
-
- case 1: /* word */
- datum = *(short *)address;
- break;
-
- case 2: /* long */
- datum = *(long *)address;
- break;
-
- default:
- { *codep = lk_bad_format;
- goto end;
- }
-
- }
-
- if(rel->r_extern)
- { /* Look it up in symbol-table */
- struct nlist * symbol = &(symbols[rel->r_symbolnum]);
- int type = symbol->n_type;
- char* name = symbol->n_un.n_name;
- int value = symbol->n_value;
-
- if(symbol->n_type == N_EXT + N_COMM)
- /* old common or external */
- datum += symbol->n_value;
- else if (symbol->n_type == N_COMM)
- /* new common */
- datum += (long)retval + header.a_text + header.a_data;
- else { *codep = lk_bad_format; goto end; }
- } /* end.. look it up */
- else
- { /* is static */
- switch(rel->r_symbolnum & N_TYPE)
- {
- case N_TEXT: case N_DATA:
- datum += (long)retval;
- break;
- case N_BSS:
- datum += (long)retval + new_common;
- break;
- case N_ABS:
- break;
- }
- } /* end .. is static */
- if(rel->r_pcrel) datum -= (long)retval;
-
- switch (rel->r_length) {
-
- case 0: /* byte */
- if (datum < -128 || datum > 127)
- {
- *codep = lk_bad_format; goto end;
- }
- *address = datum;
- break;
- case 1: /* word */
- if (datum < -32768 || datum > 32767)
- {
- *codep = lk_bad_format; goto end;
- }
- *(short *)address = datum;
- break;
- case 2: /* long */
- *(long *)address = datum;
- break;
- }
- rel++;
- }
-
- } /* end.. zip */
-
- end:
-
- sfree(reloc); sfree(symbols);
-
- if(*codep != 0) { sfree(retval); retval = 0; }
- if(undefineds)
- { *codep = lk_undefd;
- sfree(lk_undefined);
- lk_undefined = *argv_h;
- free(argv_h);
- }
- return retval;
-
- }
-
- func_ptr
- lk_dynaload( codep, hdrp, hash_tab, filename )
- int *codep;
- struct exec *hdrp;
- assoc_mem hash_tab;
- char* filename;
- {
-
- int fd = open(filename, O_RDONLY );
- func_ptr retval = lk_dynaload_fd(codep, hdrp, hash_tab, fd, 0);
-
- if(fd >= 0) close(fd);
- return retval;
-
- }
-
- assoc_mem
- lk_sym_hash(hdrp, syms)
- struct exec * hdrp;
- struct nlist * syms;
- {
- assoc_mem result = new_assoc_mem(sizeof(struct nlist*));
-
- if(result == 0) return 0;
-
- {
- struct nlist * sym = syms;
- struct nlist * end = syms + (hdrp->a_syms / sizeof(struct nlist));
-
- while(sym < end)
- {
- struct nlist ** ptr = (struct nlist**) assoc(sym->n_un.n_name, result);
- if(ptr == 0) return 0;
- *ptr = sym;
- sym++;
- }
- }
- return result;
- }
-
- #undef demo_dyna_link
-
- #ifdef demo_dyna_link
- main(argc, argv)
- char** argv;
- {
- char* me = (char*) which(argv[0]);
- char* prog = (char*)(argv[1]);
- func_ptr tion;
- assoc_mem hash_tab;
- struct exec main_hdr;
- struct nlist * main_syms;
-
- int fd = open( me, O_RDONLY );
-
- lk_get_header(fd, &main_hdr, 0 );
- main_syms = lk_get_symbols(fd, &main_hdr, 0 );
- close(fd);
- hash_tab = lk_sym_hash(&main_hdr, main_syms);
-
- { int times;
- int code;
-
- if(argc==2) times = 1;
- else times = atoi(argv[2]);
-
- while(times--)
- {
- # include <sys/time.h>
- struct timeval t1, t2;
- struct timezone tz;
- long usecs;
- gettimeofday(&t1, &tz);
- (func_ptr)tion = lk_dynaload( &code, &main_hdr, hash_tab, prog );
- gettimeofday(&t2, &tz);
-
- usecs =( t2.tv_sec - t1.tv_sec ) * 1000000 + t2.tv_usec - t1.tv_usec;
- /* fprintf(stderr, "%d %d %d\n", usecs, t2.tv_sec - t1.tv_sec,
- t2.tv_usec - t1.tv_usec);
- */
- if(tion)
- (*(func_ptr)tion)();
- else
- switch(code)
- {
- case lk_undefd:
- { char** undef = lk_undefined;
- printf("undefined:\n");
- while(*undef) printf("%s\n", *undef++);
- }
- break;
- case lk_perror:
- perror(prog);
- break;
- case lk_bad_format:
- printf("bad format\n");
- break;
- }
- }
- }
- exit(0);
- }
-
- int xstderr;
- int xfprintf;
-
- kluge() { printf(); }
-
- int comm_main;
- int ext;
- foo()
- {
- fprintf(stderr, "(%x %x)foo be called.\n", stderr, fprintf);
- fprintf(stderr, "(%x %x) <<\n", xstderr, xfprintf);
- }
-
- #endif demo_dyna_link
-