home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / emacs-19.28-src.tgz / tar.out / fsf / emacs / src / unexsunos4.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  11KB  |  376 lines

  1. /* Unexec for Sunos 4 using shared libraries.
  2.    Copyright (C) 1990, 1994 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU Emacs is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* Contributed by Viktor Dukhovni.  */
  21. /*
  22.  * Unexec for Berkeley a.out format + SUNOS shared libraries
  23.  * The unexeced executable contains the __DYNAMIC area from the
  24.  * original text file,  and then the rest of data + bss + malloced area of
  25.  * the current process.  (The __DYNAMIC area is at the top of the process
  26.  * data segment,  we use "data_start" defined externally to mark the start
  27.  * of the "real" data segment.)
  28.  *
  29.  * For programs that want to remap some of the data segment read only
  30.  * a run_time_remap is provided.  This attempts to remap largest area starting
  31.  * and ending on page boundaries between "data_start" and "bndry"
  32.  * For this it to figure out where the text file is located.  A path search
  33.  * is attempted after trying argv[0] and if all fails we simply do not remap
  34.  *
  35.  * One feature of run_time_remap () is mandatory:  reseting the break.
  36.  *
  37.  *  Note that we can no longer map data into the text segment,  as this causes
  38.  *  the __DYNAMIC struct to become read only,  breaking the runtime loader.
  39.  *  Thus we no longer need to mess with a private crt0.c,  the standard one
  40.  *  will do just fine,  since environ can live in the writable area between
  41.  *  __DYNAMIC and data_start,  just make sure that pre-crt0.o (the name
  42.  *  is somewhat abused here) is loaded first!
  43.  *
  44.  */
  45. #include <sys/param.h>
  46. #include <sys/mman.h>
  47. #include <sys/file.h>
  48. #include <sys/stat.h>
  49. #include <string.h>
  50. #include <stdio.h>
  51. #include <a.out.h>
  52.  
  53. /* Do this after the above #include's in case a configuration file wants
  54.    to define things for this file based on what <a.out.h> defines.  */
  55. #ifdef emacs
  56. #include <config.h>
  57. #endif
  58.  
  59. #if defined (SUNOS4) || defined (__FreeBSD__)
  60. #define UNDO_RELOCATION
  61. #endif
  62.  
  63. #ifdef UNDO_RELOCATION
  64. #include <link.h>
  65. #endif
  66.  
  67. #ifdef HAVE_UNISTD_H
  68. #include <unistd.h>
  69. #endif
  70.  
  71. /* NetBSD needs this bit, but SunOS does not have it.  */
  72. #ifndef MAP_FILE
  73. #define MAP_FILE 0
  74. #endif
  75.  
  76.  
  77. /*
  78.  * for programs other than emacs
  79.  * define data_start + initialized here,  and make sure
  80.  * this object is loaded first!
  81.  * emacs will define these elsewhere,  and load the object containing
  82.  * data_start (pre-crt0.o or firstfile.o?) first!
  83.  * The custom crt0.o *must not* be loaded!
  84.  */
  85. #ifndef emacs
  86.   static int data_start = 0;
  87.   static int initialized = 0;
  88. #else
  89.   extern int initialized;
  90.   extern unsigned data_start;
  91.   extern int pureptr;
  92. #endif
  93.  
  94. extern char *getenv ();
  95. static unsigned Brk;
  96. static struct exec nhdr;
  97. static int rd_only_len;
  98. static long cookie;
  99.  
  100.  
  101. unexec (new_name, a_name, bndry, bss_start, entry) 
  102.      char *new_name, *a_name;
  103.      unsigned bndry, bss_start, entry;
  104. {
  105.   int fd, new;
  106.   char *old;
  107.   struct exec ohdr;        /* Allocate on the stack,  not needed in the next life */
  108.   struct stat stat;
  109.  
  110. #ifdef emacs
  111.   fprintf (stderr, "Used %d bytes of Pure Storage\n", pureptr);
  112. #endif
  113.  
  114.   if ((fd = open (a_name, O_RDONLY)) < 0)
  115.     {
  116.       fprintf (stderr, "%s: open: ", a_name);
  117.       perror (a_name);
  118.       exit (1);
  119.     }
  120.   if ((new = open (new_name, O_WRONLY | O_CREAT, 0666)) == -1)
  121.     {
  122.       fprintf (stderr, "%s: open: ", a_name);
  123.       perror (new_name);
  124.       exit (1);
  125.     }
  126.  
  127.   if ((fstat (fd, &stat) == -1))
  128.     {
  129.       fprintf (stderr, "%s: ", a_name);
  130.       perror ("fstat");
  131.       exit (1);
  132.     }
  133.  
  134.   old = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0);
  135.   if (old == (char *)-1)
  136.     {
  137.       fprintf (stderr, "%s: ", a_name);
  138.       perror ("mmap");
  139.       exit (1);
  140.     }
  141.   close (fd);
  142.  
  143.   nhdr = ohdr = (*(struct exec *)old);
  144.  
  145.  
  146.   /*
  147.    * Remember a magic cookie so we know we've got the right binary
  148.    * when remapping.
  149.    */
  150.   cookie = time (0);
  151.  
  152.   Brk = sbrk (0);        /* Save the break, it is reset to &_end (by ld.so?) */
  153.  
  154.   /*
  155.    * Round up data start to a page boundary (Lose if not a 2 power!)
  156.    */
  157.   data_start = ((((int)&data_start) - 1) & ~(N_PAGSIZ (nhdr) - 1)) + N_PAGSIZ (nhdr);
  158.  
  159.   /*
  160.    * Round down read only pages to a multiple of the page size
  161.    */
  162.   if (bndry)
  163.     rd_only_len = ((int)bndry & ~(N_PAGSIZ (nhdr) - 1)) - data_start;
  164.  
  165. #ifndef emacs
  166.   /* Have to do this some time before dumping the data */
  167.   initialized = 1;
  168. #endif
  169.   
  170.   /* 
  171.    * Handle new data and bss sizes and optional new entry point.
  172.    * No one actually uses bss_start and entry,  but tradition compels
  173.    * one to support them.
  174.    * Could complain if bss_start > Brk,  but the caller is *supposed* to know
  175.    * what she is doing.
  176.    */
  177.   nhdr.a_data = (bss_start ? bss_start : Brk) - N_DATADDR (nhdr);
  178.   nhdr.a_bss  = bss_start ? Brk - bss_start : 0;
  179.   if (entry) 
  180.     nhdr.a_entry = entry;
  181.  
  182.   /*
  183.    * Write out the text segment with new header
  184.    * Dynamic executables are ZMAGIC with N_TXTOFF==0 and the header
  185.    * part of the text segment, but no need to rely on this.
  186.    * So write the TEXT first,  then go back replace the header.
  187.    * Doing it in the other order is less general!
  188.    */
  189.   lseek (new, N_TXTOFF (nhdr), L_SET);
  190.   write (new, old + N_TXTOFF (ohdr), N_TXTOFF (ohdr) + ohdr.a_text);
  191.   lseek (new, 0L, L_SET);
  192.   write (new, &nhdr, sizeof (nhdr));
  193.  
  194.   /*
  195.    * Write out the head of the old data segment from the file not
  196.    * from core, this has the unresolved __DYNAMIC relocation data
  197.    * we need to reload
  198.    */
  199.   lseek (new, N_DATOFF (nhdr), L_SET);
  200.   write (new, old + N_DATOFF (ohdr), (int)&data_start - N_DATADDR (ohdr));
  201.  
  202.   /*
  203.    * Copy the rest of the data from core
  204.    */
  205.   write (new, &data_start, N_BSSADDR (nhdr) - (int)&data_start);
  206.  
  207.   /*
  208.    * Copy the symbol table and line numbers
  209.    */
  210.   lseek (new, N_TRELOFF (nhdr), L_SET);
  211.   write (new, old + N_TRELOFF (ohdr), stat.st_size - N_TRELOFF (ohdr));
  212.  
  213.   /* Some other BSD systems use this file.
  214.      We don't know whether this change is right for them.  */
  215. #ifdef UNDO_RELOCATION
  216.   /* Undo the relocations done at startup by ld.so.
  217.      It will do these relocations again when we start the dumped Emacs.
  218.      Doing them twice gives incorrect results.  */
  219.   {
  220.     unsigned long daddr = N_DATADDR (ohdr);
  221.     unsigned long rel, erel;
  222. #ifdef SUNOS4
  223.     extern struct link_dynamic _DYNAMIC;
  224.  
  225.     /*  SunOS4.x's ld_rel is relative to N_TXTADDR. */
  226.     if (_DYNAMIC.ld_version < 2)
  227.       {
  228.     rel = _DYNAMIC.ld_un.ld_1->ld_rel + N_TXTADDR (ohdr);
  229.     erel = _DYNAMIC.ld_un.ld_1->ld_hash + N_TXTADDR (ohdr);
  230.       }
  231.     else
  232.       {
  233.     rel = _DYNAMIC.ld_un.ld_2->ld_rel + N_TXTADDR (ohdr);
  234.     erel = _DYNAMIC.ld_un.ld_2->ld_hash + N_TXTADDR (ohdr);
  235.       }
  236. #ifdef sparc
  237. #define REL_INFO_TYPE        struct reloc_info_sparc
  238. #else
  239. #define REL_INFO_TYPE        struct reloc_info_m68k
  240. #endif /* sparc */
  241. #define REL_TARGET_ADDRESS(r)    (((REL_INFO_TYPE *)(r))->r_address)
  242. #endif /* SUNOS4 */
  243. #ifdef __FreeBSD__
  244.     extern struct _dynamic _DYNAMIC;
  245.  
  246.     /*  FreeBSD's LD_REL is a virtual address itself. */
  247.     rel = LD_REL (&_DYNAMIC);
  248.     erel = rel + LD_RELSZ (&_DYNAMIC);
  249. #define REL_INFO_TYPE        struct relocation_info
  250. #define REL_TARGET_ADDRESS(r)    (((REL_INFO_TYPE *)(r))->r_address)
  251. #endif
  252.  
  253.     for (; rel < erel; rel += sizeof (REL_INFO_TYPE))
  254.       {
  255.     /*  This is the virtual address where ld.so will do relocation.  */
  256.     unsigned long target = REL_TARGET_ADDRESS (rel);
  257.     /*  This is the offset in the data segment.  */
  258.     unsigned long segoffset = target - daddr;
  259.  
  260.     /*  If it is located below data_start, we have to do nothing here,
  261.         because the old data has been already written to the location. */
  262.     if (target < (unsigned long)&data_start)
  263.         continue;
  264.  
  265.     lseek (new, N_DATOFF (nhdr) + segoffset, L_SET);
  266.     write (new, old + N_DATOFF (ohdr) + segoffset, sizeof (unsigned long));
  267.       }
  268.   }
  269. #endif /* UNDO_RELOCATION */
  270.  
  271.   fchmod (new, 0755);
  272. }
  273.  
  274. void
  275. run_time_remap (progname)
  276.      char *progname;
  277. {
  278.   char aout[MAXPATHLEN];
  279.   register char *path, *p;
  280.  
  281.   /* Just in case */
  282.   if (!initialized)
  283.     return;
  284.  
  285.   /* Restore the break */
  286.   brk (Brk);
  287.  
  288.   /*  If nothing to remap:  we are done! */
  289.   if (rd_only_len == 0)
  290.     return;
  291.  
  292.   /*
  293.    * Attempt to find the executable
  294.    * First try argv[0],  will almost always succeed as shells tend to give
  295.    * the full path from the hash list rather than using execvp ()
  296.    */
  297.   if (is_it (progname)) 
  298.     return;
  299.  
  300.   /*
  301.    * If argv[0] is a full path and does not exist,  not much sense in
  302.    * searching further
  303.    */
  304.   if (strchr (progname, '/')) 
  305.     return;
  306.  
  307.   /*
  308.    * Try to search for  argv[0] on the PATH
  309.    */
  310.   path = getenv ("PATH");
  311.   if (path == NULL)
  312.     return;
  313.  
  314.   while (*path)
  315.     {
  316.       /* copy through ':' or end */
  317.       for (p = aout; *p = *path; ++p, ++path)
  318.     if (*p == ':')
  319.       {
  320.         ++path;        /* move past ':' */
  321.         break;
  322.       }
  323.       *p++ = '/';
  324.       strcpy (p, progname);
  325.       /*
  326.        * aout is a candidate full path name
  327.        */
  328.       if (is_it (aout))
  329.     return;
  330.     }
  331. }
  332.  
  333. is_it (filename)
  334.   char *filename;
  335. {
  336.   int fd;
  337.   long filenames_cookie;
  338.   struct exec hdr;
  339.  
  340.   /*
  341.    * Open an executable  and check for a valid header!
  342.    * Can't bcmp the header with what we had,  it may have been stripped!
  343.    * so we may save looking at non executables with the same name, mostly
  344.    * directories.
  345.    */
  346.   fd = open (filename, O_RDONLY);
  347.   if (fd != -1)
  348.     {
  349.       if (read (fd, &hdr, sizeof (hdr)) == sizeof (hdr)
  350.       && !N_BADMAG (hdr) && N_DATOFF (hdr) == N_DATOFF (nhdr)
  351.       && N_TRELOFF (hdr) == N_TRELOFF (nhdr))
  352.     {
  353.       /* compare cookies */
  354.       lseek (fd, N_DATOFF (hdr) + (int)&cookie - N_DATADDR (hdr), L_SET);
  355.       read (fd, &filenames_cookie, sizeof (filenames_cookie));
  356.       if (filenames_cookie == cookie)
  357.         {            /* Eureka */
  358.  
  359.           /*
  360.            * Do the mapping
  361.            * The PROT_EXEC may not be needed,  but it is safer this way.
  362.            * should the shared library decide to indirect through
  363.            * addresses in the data segment not part of __DYNAMIC
  364.            */
  365.           mmap (data_start, rd_only_len, PROT_READ | PROT_EXEC,
  366.             MAP_FILE | MAP_SHARED | MAP_FIXED, fd,
  367.             N_DATOFF (hdr) + data_start - N_DATADDR (hdr));
  368.           close (fd);
  369.           return 1;
  370.         }
  371.     }
  372.       close (fd);
  373.     }
  374.   return 0;
  375. }
  376.