home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / unexalpha.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  15KB  |  536 lines

  1. /* Unexec for DEC alpha.  schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
  2.  
  3.    Copyright (C) 1994 Free Software Foundation, Inc.
  4.  
  5. This file is part of GNU Emacs.
  6.  
  7. GNU Emacs is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. GNU Emacs is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20. Boston, MA 02111-1307, USA.  */
  21.  
  22.  
  23. #include <config.h>
  24. #include <sys/types.h>
  25. #include <sys/file.h>
  26. #include <sys/stat.h>
  27. #include <sys/mman.h>
  28. #include <stdio.h>
  29. #include <varargs.h>
  30. #if !defined (__NetBSD__) && !defined (__OpenBSD__)
  31. #include <filehdr.h>
  32. #include <aouthdr.h>
  33. #include <scnhdr.h>
  34. #include <syms.h>
  35. #ifndef __linux__
  36. # include <reloc.h>
  37. # include <elf_abi.h>
  38. #endif
  39. #else /* __NetBSD__ or __OpenBSD__ */
  40. /*
  41.  * NetBSD/Alpha does not have 'normal' user-land ECOFF support because
  42.  * there's no desire to support ECOFF as the executable format in the
  43.  * long term.
  44.  */
  45. #include <sys/exec_ecoff.h>
  46.  
  47. /* Structures, constants, etc., that NetBSD defines strangely. */
  48. #define    filehdr        ecoff_filehdr
  49. #define    aouthdr        ecoff_aouthdr
  50. #define    scnhdr        ecoff_scnhdr
  51. #define    HDRR        struct ecoff_symhdr
  52. #define    pHDRR        HDRR *
  53. #define    cbHDRR        sizeof(HDRR)
  54. #ifdef __OpenBSD__
  55. #define    ALPHAMAGIC    ECOFF_MAGIC_NATIVE_ALPHA
  56. #else
  57. #define    ALPHAMAGIC    ECOFF_MAGIC_NETBSD_ALPHA
  58. #endif
  59. #define    ZMAGIC        ECOFF_ZMAGIC
  60.  
  61. /* Misc. constants that NetBSD doesn't define at all. */
  62. #define    ALPHAUMAGIC    0617
  63. #define    _MIPS_NSCNS_MAX    35
  64. #define    STYP_TEXT    0x00000020
  65. #define    STYP_DATA    0x00000040
  66. #define    STYP_BSS    0x00000080
  67. #define    STYP_RDATA    0x00000100
  68. #define    STYP_SDATA    0x00000200
  69. #define    STYP_SBSS    0x00000400
  70. #define    STYP_INIT    0x80000000
  71. #define    _TEXT        ".text"
  72. #define    _DATA        ".data"
  73. #define    _BSS        ".bss"
  74. #define    _INIT        ".init"
  75. #define    _RDATA        ".rdata"
  76. #define    _SDATA        ".sdata"
  77. #define    _SBSS        ".sbss"
  78. #endif /* __NetBSD__ || __OpenBSD__ */
  79.  
  80. static void fatal_unexec ();
  81. static void mark_x ();
  82.  
  83. #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
  84.     errno = EEOF; \
  85.     if (read (_fd, _buffer, _size) != _size) \
  86.       fatal_unexec (_error_message, _error_arg);
  87.  
  88. #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
  89.     if (write (_fd, _buffer, _size) != _size) \
  90.       fatal_unexec (_error_message, _error_arg);
  91.  
  92. #define SEEK(_fd, _position, _error_message, _error_arg) \
  93.     errno = EEOF; \
  94.     if (lseek (_fd, _position, L_SET) != _position) \
  95.       fatal_unexec (_error_message, _error_arg);
  96.  
  97. extern int errno;
  98. extern char *strerror ();
  99.  
  100. void *sbrk ();
  101.  
  102. #define EEOF -1
  103.  
  104. static struct scnhdr *text_section;
  105. static struct scnhdr *rel_dyn_section;
  106. static struct scnhdr *dynstr_section;
  107. static struct scnhdr *dynsym_section;
  108. static struct scnhdr *init_section;
  109. static struct scnhdr *finit_section;
  110. static struct scnhdr *rdata_section;
  111. static struct scnhdr *rconst_section;
  112. static struct scnhdr *data_section;
  113. static struct scnhdr *pdata_section;
  114. static struct scnhdr *xdata_section;
  115. static struct scnhdr *got_section;
  116. static struct scnhdr *lit8_section;
  117. static struct scnhdr *lit4_section;
  118. static struct scnhdr *sdata_section;
  119. static struct scnhdr *sbss_section;
  120. static struct scnhdr *bss_section;
  121.  
  122. static struct scnhdr old_data_scnhdr;
  123.  
  124. static unsigned long Brk;
  125.  
  126. struct headers {
  127.     struct filehdr fhdr;
  128.     struct aouthdr aout;
  129.     struct scnhdr section[_MIPS_NSCNS_MAX];
  130. };
  131.  
  132.  
  133.  
  134. /* Define name of label for entry point for the dumped executable.  */
  135.  
  136. #ifndef DEFAULT_ENTRY_ADDRESS
  137. #define DEFAULT_ENTRY_ADDRESS __start
  138. #endif
  139.  
  140. unexec (new_name, a_name, data_start, bss_start, entry_address)
  141.      char *new_name, *a_name;
  142.      unsigned long data_start, bss_start, entry_address;
  143. {
  144.   int new, old;
  145.   char * oldptr;
  146.   struct headers ohdr, nhdr;
  147.   struct stat stat;
  148.   long pagesize, brk;
  149.   long newsyms, symrel;
  150.   int nread;
  151.   int i;
  152.   long vaddr, scnptr;
  153. #define BUFSIZE 8192
  154.   char buffer[BUFSIZE];
  155.  
  156.   if ((old = open (a_name, O_RDONLY)) < 0)
  157.     fatal_unexec ("opening %s", a_name);
  158.  
  159.   new = creat (new_name, 0666);
  160.   if (new < 0) fatal_unexec ("creating %s", new_name);
  161.  
  162.   if ((fstat (old, &stat) == -1))
  163.     fatal_unexec ("fstat %s", a_name);
  164.  
  165.   oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0);
  166.  
  167.   if (oldptr == (char *)-1)
  168.     fatal_unexec ("mmap %s", a_name);
  169.  
  170.   close (old);
  171.  
  172.   /* This is a copy of the a.out header of the original executable */
  173.  
  174.   ohdr = (*(struct headers *)oldptr);
  175.  
  176.   /* This is where we build the new header from the in-memory copy */
  177.  
  178.   nhdr = *((struct headers *)TEXT_START);
  179.  
  180.   /* First do some consistency checks */
  181.  
  182.   if (nhdr.fhdr.f_magic != ALPHAMAGIC
  183.       && nhdr.fhdr.f_magic != ALPHAUMAGIC)
  184.     {
  185.       fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
  186.            nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC);
  187.       exit (1);
  188.     }
  189.  
  190.   if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
  191.     {
  192.       fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
  193.            nhdr.fhdr.f_opthdr, (int)sizeof (nhdr.aout));
  194.       exit (1);
  195.     }
  196.   if (nhdr.aout.magic != ZMAGIC)
  197.     {
  198.       fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
  199.            nhdr.aout.magic, ZMAGIC);
  200.       exit (1);
  201.     }
  202.  
  203.  
  204.   /* Now check the existence of certain header section and grab
  205.      their addresses. */
  206.  
  207. #define CHECK_SCNHDR(ptr, name, flags)                    \
  208.   ptr = NULL;                                \
  209.   for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++)            \
  210.     if (strncmp (nhdr.section[i].s_name, name, 8) == 0)            \
  211.       {                                    \
  212.     if (nhdr.section[i].s_flags != flags)                \
  213.       fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
  214.            nhdr.section[i].s_flags, flags, name);        \
  215.     ptr = nhdr.section + i;                        \
  216.       }                                    \
  217.  
  218.   CHECK_SCNHDR (text_section,  _TEXT,  STYP_TEXT);
  219.   CHECK_SCNHDR (init_section,  _INIT,  STYP_INIT);
  220. #ifdef _REL_DYN
  221.   CHECK_SCNHDR (rel_dyn_section, _REL_DYN,  STYP_REL_DYN);
  222. #endif /* _REL_DYN */
  223. #ifdef _DYNSYM
  224.   CHECK_SCNHDR (dynsym_section, _DYNSYM,  STYP_DYNSYM);
  225. #endif /* _REL_DYN */
  226. #ifdef _DYNSTR
  227.   CHECK_SCNHDR (dynstr_section, _DYNSTR,  STYP_DYNSTR);
  228. #endif /* _REL_DYN */
  229. #ifdef _FINI
  230.   CHECK_SCNHDR (finit_section, _FINI,  STYP_FINI);
  231. #endif /* _FINI */
  232.   CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
  233. #ifdef _RCONST
  234.   CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST);
  235. #endif
  236. #ifdef _PDATA
  237.   CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
  238. #endif _PDATA
  239. #ifdef _GOT
  240.   CHECK_SCNHDR (got_section,   _GOT,   STYP_GOT);
  241. #endif _GOT
  242.   CHECK_SCNHDR (data_section,  _DATA,  STYP_DATA);
  243. #ifdef _XDATA
  244.   CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
  245. #endif /* _XDATA */
  246. #ifdef _LIT8
  247.   CHECK_SCNHDR (lit8_section,  _LIT8,  STYP_LIT8);
  248.   CHECK_SCNHDR (lit4_section,  _LIT4,  STYP_LIT4);
  249. #endif /* _LIT8 */
  250.   CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
  251.   CHECK_SCNHDR (sbss_section,  _SBSS,  STYP_SBSS);
  252.   CHECK_SCNHDR (bss_section,   _BSS,   STYP_BSS);
  253.  
  254.  
  255.   pagesize = getpagesize ();
  256.   brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
  257.  
  258.   /* Remember the current break */
  259.  
  260.   Brk = brk;
  261.  
  262.   bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
  263.  
  264.   nhdr.aout.dsize = brk - DATA_START;
  265.   nhdr.aout.bsize = 0;
  266.   if (entry_address == 0)
  267.     {
  268.       extern DEFAULT_ENTRY_ADDRESS ();
  269.       nhdr.aout.entry = (unsigned long)DEFAULT_ENTRY_ADDRESS;
  270.     }
  271.   else
  272.     nhdr.aout.entry = entry_address;
  273.  
  274.   nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize;
  275.  
  276.   if (rdata_section != NULL)
  277.     {
  278.       rdata_section->s_size = data_start - DATA_START;
  279.  
  280.       /* Adjust start and virtual addresses of rdata_section, too.  */
  281.       rdata_section->s_vaddr = DATA_START;
  282.       rdata_section->s_paddr = DATA_START;
  283.       rdata_section->s_scnptr = text_section->s_scnptr + nhdr.aout.tsize;
  284.     }
  285.  
  286.   data_section->s_vaddr = data_start;
  287.   data_section->s_paddr = data_start;
  288.   data_section->s_size = brk - data_start;
  289.  
  290.   if (rdata_section != NULL)
  291.     {
  292.       data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
  293.     }
  294.  
  295.   vaddr = data_section->s_vaddr + data_section->s_size;
  296.   scnptr = data_section->s_scnptr + data_section->s_size;
  297.   if (lit8_section != NULL)
  298.     {
  299.       lit8_section->s_vaddr = vaddr;
  300.       lit8_section->s_paddr = vaddr;
  301.       lit8_section->s_size = 0;
  302.       lit8_section->s_scnptr = scnptr;
  303.     }
  304.   if (lit4_section != NULL)
  305.     {
  306.       lit4_section->s_vaddr = vaddr;
  307.       lit4_section->s_paddr = vaddr;
  308.       lit4_section->s_size = 0;
  309.       lit4_section->s_scnptr = scnptr;
  310.     }
  311.   if (sdata_section != NULL)
  312.     {
  313.       sdata_section->s_vaddr = vaddr;
  314.       sdata_section->s_paddr = vaddr;
  315.       sdata_section->s_size = 0;
  316.       sdata_section->s_scnptr = scnptr;
  317.     }
  318. #ifdef _XDATA
  319.   if (xdata_section != NULL)
  320.     {
  321.       xdata_section->s_vaddr = vaddr;
  322.       xdata_section->s_paddr = vaddr;
  323.       xdata_section->s_size = 0;
  324.       xdata_section->s_scnptr = scnptr;
  325.     }
  326. #endif
  327. #ifdef _GOT
  328.   if (got_section != NULL)
  329.     {
  330.       bcopy (got_section, buffer, sizeof (struct scnhdr));
  331.  
  332.       got_section->s_vaddr = vaddr;
  333.       got_section->s_paddr = vaddr;
  334.       got_section->s_size = 0;
  335.       got_section->s_scnptr = scnptr;
  336.     }
  337. #endif /*_GOT */
  338.   if (sbss_section != NULL)
  339.     {
  340.       sbss_section->s_vaddr = vaddr;
  341.       sbss_section->s_paddr = vaddr;
  342.       sbss_section->s_size = 0;
  343.       sbss_section->s_scnptr = scnptr;
  344.     }
  345.   if (bss_section != NULL)
  346.     {
  347.       bss_section->s_vaddr = vaddr;
  348.       bss_section->s_paddr = vaddr;
  349.       bss_section->s_size = 0;
  350.       bss_section->s_scnptr = scnptr;
  351.     }
  352.  
  353.   WRITE (new, (char *)TEXT_START, nhdr.aout.tsize,
  354.      "writing text section to %s", new_name);
  355.   WRITE (new, (char *)DATA_START, nhdr.aout.dsize,
  356.      "writing data section to %s", new_name);
  357.  
  358. #ifdef _GOT
  359. #define old_got_section ((struct scnhdr *)buffer)
  360.  
  361.   if (got_section != NULL)
  362.     {
  363.       SEEK (new, old_got_section->s_scnptr,
  364.         "seeking to start of got_section in %s", new_name);
  365.       WRITE (new, oldptr + old_got_section->s_scnptr, old_got_section->s_size,
  366.          "writing new got_section of %s", new_name);
  367.       SEEK (new, nhdr.aout.tsize + nhdr.aout.dsize,
  368.         "seeking to end of data section of %s", new_name);
  369.     }
  370.  
  371. #undef old_got_section
  372. #endif
  373.  
  374.   /*
  375.    * Construct new symbol table header
  376.    */
  377.  
  378.   bcopy (oldptr + nhdr.fhdr.f_symptr, buffer, cbHDRR);
  379.  
  380. #define symhdr ((pHDRR)buffer)
  381.   newsyms = nhdr.aout.tsize + nhdr.aout.dsize;
  382.   symrel = newsyms - nhdr.fhdr.f_symptr;
  383.   nhdr.fhdr.f_symptr = newsyms;
  384.   symhdr->cbLineOffset += symrel;
  385.   symhdr->cbDnOffset += symrel;
  386.   symhdr->cbPdOffset += symrel;
  387.   symhdr->cbSymOffset += symrel;
  388.   symhdr->cbOptOffset += symrel;
  389.   symhdr->cbAuxOffset += symrel;
  390.   symhdr->cbSsOffset += symrel;
  391.   symhdr->cbSsExtOffset += symrel;
  392.   symhdr->cbFdOffset += symrel;
  393.   symhdr->cbRfdOffset += symrel;
  394.   symhdr->cbExtOffset += symrel;
  395.  
  396.   WRITE (new, buffer, cbHDRR, "writing symbol table header of %s", new_name);
  397.  
  398.   /*
  399.    * Copy the symbol table and line numbers
  400.    */
  401.   WRITE (new, oldptr + ohdr.fhdr.f_symptr + cbHDRR,
  402.      stat.st_size - ohdr.fhdr.f_symptr - cbHDRR,
  403.      "writing symbol table of %s", new_name);
  404.  
  405. #ifdef _REL_DYN
  406.   if (rel_dyn_section)
  407.     update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
  408. #endif
  409.  
  410. #undef symhdr
  411.  
  412.   SEEK (new, 0, "seeking to start of header in %s", new_name);
  413.   WRITE (new, &nhdr, sizeof (nhdr),
  414.      "writing header of %s", new_name);
  415.  
  416.   close (old);
  417.   close (new);
  418.   mark_x (new_name);
  419. }
  420.  
  421.  
  422.  
  423. update_dynamic_symbols (old, new_name, new, aout)
  424.      char *old;            /* Pointer to old executable */
  425.      char *new_name;            /* Name of new executable */
  426.      int new;            /* File descriptor for new executable */
  427.      struct aouthdr aout;    /* a.out info from the file header */
  428. {
  429. #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
  430.  
  431.   typedef struct dynrel_info {
  432.     char * addr;
  433.     unsigned type:8;
  434.     unsigned index:24;
  435.     unsigned info:8;
  436.     unsigned pad:8;
  437.   } dr_info;
  438.  
  439.   int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info);
  440.   int i;
  441.   dr_info * rd_base = (dr_info *) (old + rel_dyn_section->s_scnptr);
  442.   Elf32_Sym * ds_base = (Elf32_Sym *) (old + dynsym_section->s_scnptr);
  443.  
  444.   for (i = 0; i < nsyms; i++) {
  445.     register Elf32_Sym x;
  446.  
  447.     if (rd_base[i].index == 0)
  448.       continue;
  449.  
  450.     x = ds_base[rd_base[i].index];
  451.  
  452. #if 0
  453.       fprintf (stderr, "Object inspected: %s, addr = %lx, shndx = %x",
  454.            old + dynstr_section->s_scnptr + x.st_name, rd_base[i].addr, x.st_shndx);
  455. #endif
  456.  
  457.  
  458.     if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL)
  459.     && (x.st_shndx == 0)
  460.     /* && (x.st_value == NULL) */
  461.     ) {
  462.       /* OK, this is probably a reference to an object in a shared
  463.      library, so copy the old value. This is done in several steps:
  464.      1. reladdr is the address of the location in question relative to
  465.             the start of the data section,
  466.          2. oldref is the addr is the mapped in temacs executable,
  467.          3. newref is the address of the location in question in the
  468.             undumped executable,
  469.          4. len is the size of the object reference in bytes --
  470.             currently only 4 (long) and 8 (quad) are supported.
  471.         */
  472.       register unsigned long reladdr = (long)rd_base[i].addr - old_data_scnhdr.s_vaddr;
  473.       char * oldref = old + old_data_scnhdr.s_scnptr + reladdr;
  474.       unsigned long newref = aout.tsize + reladdr;
  475.       int len;
  476.  
  477. #if 0
  478.       fprintf (stderr, "...relocated\n");
  479. #endif
  480.  
  481.       if (rd_base[i].type == R_REFLONG) 
  482.     len = 4;
  483.       else if (rd_base[i].type == R_REFQUAD) 
  484.     len = 8;
  485.       else
  486.     fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", i);
  487.  
  488.       SEEK (new, newref, "seeking to dynamic symbol in %s", new_name);
  489.       WRITE (new, oldref, len, "writing old dynrel info in %s", new_name);
  490.     }
  491.  
  492. #if 0
  493.     else
  494.       fprintf (stderr, "...not relocated\n");
  495. #endif
  496.  
  497.   }
  498.  
  499. #endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
  500. }
  501.  
  502.  
  503. /*
  504.  * mark_x
  505.  *
  506.  * After successfully building the new a.out, mark it executable
  507.  */
  508.  
  509. static void
  510. mark_x (name)
  511.      char *name;
  512. {
  513.   struct stat sbuf;
  514.   int um = umask (777);
  515.   umask (um);
  516.   if (stat (name, &sbuf) < 0)
  517.     fatal_unexec ("getting protection on %s", name);
  518.   sbuf.st_mode |= 0111 & ~um;
  519.   if (chmod (name, sbuf.st_mode) < 0)
  520.     fatal_unexec ("setting protection on %s", name);
  521. }
  522.  
  523. static void
  524. fatal_unexec (s, arg)
  525.      char *s;
  526.      char *arg;
  527. {
  528.   if (errno == EEOF)
  529.     fputs ("unexec: unexpected end of file, ", stderr);
  530.   else
  531.     fprintf (stderr, "unexec: %s, ", strerror (errno));
  532.   fprintf (stderr, s, arg);
  533.   fputs (".\n", stderr);
  534.   exit (1);
  535. }
  536.