⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unexec.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 1, or (at your option)    any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.In other words, you are welcome to use, share and improve this program.You are forbidden to forbid anyone else to use, share and improvewhat you give them.   Help stamp out software-hoarding!  *//* * unexec.c - Convert a running program into an a.out file. * * Author:	Spencer W. Thomas * 		Computer Science Dept. * 		University of Utah * Date:	Tue Mar  2 1982 * Modified heavily since then. * * Synopsis: *	unexec (new_name, a_name, data_start, bss_start, entry_address) *	char *new_name, *a_name; *	unsigned data_start, bss_start, entry_address; * * Takes a snapshot of the program and makes an a.out format file in the * file named by the string argument new_name. * If a_name is non-NULL, the symbol table will be taken from the given file. * On some machines, an existing a_name file is required. * * The boundaries within the a.out file may be adjusted with the data_start * and bss_start arguments.  Either or both may be given as 0 for defaults. * * Data_start gives the boundary between the text segment and the data * segment of the program.  The text segment can contain shared, read-only * program code and literal data, while the data segment is always unshared * and unprotected.  Data_start gives the lowest unprotected address. * The value you specify may be rounded down to a suitable boundary * as required by the machine you are using. * * Specifying zero for data_start means the boundary between text and data * should not be the same as when the program was loaded. * If NO_REMAP is defined, the argument data_start is ignored and the * segment boundaries are never changed. * * Bss_start indicates how much of the data segment is to be saved in the * a.out file and restored when the program is executed.  It gives the lowest * unsaved address, and is rounded up to a page boundary.  The default when 0 * is given assumes that the entire data segment is to be stored, including * the previous data and bss as well as any additional storage allocated with * break (2). * * The new file is set up to start at entry_address. * * If you make improvements I'd like to get them too. * harpo!utah-cs!thomas, thomas@Utah-20 * *//* Modified to support SysVr3 shared libraries by James Van Artsdalen * of Dell Computer Corporation.  james@bigtex.cactus.org. *//* There are several compilation parameters affecting unexec:* COFFDefine this if your system uses COFF for executables.Otherwise we assume you use Berkeley format.* NO_REMAPDefine this if you do not want to try to save Emacs's pure data areasas part of the text segment.Saving them as text is good because it allows users to share more.However, on machines that locate the text area far from the data area,the boundary cannot feasibly be moved.  Such machines requireNO_REMAP.Also, remapping can cause trouble with the built-in startup routine/lib/crt0.o, which defines `environ' as an initialized variable.Dumping `environ' as pure does not work!  So, to use remapping,you must write a startup routine for your machine in Emacs's crt0.c.If NO_REMAP is defined, Emacs uses the system's crt0.o.* SECTION_ALIGNMENTSome machines that use COFF executables require that each sectionstart on a certain boundary *in the COFF file*.  Such machines shoulddefine SECTION_ALIGNMENT to a mask of the low-order bits that must bezero on such a boundary.  This mask is used to control padding betweensegments in the COFF file.If SECTION_ALIGNMENT is not defined, the segments are writtenconsecutively with no attempt at alignment.  This is right forunmodified system V.* SEGMENT_MASKSome machines require that the beginnings and ends of segments*in core* be on certain boundaries.  For most machines, a pageboundary is sufficient.  That is the default.  When a largerboundary is needed, define SEGMENT_MASK to a mask ofthe bits that must be zero on such a boundary.* A_TEXT_OFFSET(HDR)Some machines count the a.out header as part of the size of the textsegment (a_text); they may actually load the header into core as thefirst data in the text segment.  Some have additional padding betweenthe header and the real text of the program that is counted in a_text.For these machines, define A_TEXT_OFFSET(HDR) to examine the headerstructure HDR and return the number of bytes to add to `a_text'before writing it (above and beyond the number of bytes of actualprogram text).  HDR's standard fields are already correct, except thatthis adjustment to the `a_text' field has not yet been made;thus, the amount of offset can depend on the data in the file.  * A_TEXT_SEEK(HDR)If defined, this macro specifies the number of bytes to seek into thea.out file before starting to write the text segment.a* EXEC_MAGICFor machines using COFF, this macro, if defined, is a value storedinto the magic number field of the output file.* ADJUST_EXEC_HEADERThis macro can be used to generate statements to adjust orinitialize nonstandard fields in the file header* ADDR_CORRECT(ADDR)Macro to correct an int which is the bit pattern of a pointer to a byteinto an int which is the number of a byte.This macro has a default definition which is usually right.This default definition is a no-op on most machines (where apointer looks like an int) but not on all machines.*/#ifndef emacs#define PERROR(arg) perror (arg); return -1#else#include "config.h"#define PERROR(file) report_error (file, new)#endif#ifndef CANNOT_DUMP  /* all rest of file!  */#ifndef CANNOT_UNEXEC /* most of rest of file */#include <a.out.h>/* Define getpagesize () if the system does not.   Note that this may depend on symbols defined in a.out.h */#include "getpagesize.h"#ifndef makedev			/* Try to detect types.h already loaded */#include <sys/types.h>#endif#include <stdio.h>#include <sys/stat.h>#include <errno.h>extern char *start_of_text ();		/* Start of text */extern char *start_of_data ();		/* Start of initialized data */#ifdef COFF#ifndef USG#ifndef STRIDE#ifndef UMAX#ifndef sun386/* I have a suspicion that these are turned off on all systems   and can be deleted.  Try it in version 19.  */#include <filehdr.h>#include <aouthdr.h>#include <scnhdr.h>#include <syms.h>#endif /* not sun386 */#endif /* not UMAX */#endif /* Not STRIDE */#endif /* not USG */static long block_copy_start;		/* Old executable start point */static struct filehdr f_hdr;		/* File header */static struct aouthdr f_ohdr;		/* Optional file header (a.out) */long bias;			/* Bias to add for growth */long lnnoptr;			/* Pointer to line-number info within file */#define SYMS_START block_copy_startstatic long text_scnptr;static long data_scnptr;#else /* not COFF */extern char *sbrk ();#define SYMS_START ((long) N_SYMOFF (ohdr))/* Some machines override the structure name for an a.out header.  */#ifndef EXEC_HDR_TYPE#define EXEC_HDR_TYPE struct exec#endif#ifdef HPUX#ifdef HP9000S200_ID#define MY_ID HP9000S200_ID#else#include <model.h>#define MY_ID MYSYS#endif /* no HP9000S200_ID */static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC};static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC};#define N_TXTOFF(x) TEXT_OFFSET(x)#define N_SYMOFF(x) LESYM_OFFSET(x)static EXEC_HDR_TYPE hdr, ohdr;#else /* not HPUX */#if defined (USG) && !defined (IBMRTAIX) && !defined (IRIS)static struct bhdr hdr, ohdr;#define a_magic fmagic#define a_text tsize#define a_data dsize#define a_bss bsize#define a_syms ssize#define a_trsize rtsize#define a_drsize rdsize#define a_entry entry#define	N_BADMAG(x) \    (((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\     ((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC)#define NEWMAGIC FMAGIC#else /* IRIS or IBMRTAIX or not USG */static EXEC_HDR_TYPE hdr, ohdr;#define NEWMAGIC ZMAGIC#endif /* IRIS or IBMRTAIX not USG */#endif /* not HPUX */static int unexec_text_start;static int unexec_data_start;#endif /* not COFF */static int pagemask;/* Correct an int which is the bit pattern of a pointer to a byte   into an int which is the number of a byte.   This is a no-op on ordinary machines, but not on all.  */#ifndef ADDR_CORRECT   /* Let m-*.h files override this definition */#define ADDR_CORRECT(x) ((char *)(x) - (char*)0)#endif#ifdef emacsstaticreport_error (file, fd)     char *file;     int fd;{  if (fd)    close (fd);  error ("Failure operating on %s", file);}#endif /* emacs */#define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1#define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1staticreport_error_1 (fd, msg, a1, a2)     int fd;     char *msg;     int a1, a2;{  close (fd);#ifdef emacs  error (msg, a1, a2);#else  fprintf (stderr, msg, a1, a2);  fprintf (stderr, "\n");#endif}/* **************************************************************** * unexec * * driving logic. */unexec (new_name, a_name, data_start, bss_start, entry_address)     char *new_name, *a_name;     unsigned data_start, bss_start, entry_address;{  int new, a_out = -1;  if (a_name && (a_out = open (a_name, 0)) < 0)    {      PERROR (a_name);    }  if ((new = creat (new_name, 0666)) < 0)    {      PERROR (new_name);    }  if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0      || copy_text_and_data (new, a_out) < 0      || copy_sym (new, a_out, a_name, new_name) < 0#ifdef COFF      || adjust_lnnoptrs (new, a_out, new_name) < 0#endif      )    {      close (new);      /* unlink (new_name);	    	/* Failed, unlink new a.out */      return -1;	    }  close (new);  if (a_out >= 0)    close (a_out);  mark_x (new_name);  return 0;}/* **************************************************************** * make_hdr * * Make the header in the new a.out from the header in core. * Modify the text and data sizes. */static intmake_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)     int new, a_out;     unsigned data_start, bss_start, entry_address;     char *a_name;     char *new_name;{  int tem;#ifdef COFF  auto struct scnhdr f_thdr;		/* Text section header */  auto struct scnhdr f_dhdr;		/* Data section header */  auto struct scnhdr f_bhdr;		/* Bss section header */  auto struct scnhdr scntemp;		/* Temporary section header */  register int scns;#endif /* COFF */#ifdef USG_SHARED_LIBRARIES  extern unsigned int bss_end;#else  unsigned int bss_end;#endif  pagemask = getpagesize () - 1;  /* Adjust text/data boundary. */#ifdef NO_REMAP  data_start = (int) start_of_data ();#else /* not NO_REMAP */  if (!data_start)    data_start = (int) start_of_data ();#endif /* not NO_REMAP */  data_start = ADDR_CORRECT (data_start);#ifdef SEGMENT_MASK  data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */#else  data_start = data_start & ~pagemask; /* (Down) to page boundary. */#endif  bss_end = ADDR_CORRECT (sbrk (0)) + pagemask;  bss_end &= ~ pagemask;  /* Adjust data/bss boundary. */  if (bss_start != 0)    {      bss_start = (ADDR_CORRECT (bss_start) + pagemask);      /* (Up) to page bdry. */      bss_start &= ~ pagemask;      if (bss_start > bss_end)	{	  ERROR1 ("unexec: Specified bss_start (%u) is past end of program",		  bss_start);	}    }  else    bss_start = bss_end;  if (data_start > bss_start)	/* Can't have negative data size. */    {      ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",	      data_start, bss_start);    }#ifdef COFF  /* Salvage as much info from the existing file as possible */  if (a_out >= 0)    {      if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))	{	  PERROR (a_name);	}      block_copy_start += sizeof (f_hdr);      if (f_hdr.f_opthdr > 0)	{	  if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))	    {	      PERROR (a_name);	    }	  block_copy_start += sizeof (f_ohdr);	}      /* Loop through section headers, copying them in */      for (scns = f_hdr.f_nscns; scns > 0; scns--) {	if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))	  {	    PERROR (a_name);	  }	if (scntemp.s_scnptr > 0L)	  {            if (block_copy_start < scntemp.s_scnptr + scntemp.s_size)	      block_copy_start = scntemp.s_scnptr + scntemp.s_size;	  }	if (strcmp (scntemp.s_name, ".text") == 0)	  {	    f_thdr = scntemp;	  }	else if (strcmp (scntemp.s_name, ".data") == 0)	  {	    f_dhdr = scntemp;	  }	else if (strcmp (scntemp.s_name, ".bss") == 0)	  {	    f_bhdr = scntemp;	  }      }    }  else    {      ERROR0 ("can't build a COFF file from scratch yet");    }  /* Now we alter the contents of all the f_*hdr variables     to correspond to what we want to dump.  */#ifdef USG_SHARED_LIBRARIES  /* The amount of data we're adding to the file is distance from the   * end of the original .data space to the current end of the .data   * space.   */  bias = bss_end - (f_ohdr.data_start + f_dhdr.s_size);#endif  f_hdr.f_flags |= (F_RELFLG | F_EXEC);#ifdef EXEC_MAGIC  f_ohdr.magic = EXEC_MAGIC;#endif#ifndef NO_REMAP  f_ohdr.text_start = (long) start_of_text ();  f_ohdr.tsize = data_start - f_ohdr.text_start;  f_ohdr.data_start = data_start;#endif /* NO_REMAP */  f_ohdr.dsize = bss_start - f_ohdr.data_start;  f_ohdr.bsize = bss_end - bss_start;  f_thdr.s_size = f_ohdr.tsize;  f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -