home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume14 / bsd-dyna-link / dyna_link.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-05-08  |  14.6 KB  |  617 lines

  1. /*
  2. **   #include <a.out.h>
  3. **   #include "assoc.h"
  4. **   #include "dyna_link.h
  5. **   
  6. **   
  7. **   lk_get_header(fd, hdrp, offset)  /@ reads an a.out header into memory @/
  8. **      int fd;               /@ an open file-descriptor @/
  9. **      struct exec *hdrp;    /@ pointer to memory for a.out header @/
  10. **      long offset;          /@ displacement of file (for archives)@/
  11. **
  12. **   lk_get_symbols(fd, hdrp, offset)  /@ Reads symbols into memory @/
  13. **      int fd;               /@ an open file-descriptor @/
  14. **      struct exec *hdrp;    /@ pointer to previously initialized header @/
  15. **      long offset;          /@ displacement of file (for archives) @/
  16. **
  17. **   assoc_mem
  18. **   lk_sym_hash(hdrp, syms); /@ Creates lookup-table for symbols @/
  19. **      struct exec *hdrp;    /@ pointer to previously initialized header @/
  20. **      struct nlist *syms;   /@ pointer to previously initialized symbols @/
  21. **
  22. **   func_ptr 
  23. **   lk_dynaload(codep, hdrp, hash_table, filename) /@ loads named file @/
  24. **      int* codep;           /@ pointer to memory for return-code @/
  25. **      struct exec* hdrp;    /@ pointer to previously initialized header @/
  26. **      assoc_mem hash_table; /@ previously initialized lookup-table @/
  27. **      char* filename;
  28. **
  29. **   func_ptr  /@ loads a file, given by file-descriptor and offset. @/
  30. **   lk_dynaload_fd(codep, hdrp, hash_tab, fd, offset)
  31. **     int *codep;            /@ pointer to memory for return-code @/
  32. **     struct exec *hdrp;     /@ pointer to previously initialized header @/
  33. **     assoc_mem hash_tab;    /@ previously initialized lookup-table @/
  34. **     int fd;                /@ an open file-descriptor @/
  35. **     long disp;             /@ displacement of file (for archives) @/
  36. **
  37. **   This library furnishes routines for doing a dynamic load of an executable
  38. **   segment ( .o file).
  39. **
  40. **   The caller first must build a lookup-table for the symbols
  41. **   of the executing program.  (See assoc.doc for description
  42. **   of lookup-table routines.)
  43. **
  44. **   Once the lookup-table has been made, the program may repeatedly call
  45. **   lk_dynaload() or lk_dynaload_fd() to load segments.
  46. **   Loaded segments may be freed using free().
  47. **
  48. **   The routines to be used for building the lookup-table are
  49. **   lk_get_header(), lk_get_symbols(), and lk_sym_hash().  These are
  50. **   also potentially useful for other link-editor applications, and
  51. **   for that reason are parameterized so that they may be used on
  52. **   archive members, as well as on individual a.out files.
  53. **
  54. **   lk_get_header() returns 0 on success, -1 on failure.  Sets errno.
  55. **
  56. **   lk_get_symbols() returns a buffer from malloc() on success, null
  57. **     on failure.  Sets errno.
  58. **
  59. **   lk_sym_hash() returns an assoc_mem on success (see assoc.doc), null
  60. **     on failure.  Sets errno.
  61. **
  62. **   lk_dynaload() and lk_dynaload_fd() return a pointer to the entry-point
  63. **     of the .o file on success, null on failure.  Sets *codep (see
  64. **     parameters).  The values for *codep are defined in dyna_link.h:
  65. **
  66. **      #define lk_ok 0
  67. **      #define lk_undefd 1
  68. **      #define lk_bad_format 2
  69. **      #define lk_perror -1
  70. **
  71. **   lk_ok means "okay."
  72. **   lk_undefd means that one or more symbols required by the .o file
  73. **     are not defined in the lookup-table.  In this case the char**
  74. **     lk_undefined will have been set to point to a vector containing
  75. **     the undefined symbols.
  76. **   lk_bad_format means that the .o file is not formatted occording
  77. **     to the a.out file conventions.
  78. **   lk_perror means that errno has been set.
  79. **
  80. **  
  81. **   Tutorial example:
  82. **
  83. **   main(argc, argv)
  84. **     char** argv;
  85. **   {
  86. **     char* me = (char*) which(argv[0]);
  87. **     char* prog = (char*)(argv[1]);
  88. **     func_ptr entry_point;
  89. **     assoc_mem hash_tab;
  90. **     struct exec main_hdr;
  91. **     struct nlist * main_syms;
  92. **     int code;
  93. **     int fd = open( me, O_RDONLY );
  94. **   
  95. **     lk_get_header(fd, &main_hdr, 0 );
  96. **     main_syms = lk_get_symbols(fd, &main_hdr, 0 );
  97. **     close(fd);
  98. **     hash_tab = lk_sym_hash(&main_hdr, main_syms);
  99. **   
  100. **     (func_ptr) entry_point
  101. **                 = lk_dynaload( &code, &main_hdr, hash_tab, prog );
  102. **     if(entry_point)
  103. **           (*(func_ptr) entry_point)();
  104. **     else
  105. **        switch(code)
  106. **           {
  107. **           case lk_undefd:
  108. **             { char** undef = lk_undefined;
  109. **           printf("undefined:\n");
  110. **           while(*undef) printf("%s\n", *undef++);
  111. **             }
  112. **             break;
  113. **           case lk_perror:
  114. **             perror(prog);
  115. **             break;
  116. **           case lk_bad_format:
  117. **             printf("bad format\n");
  118. **             break;
  119. **           }
  120. **         }
  121. **     }
  122. **     exit(0);
  123. **   }
  124. **   
  125. */
  126.  
  127.  
  128. #include <stdio.h>
  129. #include <a.out.h>
  130. #include <sys/file.h>
  131. #include <sys/types.h>
  132. #include <errno.h>
  133. #include <sys/stat.h>
  134. #include <ctype.h>
  135.  
  136. #include "assoc.h"
  137. #include "dyna_link.h"
  138.  
  139. lk_get_header(fd, hdrp, disp)
  140.   int fd;
  141.   struct exec *hdrp;
  142.   long disp;
  143. {
  144.   lseek(fd, disp, 0);
  145.   if (read(fd, hdrp, sizeof(struct exec)) != sizeof(struct exec))
  146.     {hdrp->a_magic = 0;  return -1; }
  147.   return 0;
  148. }
  149.  
  150. /* This routine buffers up the symbols and strings from a file. */
  151. /* Converts file-displacements of strings to pointers.          */
  152. struct nlist *
  153. lk_get_symbols(fd, hdrp, disp)
  154.   int fd;
  155.   struct exec *hdrp;
  156.   long disp;
  157. {
  158.   struct nlist * buffer;
  159.   unsigned long size;
  160.  
  161.   if(N_BADMAG(*hdrp))
  162.     { errno = ENOEXEC;
  163.       return 0;
  164.     }
  165.  
  166.   lseek(fd, disp + N_SYMOFF(*hdrp) + hdrp->a_syms, 0);
  167.   if(read(fd, &size, 4) != 4)
  168.     return 0;
  169.  
  170.   buffer = (struct nlist*) malloc(hdrp->a_syms + size);
  171.   if(buffer == 0) return 0;
  172.   
  173.   lseek(fd, disp + N_SYMOFF(*hdrp), 0);
  174.   if(read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size)
  175.     { free(buffer);
  176.       return 0;
  177.     }
  178.   
  179.   {
  180.     struct nlist * sym = buffer;
  181.     struct nlist * end = sym + hdrp->a_syms / sizeof(struct nlist);
  182.     long displ = (long)buffer + (long)(hdrp->a_syms);
  183.  
  184.     while(sym < end)
  185.       {
  186.     sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
  187.     sym++;
  188.       }
  189.   }
  190.   return buffer;
  191.   
  192. }
  193. static file_size;
  194.  
  195. /* Buffers up relocation info */
  196. struct relocation_info *
  197. lk_get_reloc(fd, hdrp, disp)
  198.      int fd;
  199.      struct exec *hdrp;
  200.      long disp;
  201. {
  202.   struct relocation_info * buffer;
  203.   int size;
  204.  
  205.  
  206.   if(N_BADMAG(*hdrp))
  207.     { errno = ENOEXEC;
  208.       return 0;
  209.     }
  210.   
  211.   lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
  212.   
  213.   size = hdrp->a_trsize + hdrp->a_drsize;
  214.   buffer = (struct relocation_info*) malloc( size );
  215.  
  216.   if(buffer == 0) return 0;
  217.   
  218.   if(read(fd, buffer, size) !=  size)
  219.     { free(buffer);
  220.       return 0;
  221.     }
  222.   
  223.   return buffer;
  224.   
  225. }
  226.  
  227. /* Buffers up text and data */
  228. static
  229. unsigned char *
  230. lk_get_text_and_data(fd, hdrp, bss, disp )
  231.   int fd;
  232.   struct exec *hdrp;
  233.   int bss; /* -1 iff we should allocate hdrp->a_bss extra space,
  234.        ** larger numbers indicate extra space to allocate
  235.        */
  236.   long disp;
  237. {
  238.   unsigned char * buffer;
  239.   int size;
  240.  
  241.   if(N_BADMAG(*hdrp))
  242.     {
  243.       errno = ENOEXEC;
  244.       return 0;
  245.     }
  246.   
  247.   lseek(fd, disp + N_TXTOFF(*hdrp), 0);
  248.   
  249.   size = hdrp->a_text + hdrp->a_data;
  250.  
  251.   if(bss == -1) size += hdrp->a_bss;
  252.   else if (bss > 1) size += bss;
  253.  
  254.   buffer = (unsigned char*) malloc( size );
  255.   
  256.   if(buffer == 0) return 0;
  257.   
  258.   if(read(fd, buffer, size) !=  size)
  259.     { free(buffer);
  260.       return 0;
  261.     }
  262.  
  263.   if(bss == -1)
  264.     bzero(buffer +  hdrp->a_text + hdrp->a_data, hdrp->a_bss);
  265.   else if(bss > 0)
  266.     bzero(buffer +  hdrp->a_text + hdrp->a_data, bss );
  267.  
  268.   return buffer;
  269.   
  270. }
  271.  
  272. char** lk_undefined = 0;
  273.  
  274. func_ptr
  275. lk_dynaload_fd(codep, hdrp, hash_tab, fd, disp)
  276.   int *codep;
  277.   struct exec *hdrp;
  278.   assoc_mem hash_tab;
  279.   int fd;
  280.   long disp;
  281. {
  282.   func_ptr retval = 0;
  283.   unsigned char* text_data_bss;
  284.   struct exec header;
  285.   struct nlist * symbols = 0;
  286.   struct relocation_info * reloc = 0;
  287.   long new_common = 0; /* Length of new common */
  288.   assoc_mem lk_sym_hash();
  289.   int undefineds = 0;
  290.   char*** argv_h = 0;
  291.  
  292.   *codep = 0;
  293.  
  294.   if(fd < 0) { *codep = lk_perror; goto end; }
  295.  
  296.   if(  lk_get_header(fd, &header, 0) != 0
  297.      ||(reloc = lk_get_reloc(fd, &header, 0)) == 0
  298.      ||(symbols = lk_get_symbols(fd, &header, 0 )) == 0
  299.     )
  300.     { *codep = lk_perror; goto end; }
  301.  
  302.  
  303.   if(  header.a_magic != 0x107 )
  304.     { *codep = lk_bad_format; goto end; }
  305.  
  306.   /* First we will buzz through the new symbols, resolving them.
  307.   */
  308.   { struct nlist * symbol = symbols;
  309.     struct nlist * endp = symbols + (header.a_syms / sizeof(struct nlist));
  310.     long last_value = new_common;
  311.     while(symbol < endp)
  312.       { int type;
  313.     int value;
  314.     struct nlist * old_symbol = 0;
  315.     struct nlist ** old_symbol_p = 0;
  316.  
  317.     type = symbol->n_type;
  318.         value = symbol->n_value;
  319.  
  320.     if(type == N_EXT + N_UNDF )
  321.       { /* is not defined here yet. */
  322.           old_symbol_p = (struct nlist **)
  323.           assoc_lookup(symbol->n_un.n_name, hash_tab);
  324.  
  325.         if(old_symbol_p) old_symbol = *old_symbol_p;
  326.  
  327.         if(value != 0)
  328.           { /* is common */
  329.         if(old_symbol == 0)
  330.           { /* is new common */
  331.             int rnd =
  332.               value >= sizeof(double) ? sizeof(double) - 1
  333.             : value >= sizeof(long) ? sizeof(long) - 1
  334.               : sizeof(short) - 1;
  335.  
  336.             symbol->n_type = N_COMM;
  337.             new_common += rnd;
  338.             new_common &= ~(long)rnd;
  339.             symbol->n_value = new_common;
  340.             new_common += value;
  341.           }
  342.         else
  343.           { /* Is old common */
  344.  
  345.             symbol->n_type = N_EXT + N_COMM;
  346.             symbol->n_value = old_symbol -> n_value;
  347.           }
  348.         last_value = symbol->n_value;
  349.           } /* end .. is common */
  350.         else
  351.           { /* is extern */
  352.         if(old_symbol == 0)
  353.           { /* symbol is unresolved. Sigh. */
  354.             /* But will will keep on going, looking for others. */
  355.             if(argv_h == 0)
  356.               argv_h = (char***) argv_new();
  357.             argv_put(argv_h, symbol->n_un.n_name);
  358.             undefineds = 1;
  359.           }
  360.         else
  361.           {
  362.             symbol->n_type = N_EXT + N_COMM;
  363.             symbol->n_value = old_symbol -> n_value;
  364.             last_value = symbol->n_value;
  365.           }
  366.           }
  367.       } /* end.. is undefined */
  368.  
  369. #       ifdef do_stabs
  370.     if(type&N_EXT && type&N_TYPE == N_UNDF && type&N_STAB)
  371.       {
  372.         symbol->n_value = last_value;
  373.         symbol->n_type = (type&N_STAB) | (N_EXT+N_COMM);
  374.       }
  375. #       endif
  376.     symbol++;    
  377.       }
  378.   } /* end buzz */
  379.  
  380.   if(undefineds) { goto end; }
  381.   retval = (func_ptr)lk_get_text_and_data(fd, &header, header.a_bss + new_common, 0 );
  382.  
  383.  
  384.   /* Now zip through relocation data, doing our stuff. 
  385.   ** First comes the text-relocation
  386.   */
  387.   {
  388.     struct relocation_info * rel = reloc;
  389.     struct relocation_info * first_data =
  390.       reloc + 
  391.     (header.a_trsize  / sizeof(struct relocation_info));
  392.  
  393.     struct relocation_info * endp =
  394.       reloc + 
  395.     (header.a_trsize + header.a_drsize )/ sizeof(struct relocation_info);
  396.  
  397.     while(rel < endp )
  398.       {
  399.     
  400.     char *address = 
  401.       (char*) (rel->r_address + (long)retval);
  402.  
  403.     long datum;
  404.  
  405.     if(rel >= first_data)
  406.       address += header.a_text;
  407.     
  408.     switch (rel->r_length)
  409.       {
  410.       case 0:        /* byte */
  411.         datum = *address;
  412.         break;
  413.         
  414.       case 1:        /* word */
  415.         datum = *(short *)address;
  416.         break;
  417.         
  418.       case 2:        /* long */
  419.         datum = *(long *)address;
  420.         break;
  421.         
  422.       default:
  423.         { *codep = lk_bad_format;
  424.           goto end;
  425.         }
  426.  
  427.       }
  428.         
  429.     if(rel->r_extern)
  430.       { /* Look it up in symbol-table */
  431.         struct nlist * symbol = &(symbols[rel->r_symbolnum]);
  432.         int type = symbol->n_type;
  433.         char* name = symbol->n_un.n_name;
  434.         int value = symbol->n_value;
  435.  
  436.         if(symbol->n_type == N_EXT + N_COMM)
  437.           /* old common or external */
  438.            datum += symbol->n_value;
  439.         else if (symbol->n_type == N_COMM)
  440.           /* new common */
  441.           datum += (long)retval + header.a_text + header.a_data;
  442.         else {  *codep = lk_bad_format; goto end; }
  443.       } /* end.. look it up */
  444.     else
  445.       { /* is static */
  446.         switch(rel->r_symbolnum & N_TYPE)
  447.           {
  448.           case N_TEXT: case N_DATA:
  449.         datum += (long)retval;
  450.         break;
  451.           case N_BSS:
  452.         datum += (long)retval +  new_common;
  453.         break;
  454.           case N_ABS:
  455.         break;
  456.           }
  457.       } /* end .. is static */
  458.     if(rel->r_pcrel) datum -= (long)retval;
  459.  
  460.     switch (rel->r_length) {
  461.       
  462.     case 0:        /* byte */
  463.       if (datum < -128 || datum > 127)
  464.         { 
  465.           *codep = lk_bad_format; goto end;
  466.         }
  467.       *address = datum;
  468.       break;
  469.     case 1:        /* word */
  470.       if (datum < -32768 || datum > 32767)
  471.         { 
  472.           *codep = lk_bad_format; goto end;
  473.         }
  474.       *(short *)address = datum;
  475.       break;
  476.     case 2:        /* long */
  477.       *(long *)address = datum;
  478.       break;
  479.     }
  480.     rel++;
  481.       }
  482.     
  483.   } /* end.. zip */
  484.  
  485.  end:
  486.  
  487.   sfree(reloc); sfree(symbols);
  488.  
  489.   if(*codep != 0) { sfree(retval); retval = 0; }
  490.   if(undefineds)
  491.     { *codep = lk_undefd;
  492.       sfree(lk_undefined);
  493.       lk_undefined = *argv_h;
  494.       free(argv_h);
  495.     }
  496.   return retval;
  497.  
  498. }
  499.  
  500. func_ptr
  501. lk_dynaload( codep, hdrp, hash_tab, filename )
  502.   int *codep;
  503.   struct exec *hdrp;
  504.   assoc_mem hash_tab;
  505.   char* filename;
  506. {
  507.  
  508.   int fd = open(filename, O_RDONLY );
  509.   func_ptr retval = lk_dynaload_fd(codep, hdrp, hash_tab, fd, 0); 
  510.  
  511.   if(fd >= 0) close(fd);
  512.   return retval;
  513.   
  514. }
  515.  
  516. assoc_mem
  517. lk_sym_hash(hdrp, syms)
  518.   struct exec * hdrp;
  519.   struct nlist * syms;
  520. {
  521.   assoc_mem result = new_assoc_mem(sizeof(struct nlist*));
  522.  
  523.   if(result == 0) return 0;
  524.  
  525.   {
  526.     struct nlist * sym = syms;
  527.     struct nlist * end = syms + (hdrp->a_syms / sizeof(struct nlist));
  528.  
  529.     while(sym < end)
  530.       {
  531.     struct nlist ** ptr = (struct nlist**) assoc(sym->n_un.n_name, result);
  532.     if(ptr == 0) return 0;
  533.     *ptr = sym;
  534.     sym++;
  535.       }
  536.   }
  537.   return result;
  538. }
  539.  
  540. #undef demo_dyna_link
  541.  
  542. #ifdef demo_dyna_link
  543. main(argc, argv)
  544.   char** argv;
  545. {
  546.   char* me = (char*) which(argv[0]);
  547.   char* prog = (char*)(argv[1]);
  548.   func_ptr tion;
  549.   assoc_mem hash_tab;
  550.   struct exec main_hdr;
  551.   struct nlist * main_syms;
  552.  
  553.   int fd = open( me, O_RDONLY );
  554.  
  555.   lk_get_header(fd, &main_hdr, 0 );
  556.   main_syms = lk_get_symbols(fd, &main_hdr, 0 );
  557.   close(fd);
  558.   hash_tab = lk_sym_hash(&main_hdr, main_syms);
  559.  
  560.   { int times;
  561.     int code;
  562.  
  563.     if(argc==2) times = 1;
  564.       else times = atoi(argv[2]);
  565.  
  566.     while(times--)
  567.       {
  568. #       include <sys/time.h>
  569.     struct timeval t1, t2;
  570.     struct timezone tz;
  571.     long usecs;
  572.     gettimeofday(&t1, &tz);
  573.     (func_ptr)tion = lk_dynaload( &code, &main_hdr, hash_tab, prog );
  574.     gettimeofday(&t2, &tz);
  575.  
  576.     usecs =( t2.tv_sec - t1.tv_sec ) * 1000000 + t2.tv_usec - t1.tv_usec;
  577. /*    fprintf(stderr, "%d %d %d\n", usecs, t2.tv_sec - t1.tv_sec,
  578.         t2.tv_usec - t1.tv_usec);
  579. */
  580.     if(tion)
  581.       (*(func_ptr)tion)();
  582.     else
  583.       switch(code)
  584.         {
  585.         case lk_undefd:
  586.           { char** undef = lk_undefined;
  587.         printf("undefined:\n");
  588.         while(*undef) printf("%s\n", *undef++);
  589.           }
  590.           break;
  591.         case lk_perror:
  592.           perror(prog);
  593.           break;
  594.         case lk_bad_format:
  595.           printf("bad format\n");
  596.           break;
  597.         }
  598.       }
  599.   }
  600.   exit(0);
  601. }
  602.  
  603. int xstderr;
  604. int xfprintf;
  605.  
  606. kluge() { printf(); }
  607.  
  608. int comm_main;
  609. int ext;
  610. foo()
  611. {
  612.   fprintf(stderr, "(%x %x)foo be called.\n", stderr, fprintf);
  613.   fprintf(stderr, "(%x %x) <<\n", xstderr, xfprintf);
  614. }
  615.  
  616. #endif demo_dyna_link
  617.