home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / port / dec / dynloader.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  10.9 KB  |  472 lines

  1.  
  2. /*
  3.  *   DYNAMIC_LOADER.C
  4.  *
  5.  *   Dynamically load specified object module
  6.  *
  7.  *   IDENTIFICATION:
  8.  *   $Header: /private/postgres/src/port/dec/RCS/dynloader.c,v 1.7 1991/12/15 02:01:25 glass Exp $
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <sys/exec.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <fcntl.h>
  16.  
  17. #include "port.h"
  18. #include "tmp/c.h"
  19. #include "utils/log.h"
  20. #include "utils/fmgr.h"
  21.  
  22. char *sbrk();
  23. char *Align();
  24.  
  25. /*
  26.  *  WARNING: the exec header may show dsize = N and bsize = 0 where the
  27.  *  actual format in 'dat' and 'bss' is N - V and V.
  28.  */
  29.  
  30. static struct {
  31.     struct exec ex;
  32.     struct scnhdr txt;
  33.     struct scnhdr dat;
  34.     struct scnhdr bss;
  35. } hdr;
  36.  
  37. /*
  38.  *  Unfortunately, the MIPS proccessor's JAL (jump and link) instruction
  39.  *  only has a 28 bit resolution (26 bits long world aligned).  Therefore,
  40.  *  for dynamically loaded code in the data area (0x1000,0000) to access
  41.  *  routines in the text area, a jump table must be constructed in the
  42.  *  data area that uses the JR (jump register) instruction.
  43.  */
  44.  
  45. typedef struct {
  46.     long  ary[4];
  47.     /*
  48.      *  lui  r14,0xMMMM        0x3C0Exxxx
  49.      *  ori  r14,r14,0xLLLL    0x35CExxxx
  50.      *  jr   r14        0x01C00008  000000rrrrr00000... (r=01110)
  51.      *  nop            0x00000000
  52.      */
  53. } AJMP;
  54.  
  55. #define AJMP0    0x3C0E0000
  56. #define AJMP1    0x35CE0000
  57. #define AJMP2    0x01C00008
  58. #define AJMP3    0x00000000
  59.  
  60. static HDRR shdr;
  61.  
  62. #define a_nscns         ex.ex_f.f_nscns
  63. #define a_symptr        ex.ex_f.f_symptr
  64. #define a_nsyms         ex.ex_f.f_nsyms
  65.  
  66. #define a_tsize         ex.ex_o.tsize
  67. #define a_dsize         ex.ex_o.dsize
  68. #define a_bsize         ex.ex_o.bsize
  69.  
  70. AJMP    *AJmp;
  71.  
  72. DynamicFunctionList *
  73. dynamic_file_load(err, filename, start_address, size)
  74. char **err;
  75. char *filename;
  76. char **start_address;
  77. int *size;
  78.  
  79. {
  80.     int fd;
  81.     int n;
  82.     int a_strsize;
  83.     char *ptr;
  84.     char *p_start;
  85.     char *p_text;
  86.     char *p_data;
  87.     char *p_bss;
  88.     char *p_jmptab;
  89.     char *p_syms;
  90.     char *p_treloc;
  91.     char *p_dreloc;
  92.     char *p_breloc;
  93.     char *p_strs;
  94.     char *p_end;
  95.     DynamicFunctionList *retval, *load_symbols();
  96.  
  97.     bzero(&hdr, sizeof(hdr));
  98.  
  99.     fd = open(filename, O_RDONLY, 0);
  100.     if (fd < 0) {
  101.     *err = "unable to open file";
  102.     return(NULL);
  103.     }
  104.     n = read(fd, &hdr.ex, sizeof(hdr.ex));
  105.     if (n != sizeof(hdr.ex) /*|| N_BADMAG(hdr)*/) {
  106.     *err = "bad object header";
  107.     close(fd);
  108.     return(NULL);
  109.     }
  110.     if (hdr.a_nscns > 3) {
  111.     *err = "expected 3 sections in object hdr";
  112.     close(fd);
  113.     return(NULL);
  114.     }
  115.     read(fd, &hdr.txt, hdr.a_nscns * sizeof(hdr.txt));
  116.     lseek(fd, hdr.a_symptr, 0);
  117.     n = read(fd, &shdr, sizeof(shdr));
  118.     if (n != sizeof(shdr)) {
  119.     *err = "bad sym hdr";
  120.     close(fd);
  121.     return(NULL);
  122.     }
  123.  
  124.     /*
  125.      *  BRK enough for:
  126.      *        a_text
  127.      *        a_data
  128.      *        a_bss
  129.      *        a_syms
  130.      *        a_trsize
  131.      *        a_drsize
  132.      *        and string table
  133.      *
  134.      *  When through relocating, BRK to remove a_syms, a_trsize, a_drsize
  135.      *  NOTE THAT NO CALLS THAT USE MALLOC() MAY BE MADE AFTER THE SBRK!
  136.      */
  137.  
  138.     p_start = ptr = Align(sbrk(0));
  139.     p_text  = ptr;        ptr = p_text + hdr.txt.s_size;
  140.     p_data  = ptr;        ptr = p_data + hdr.dat.s_size;
  141.     p_bss   = ptr;        ptr = p_bss  + hdr.bss.s_size;
  142.     p_jmptab= ptr;        ptr = p_jmptab+ shdr.iextMax * sizeof(AJMP);
  143.     p_syms  = Align(ptr);   ptr = p_syms + shdr.iextMax * sizeof(EXTR);
  144.     p_treloc= Align(ptr);   ptr = p_treloc + hdr.txt.s_nreloc * sizeof(Reloc);
  145.     p_dreloc= Align(ptr);   ptr = p_dreloc + hdr.dat.s_nreloc * sizeof(Reloc);
  146.     p_breloc= Align(ptr);   ptr = p_breloc + hdr.bss.s_nreloc * sizeof(Reloc);
  147.     p_strs  = Align(ptr);   ptr = p_strs + shdr.issExtMax;
  148.     p_end   = Align(ptr);
  149.  
  150.     AJmp = (AJMP *)p_jmptab;
  151.  
  152.     if (brk(p_end) == -1) {
  153.     *err = "brk() failed";
  154.     close(fd);
  155.     return(NULL);
  156.     }
  157.     n = 0;
  158.     n += seekread("text", fd, hdr.txt.s_scnptr, p_text, hdr.txt.s_size);
  159.     n += seekread("data", fd, hdr.dat.s_scnptr, p_data, hdr.dat.s_size);
  160.     n += seekread("bss ", fd, hdr.bss.s_scnptr, p_bss , hdr.bss.s_size);
  161.     n += seekread("syms", fd, shdr.cbExtOffset, p_syms, shdr.iextMax 
  162.                             * sizeof(EXTR));
  163.     n += seekread("trel", fd, hdr.txt.s_relptr, p_treloc,
  164.                     hdr.txt.s_nreloc * sizeof(Reloc));
  165.     n += seekread("drel", fd, hdr.dat.s_relptr, p_dreloc,
  166.                     hdr.dat.s_nreloc * sizeof(Reloc));
  167.     n += seekread("brel", fd, hdr.bss.s_relptr, p_breloc,
  168.                     hdr.bss.s_nreloc * sizeof(Reloc));
  169.     n += seekread("strs", fd, shdr.cbSsExtOffset, p_strs, shdr.issExtMax);
  170.     close(fd);
  171.  
  172.     if (n) {
  173.     *err = "format-read error";
  174.         if (sbrk(0) != p_end) 
  175.         elog(WARN, "dynamic_load: unexpected malloc");
  176.     else
  177.         brk(p_start);    /* restore allocated memory */
  178.     return(NULL);
  179.     }
  180.  
  181.     /*
  182.      *  relocate
  183.      *
  184.      *  n holds cumulative error
  185.      */
  186.  
  187.     {
  188.     EXTR *syms = (EXTR *)p_syms;
  189.     Reloc *reloc;
  190.     Reloc *relend;
  191.  
  192.     n = 0;
  193.     reloc = (Reloc *)p_treloc;
  194.     relend= reloc + hdr.txt.s_nreloc;
  195.     while (reloc < relend) {
  196.         n += relocate(p_text, reloc, p_syms, p_strs, p_text, p_data, p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
  197.         ++reloc;
  198.     }
  199.  
  200.     reloc = (Reloc *)p_dreloc;
  201.     relend= reloc + hdr.dat.s_nreloc;
  202.     while (reloc < relend) {
  203.         n += relocate(p_data, reloc, p_syms, p_strs, p_text, p_data, p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
  204.         ++reloc;
  205.     }
  206.  
  207.     reloc = (Reloc *)p_breloc;
  208.     relend= reloc + hdr.bss.s_nreloc;
  209.     while (reloc < relend) {
  210.         n += relocate(p_bss, reloc, p_syms, p_strs, p_text, p_data,
  211.                       p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
  212.         ++reloc;
  213.     }
  214.     }
  215.     if (n)
  216.     *err = "relocate error";
  217.  
  218.     if (sbrk(0) != p_end) {
  219.     elog(WARN, "unexpected malloc %08lx %08lx", sbrk(0), p_end);
  220.     } else {
  221.         brk(p_syms);    /* destroy non essential data */
  222.     }
  223.     *start_address = p_start;
  224.     *size = (long) (p_syms - p_start);
  225.  
  226.     retval = load_symbols(filename, p_start);
  227.  
  228.     return(retval);
  229. }
  230.  
  231. relocate(base, reloc, symbase, strs, tbase, dbase, bbase, vtbase, vdbase, vbbase)
  232. char *base;
  233. Reloc *reloc;
  234. EXTR *symbase;
  235. char  *strs;
  236. char  *tbase, *dbase, *bbase;
  237. long  vtbase, vdbase, vbbase;
  238. {
  239.     char *address = tbase + reloc->r_vaddr; /* always rel to tbase */
  240.     char *symname;
  241.     unsigned long value;
  242.     short n_type;
  243.  
  244.     fflush(stdout);
  245. #ifdef DYNAMIC_LOADER_DEBUG
  246.     printf("relocate (tdb) %08lx %08lx %08lx addr %08lx\n",
  247.     tbase, dbase, bbase, address
  248.     );
  249. #endif
  250.  
  251.     if (reloc->r_extern == 0) {
  252.     symname = "<internal>";
  253.     switch(reloc->r_symndx) {
  254.     case R_SN_TEXT:
  255. #ifdef DYNAMIC_LOADER_DEBUG
  256.         puts("local text");
  257. #endif
  258.         value = (long)tbase - vtbase;
  259.         break;
  260.     case R_SN_DATA:
  261. #ifdef DYNAMIC_LOADER_DEBUG
  262.         puts("local data");
  263. #endif
  264.         value = (long)dbase - vdbase;
  265.         break;
  266.     case R_SN_SDATA:
  267. #ifdef DYNAMIC_LOADER_DEBUG
  268.         puts("local sdata ???");
  269. #endif
  270.         value = (long)bbase - vbbase;
  271.         break;
  272.     default:
  273.         elog(WARN, "dynamic_loader: don't understand secton type %d",
  274.         reloc->r_symndx
  275.         );
  276.         break;
  277.     }
  278.     } else {
  279.         EXTR *sym = symbase + reloc->r_symndx;
  280.     symname = strs + sym->asym.iss;
  281.     switch(sym->asym.sc) {
  282.     case scText:
  283. #ifdef DYNAMIC_LOADER_DEBUG
  284.         puts("text symb");
  285. #endif
  286.         value = (long)tbase - vtbase;
  287.         break;
  288.     case scData:
  289. #ifdef DYNAMIC_LOADER_DEBUG
  290.         puts("data symb");
  291. #endif
  292.         value = (long)dbase - vdbase;
  293.         break;
  294.     case scBss:
  295. #ifdef DYNAMIC_LOADER_DEBUG
  296.         puts("bss symb");
  297.         puts("????");
  298. #endif
  299.         value = (long)dbase - vbbase;
  300.         break;
  301.     case scUndefined:
  302. #ifdef DYNAMIC_LOADER_DEBUG
  303.         puts("undef symb");
  304. #endif
  305.         {
  306.         FList *fl = ExtSyms;
  307.         char *str = strs + sym->asym.iss;
  308.         AJMP *aj;
  309. #ifdef DYNAMIC_LOADER_DEBUG
  310.         puts(str);
  311. #endif
  312.  
  313.         while (fl->name) {
  314.                 if (strcmp(fl->name, str) == 0)
  315.                 break;
  316.             if (fl->name[0] == '_' && strcmp(fl->name + 1, str) == 0)
  317.             break;
  318.             ++fl;
  319.         }
  320.         if (fl->name == NULL)
  321.             elog(WARN, "dynamic_loader: Illegal ext. symbol %s", str);
  322.         value = (long)fl->func;
  323. #ifdef DYNAMIC_LOADER_DEBUG
  324.         printf("func addr %08lx\n", value);
  325. #endif
  326.  
  327.         aj =  AJmp + reloc->r_symndx;    /* index into jump table */
  328.                         /* create jt entry     */
  329.         aj->ary[0] = AJMP0 | ((value >> 16) & 0xFFFF);
  330.         aj->ary[1] = AJMP1 | (value & 0xFFFF);
  331.         aj->ary[2] = AJMP2;
  332.         aj->ary[3] = AJMP3;
  333.         value = (long)aj;
  334. #ifdef DYNAMIC_LOADER_DEBUG
  335.         printf("Jmp Tab Addr %08lx\n", value);
  336. #endif
  337.         }
  338.         break;
  339.     default:
  340.         elog(WARN, "dynamic_loader: do'na understand storage class %d",
  341.         sym->asym.sc
  342.         );
  343.         break;
  344.     }
  345.     }
  346.  
  347.     switch(reloc->r_type) {
  348.     case R_REFHALF:    /* 1 16 bit reference */
  349.     case R_REFWORD:    /* 2 32 bit reference */
  350.     elog(WARN, "dynamic_loader: reloc type? %d %s",
  351.         reloc->r_type, symname
  352.     );
  353.     break;
  354.     case R_JMPADDR:    /* 3 26 bit jump ref (rel?)  */
  355.     value &= 0x0FFFFFFF;
  356. #ifdef DYNAMIC_LOADER_DEBUG
  357.     printf("ja %08lx %08lx (%08lx)\n", address, value, *(long *)address);
  358. #endif
  359.     *(long *)address += (value >> 2);    /* long words */
  360. #ifdef DYNAMIC_LOADER_DEBUG
  361.     printf("ja address is: %08lx\n", (*(long *)address & 0x03FFFFFF) << 2);
  362. #endif
  363.     break;
  364.     case R_REFHI:    /* 4 high 16 bits        */
  365. #ifdef DYNAMIC_LOADER_DEBUG
  366.     printf("rhi %08lx %08lx (%s)\n", address, value, value);
  367. #endif
  368.     *(short *)(address) += (value >> 16) & 0xFFFF;
  369.     break;
  370.     case R_REFLO:    /* 5 low 16 bits        */
  371. #ifdef DYNAMIC_LOADER_DEBUG
  372.     printf("rlo %08lx %08lx\n", address, value);
  373. #endif
  374.     *(short *)(address) += value & 0xFFFF;
  375.     break;
  376.     case R_GPREL:    /* 6 global pointer relative data item */
  377.     elog(WARN, "dynamic_loader: must compile -G 0!",
  378.         reloc->r_type, symname
  379.     );
  380.     break;
  381.     case R_LITERAL:    /* 7 global pointer relative literal pool item */
  382.     elog(WARN, "dynamic_loader: reloc type? %d %s",
  383.         reloc->r_type, symname
  384.     );
  385.     break;
  386.     default:
  387.     return(-1);
  388.     }
  389.     return(0);
  390. }
  391.  
  392. seekread(seg, fd, offset, ptr, bytes)
  393. char *seg;
  394. int fd;
  395. int offset, bytes;
  396. unsigned char *ptr;
  397. {
  398.     int n;
  399.  
  400.     n = lseek(fd, offset, 0);
  401.     if (n != offset)
  402.     return(-1);
  403.     n = read(fd, ptr, bytes);
  404.     if (n != bytes)
  405.     return(-1);
  406.     return(0);
  407. }
  408.  
  409. char *
  410. Align(padr)
  411. char *padr;
  412. {
  413.     long adr = ((long)padr + 3) & ~3;
  414.     return((char *)adr);
  415. }
  416.  
  417. /*
  418.  * Cheat massively because I can't figure out how to read the symbol table
  419.  * properly, so use system("nm ...") to do it instead.
  420.  */
  421.  
  422. DynamicFunctionList *
  423. load_symbols(filename, entry_addr)
  424.  
  425. char *filename;
  426. int entry_addr;
  427.  
  428. {
  429.     char command[256];
  430.     char line[128];
  431.     char *tmp_file = "/tmp/PG_DYNSTUFF";
  432.     FILE *fp;
  433.     DynamicFunctionList *head, *scanner;
  434.     int entering = 1, func_addr;
  435.     char funcname[16];
  436.  
  437.     sprintf(command, "/usr/bin/nm %s | grep \' T \' > %s", filename, tmp_file);
  438.  
  439.     if (system(command))
  440.     {
  441.         fprintf(stderr, "system() died\n");
  442.     }
  443.  
  444.     fp = fopen(tmp_file, "r");
  445.  
  446.     while (fgets(line, 127, fp) != NULL)
  447.     {
  448.         sscanf(line, "%lx T %s", &func_addr, funcname);
  449.         if (entering)
  450.         {
  451.             head = (DynamicFunctionList *)
  452.                    malloc(sizeof(DynamicFunctionList));
  453.             scanner = head;
  454.             entering = 0;
  455.         }
  456.         else
  457.         {
  458.             scanner->next = (DynamicFunctionList *)
  459.                             malloc(sizeof(DynamicFunctionList));
  460.             scanner = scanner->next;
  461.         }
  462.  
  463.         strcpy(scanner->funcname, funcname);
  464.         scanner->func = (func_ptr) (func_addr + entry_addr);
  465.         scanner->next = NULL;
  466.     }
  467.     fclose(fp);
  468.  
  469.     unlink(tmp_file);
  470.     return(head);
  471. }
  472.