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