From b7fa3dd64d055ca7c992d3a9944bfa1982fd686c Mon Sep 17 00:00:00 2001 From: John Polstra Date: Tue, 23 Dec 1997 05:35:56 +0000 Subject: Add patches to use the unexec function from xemacs. This eliminates the need for a hack in ld.so to make emacs work. I have submitted these changes to a GNU emacs maintainer. --- editors/emacs22/files/patch-ad | 695 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 695 insertions(+) create mode 100644 editors/emacs22/files/patch-ad (limited to 'editors/emacs22/files/patch-ad') diff --git a/editors/emacs22/files/patch-ad b/editors/emacs22/files/patch-ad new file mode 100644 index 000000000000..f2013a374044 --- /dev/null +++ b/editors/emacs22/files/patch-ad @@ -0,0 +1,695 @@ +--- src/unexfreebsd.c.orig Wed Dec 3 17:28:14 1997 ++++ src/unexfreebsd.c Wed Dec 3 17:34:02 1997 +@@ -0,0 +1,692 @@ ++/* Code to do an unexec for FreeBSD for a temacs linked -Bdynamic. ++ Derived from unexnetbsd.c, which was derived from unexsunos4.c ++ Copyright (C) 1992, 1993 Free Software Foundation, Inc. ++ ++This file is part of XEmacs. ++ ++XEmacs 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 2, or (at your option) any ++later version. ++ ++XEmacs 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 XEmacs; see the file COPYING. If not, write to ++the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* Synched up with: Not in FSF? */ ++ ++/* ++Created 29-Oct-92 by Harlan Sexton ++Tweaked 06-Aug-93 by Dean Michaels to work with sun3. ++Converted 01-Dec-93 by Paul Mackerras to work with NetBSD shared libraries. ++Tweaked 26-Feb-94 by Shawn Carey for use with FreeBSD-1.1 shared libraries. ++*/ ++ ++/********************** Included .h Files **************************/ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/********************** Macros *************************************/ ++ ++#define SYS_ERR strerror(errno) ++ ++#define MASK_UP(x,p_of_two) \ ++ ((((unsigned long) (x)) + ((p_of_two) - 1)) & (~((p_of_two) - 1))) ++ ++#define MASK_DOWN(x,p_of_two) (((unsigned long) (x)) & (~((p_of_two) - 1))) ++ ++/********************** Typedefs and Structs ***********************/ ++ ++struct translation_struct ++{ ++ long txtaddr; ++ long txtoff; ++ long dataddr; ++ long datoff; ++ long bssaddr; ++ long endaddr; ++}; ++ ++/********************** Function Prototypes/Declarations ***********/ ++ ++static void unexec_error (const char *m, int use_errno, ...); ++static int unexec_open (char *filename, int flag, int mode); ++static caddr_t unexec_mmap (int fd, size_t len, int prot, int flags); ++static long unexec_seek (int fd, long position); ++static void unexec_read (int fd, long position, char *buf, int bytes); ++static void unexec_write (int fd, long position, char *buf, int bytes); ++static void unexec_pad (int fd, int bytes); ++static void unexec_fstat (int fd, struct stat *statptr); ++static void unexec_fchmod (int fd, int mode); ++static long unexec_addr_to_offset (long addr, struct translation_struct *ts); ++static void copy_relocation_site (struct relocation_info *ri, ++ caddr_t from_base_addr, ++ caddr_t to_base_addr, ++ struct translation_struct *ts); ++static void reset_symtab (struct nlist *start, struct nlist *end, ++ char *strtab, long edata_value, long end_value, ++ int shlib_image); ++static void reset_ldso_symtab (struct nzlist *start, struct nzlist *end, ++ char *strtab, long edata_value, long end_value, ++ int shlib_image); ++int run_time_remap (char *dummy); ++ ++/********************** Variables **********************************/ ++ ++/* for reporting error messages from system calls */ ++extern int errno; ++extern int _DYNAMIC; ++extern char **environ; ++ ++static unsigned long sbrk_of_0_at_unexec; ++ ++/*******************************************************************/ ++ ++static void ++unexec_error (const char *fmt, int use_errno, ...) ++{ ++ const char *err_msg = SYS_ERR; ++ va_list args; ++ ++ fprintf (stderr, "unexec - "); ++ va_start (args, use_errno); ++ vfprintf (stderr, fmt, args); ++ va_end (args); ++ ++ if (use_errno) ++ fprintf (stderr, ": %s", err_msg); ++ fprintf (stderr, "\n"); ++ exit (1); ++ return; ++} ++ ++static int ++unexec_open (char *filename, int flag, int mode) ++{ ++ int fd; ++ ++ errno = 0; ++ ++ fd = open (filename, flag, mode); ++ ++ if (fd < 0) ++ unexec_error ("Failure opening file %s", 1, filename); ++ return fd; ++} ++ ++static caddr_t ++unexec_mmap (int fd, size_t len, int prot, int flags) ++{ ++ caddr_t return_val; ++ ++ unexec_seek (fd, 0); ++ errno = 0; ++ return_val = mmap (0, len, prot, flags, fd, 0); ++ ++ if (return_val == (caddr_t) -1) ++ unexec_error ("Failure mmap'ing file", 1); ++ return return_val; ++} ++ ++ ++static long ++unexec_seek (int fd, long position) ++{ ++ long seek_value; ++ ++ if (fd <= 0) ++ unexec_error ("No file open in which to seek", 0); ++ ++ errno = 0; ++ ++ if (position < 0) ++ seek_value = (long) lseek (fd, 0, L_INCR); ++ else ++ seek_value = (long) lseek (fd, position, L_SET); ++ ++ if (seek_value < 0) ++ unexec_error ("Failed to do a seek to 0x%x in %s", 1, ++ position, "unexec() output file"); ++ ++ return seek_value; ++} ++ ++static void ++unexec_read (int fd, long position, char *buf, int bytes) ++{ ++ int n_read; ++ int remains = bytes; ++ position = unexec_seek (fd, position); ++ ++ if (bytes < 0) ++ unexec_error ("Attempted read of %d bytes", 0, bytes); ++ ++ errno = 0; ++ ++ while (remains > 0) ++ { ++ n_read = read (fd, buf, remains); ++ if (n_read <= 0) ++ unexec_error ("Read failed for 0x%x bytes at offset 0x%x in %s", ++ 1, bytes, position, "unexec() output file"); ++ buf += n_read; ++ remains -= n_read; ++ } ++ ++ return; ++} ++ ++static void ++unexec_write (int fd, long position, char *buf, int bytes) ++{ ++ int n_written; ++ int remains = bytes; ++ position = unexec_seek (fd, position); ++ ++ if (bytes < 0) ++ unexec_error ("Attempted write of %d bytes in %s", ++ 0, bytes, "unexec() output file"); ++ ++ errno = 0; ++ ++ while (remains > 0) ++ { ++ n_written = write (fd, buf, remains); ++ if (n_written <= 0) ++ unexec_error ("Write failed for 0x%x bytes at offset 0x%x in %s", ++ 1, bytes, position, "unexec() output file"); ++ buf += n_written; ++ remains -= n_written; ++ } ++ ++ return; ++} ++ ++static void ++unexec_pad (int fd, int bytes) ++{ ++ if (bytes > 0) ++ { ++ char buf[1024]; ++ int remaining = bytes; ++ ++ memset (buf, 0, sizeof (buf)); ++ ++ while (remaining > 0) ++ { ++ int this_write = (remaining > sizeof(buf))?sizeof(buf):remaining; ++ unexec_write (fd, -1, buf, this_write); ++ remaining -= this_write; ++ } ++ } ++} ++ ++static void ++unexec_fstat (int fd, struct stat *statptr) ++{ ++ errno = 0; ++ if (-1 == fstat (fd, statptr)) ++ unexec_error ("fstat() failed for descriptor %d", 1, fd); ++ return; ++} ++ ++static void ++unexec_fchmod (int fd, int mode) ++{ ++ errno = 0; ++ if (-1 == fchmod (fd, mode)) ++ unexec_error ("fchmod() failed for descriptor %d", 1, fd); ++ return; ++} ++ ++static long ++unexec_addr_to_offset (long addr, struct translation_struct *ts) ++ ++{ ++ if ((addr < ts->txtaddr) || (addr >= ts->bssaddr)) ++ return -1; ++ else if (addr >= ts->dataddr) ++ return ((long) ((addr - ts->dataddr) + ts->datoff)); ++ else ++ return ((long) ((addr - ts->txtaddr) + ts->txtoff)); ++} ++ ++ ++/* ++ * "LD.SO" DATA AND SYMBOL TABLE OPERATIONS ++ */ ++ ++static void ++copy_relocation_site (struct relocation_info *ri, ++ caddr_t from_base_addr, ++ caddr_t to_base_addr, ++ struct translation_struct *ts) ++{ ++ long offset; ++ caddr_t from, to; ++ ++ /* We can get relocation sites in the bss region, for objects whose ++ contents are copied from a shared library. We don't need or want ++ to restore these at present. */ ++#ifndef sparc ++ if (ri->r_copy) ++ return; ++#else ++ /* Struct relocation_info_sparc doesn't have member r_copy. ++ Instead, we use the address to check if this is run-time-copied. */ ++ if (ri->r_address >= ts->bssaddr && ri->r_address < ts->endaddr) ++ return; ++#endif ++ ++ offset = unexec_addr_to_offset (ri->r_address, ts); ++ if (offset == -1) ++ unexec_error ("bad relocation address 0x%x (0x%x)", 0, ri->r_address, ++ ((long *)ri)[1]); ++ ++ from = from_base_addr + offset; ++ to = to_base_addr + offset; ++ /* This stuff should be in a md_ file somewhere... */ ++#ifndef sparc ++ switch (ri->r_length) ++ { ++ case 0: ++ *((char *) to) = *((char *) from); ++ break; ++ case 1: ++ *((short *) to) = *((short *) from); ++ break; ++ case 2: ++ *((long *) to) = *((long *) from); ++ break; ++ default: ++ unexec_error ("unknown reloc length %d seen during unexec()", ++ 0, ri->r_length); ++ break; ++ } ++#else /* sparc */ ++ switch (ri->r_type) ++ { ++ case RELOC_8: ++ case RELOC_DISP8: ++ *((char *) to) = *((char *) from); ++ break; ++ case RELOC_16: ++ case RELOC_DISP16: ++ *((short *) to) = *((short *) from); ++ break; ++ case RELOC_LO10: ++ case RELOC_13: ++ case RELOC_22: ++ case RELOC_HI22: ++ case RELOC_WDISP22: ++ case RELOC_WDISP30: ++ case RELOC_32: ++ case RELOC_DISP32: ++ case RELOC_GLOB_DAT: ++ *((long *) to) = *((long *) from); ++ break; ++ case RELOC_JMP_SLOT: ++ { ++ long *target = (long *) to; ++ long *source = (long *) from; ++ *target = *source; ++ target++; ++ source++; ++ *target = *source; ++ target++; ++ source++; ++ *target = *source; ++ } ++ break; ++ default: ++ unexec_error ("unknown reloc type %d seen during unexec()", ++ 0, ri->r_type); ++ break; ++ } ++#endif /* sparc */ ++} ++ ++static void ++reset_symtab (struct nlist *start, struct nlist *end, char *strtab, ++ long edata_value, long end_value, int shlib_image) ++{ ++ struct nlist *tmp = start; ++ int found_edata = 0; ++ int found_end = 0; ++ ++ while (tmp < end) ++ { ++ int type = tmp->n_type; ++ ++ if ((type == (N_UNDF | N_EXT)) && ++ (tmp->n_value != 0)) ++ unexec_error ("unexec'ing image has COMMON symbols in it -- we quit!", ++ 0); ++ ++ if (!(type & N_STAB)) ++ { ++ if (!found_edata && ++ (type == (N_EXT | N_DATA)) && ++ tmp->n_un.n_strx && ++ !strcmp ("_edata", strtab + tmp->n_un.n_strx)) ++ { ++ tmp->n_value = edata_value; ++ found_edata = 1; ++ } ++ ++ ++ if ((type & N_TYPE) == N_BSS) ++ { ++ if (!found_end && ++ (type == (N_EXT | N_BSS)) && ++ tmp->n_un.n_strx && ++ !strcmp ("_end", strtab + tmp->n_un.n_strx)) ++ { ++ tmp->n_value = end_value; ++ found_end = 1; ++ } ++ else if (type & N_EXT) ++ tmp->n_type = N_DATA | N_EXT; ++ else ++ tmp->n_type = N_DATA; ++ } ++ ++ /* the way things are being handled here, having sbrk() in the ++ image is fatal for an image linked with shared lib's (although ++ the code could be modified to support it), but this should ++ never happen anyway */ ++ if (shlib_image && ++ (type == (N_EXT | N_TEXT)) && ++ tmp->n_un.n_strx && ++ !strcmp ("_sbrk", strtab + tmp->n_un.n_strx)) ++ unexec_error ("unexec'd shlib image has sbrk() in it -- we quit!", ++ 0); ++ } ++ ++ tmp++; ++ } ++} ++ ++static void ++reset_ldso_symtab (struct nzlist *start, struct nzlist *end, char *strtab, ++ long edata_value, long end_value, int shlib_image) ++{ ++ struct nzlist *tmp = start; ++ int found_edata = 0; ++ int found_end = 0; ++ ++ while (tmp < end) { ++ int type = tmp->nz_type; ++/* ++ * the following code breaks under FreeBSD-1.1-BETA, but everything ++ * seems to work perfectly if it's commented out. This did not break ++ * anything until the changes to ld.so were made. ++ */ ++/* ++ if ((type == (N_UNDF | N_EXT)) && (tmp->nz_value != 0)) ++ unexec_error("unexec'ing image has COMMON symbols in rel -- we quit!",0); ++*/ ++ if (!(type & N_STAB)) { ++ if (!found_edata && ++ (type == (N_EXT | N_DATA)) && ++ !strcmp ("_edata", strtab + tmp->nz_strx)) { ++ tmp->nz_value = edata_value; ++ found_edata = 1; ++ } ++ ++ if ((type & N_TYPE) == N_BSS) { ++ if (!found_end && ++ (type == (N_EXT | N_BSS)) && ++ !strcmp ("_end", strtab + tmp->nz_strx)) { ++ tmp->nz_value = end_value; ++ found_end = 1; ++ } else if (type & N_EXT) ++ tmp->nz_type = N_DATA | N_EXT; ++ else ++ tmp->nz_type = N_DATA; ++ } ++ ++ /* the way things are being handled here, having sbrk() in the ++ image is fatal for an image linked with shared lib's (although ++ the code could be modified to support it), but this should ++ never happen anyway */ ++ if (shlib_image && ++ (type == (N_EXT | N_TEXT)) && ++ !strcmp ("_sbrk", strtab + tmp->nz_strx)) ++ unexec_error("unexec'd shlib image has sbrk() ref -- we quit!", 0); ++ } ++ tmp++; ++ } ++} ++ ++extern int getpagesize (void); ++ ++/* ++ * EXPORTED FUNCTIONS ++ */ ++ ++/* this has to be a global variable to prevent the optimizers from ++ * assuming that it can not be 0. ++*/ ++static void *dynamic_addr = (void *) &_DYNAMIC; ++ ++int ++unexec (char *new_name, char *old_name, ++ unsigned int emacs_edata, unsigned int dummy1, unsigned int dummy2) ++{ ++ /* ld.so data */ ++ struct _dynamic *ld = 0; ++ struct section_dispatch_table *ld2 = 0; ++ /* old and new state */ ++ int old_fd; ++ int new_fd; ++ caddr_t old_base_addr; ++ caddr_t new_base_addr; ++ struct exec old_hdr; ++ struct exec new_hdr; ++ struct stat old_buf; ++ struct stat new_buf; ++ /* some process specific "constants" */ ++ unsigned long n_pagsiz, new_edata; ++ long page_size = getpagesize (); ++ caddr_t plt_end; ++ caddr_t current_break = (caddr_t) sbrk (0); ++ ++ if (!page_size) ++ unexec_error ("unexec() failed because we can't get the size of a page!", ++ 0); ++ ++ /* see if this is a -Bdynamic image -- if so, find ld.so structures */ ++ if (dynamic_addr) ++ { ++ ld = (struct _dynamic *) dynamic_addr; ++ ld2 = ld->d_un.d_sdt; ++ if (ld->d_version < LD_VERSION_BSD) ++ unexec_error ("%s linked with obsolete version of ld -- we quit!", ++ 0, old_name); ++ } ++ ++ /* open the old and new files, figuring out how big the old one is ++ so that we can map it in */ ++ old_fd = unexec_open (old_name, O_RDONLY, 0); ++ new_fd = unexec_open (new_name, O_RDWR | O_CREAT | O_TRUNC, 0666); ++ ++ /* setup the header and the statbuf for old_fd */ ++ unexec_read (old_fd, 0, (char *) &old_hdr, sizeof (old_hdr)); ++ unexec_fstat (old_fd, &old_buf); ++ ++ ++ /* set up some important constants */ ++ n_pagsiz = __LDPGSZ; ++ if (dynamic_addr) ++ plt_end = (caddr_t) MASK_UP (ld2->sdt_plt + ld2->sdt_plt_sz, sizeof (double)); ++ else ++ plt_end = (caddr_t) N_DATADDR (old_hdr); ++ ++#if 0 ++ /* never write protect the variable "environ", defined in /lib/crt0.o, and ++ set in process.c and callproc.c */ ++ mprotect_bottom_addr = ((unsigned long) &environ) + sizeof (char **); ++ /* never protect ABOVE the end of data emacs_edata specified */ ++ mprotect_top_addr = MIN (emacs_edata, N_DATADDR (old_hdr) + old_hdr.a_data); ++#endif ++ ++ /* Set up the image of the old file */ ++ old_base_addr = unexec_mmap (old_fd, old_buf.st_size, PROT_READ, ++ MAP_FILE | MAP_PRIVATE); ++ close (old_fd); ++ ++ /* set up the new exec */ ++ new_hdr = old_hdr; ++ new_edata = (unsigned long) MASK_UP (current_break, n_pagsiz); ++ new_hdr.a_data = new_edata - ((unsigned long) N_DATADDR (old_hdr)); ++ new_hdr.a_bss = 0; ++ ++ /* set up this variable, in case we want to reset "the break" ++ when restarting */ ++ sbrk_of_0_at_unexec = ((unsigned long) MASK_UP (current_break, n_pagsiz)); ++ ++ /* Write out the first approximation to the new file. The sizes of ++ each section will be correct, but there will be a number of ++ corrections that will need to be made. */ ++ { ++ long old_datoff = N_DATOFF (old_hdr); ++ long old_dataddr = N_DATADDR (old_hdr); ++ long new_treloff = N_RELOFF (new_hdr); ++ long old_treloff = N_RELOFF (old_hdr); ++ long ld_so_size = ((unsigned long) plt_end) - old_dataddr; ++ long real_data_size = current_break - plt_end; ++ long pad_size = ++ MASK_UP (current_break, n_pagsiz) - ((unsigned long) current_break); ++ ++ ++ /* First, write the text segment with new header -- copy everything until ++ the start of the data segment from the old file, and then go back and ++ write the new header. */ ++ unexec_write (new_fd, 0, old_base_addr, old_datoff + ld_so_size); ++ unexec_write (new_fd, 0, (char *) &new_hdr, sizeof (new_hdr)); ++ ++ /* Copy the rest of the data segment from the running image. */ ++ unexec_write (new_fd, old_datoff + ld_so_size, ++ plt_end, real_data_size); ++ ++ /* pad out the data segment */ ++ unexec_pad (new_fd, pad_size); ++ ++ /* Finally, copy the symbol table information from the old file. */ ++ unexec_write (new_fd, new_treloff, ++ old_base_addr + old_treloff, ++ old_buf.st_size - old_treloff); ++ } ++ ++ ++ /* Next, map in the output file so that we can jump around fixing it ++ up. We retain the old file so that we can refer to it. */ ++ unexec_fstat (new_fd, &new_buf); ++ new_base_addr = unexec_mmap (new_fd, ++ MASK_UP (new_buf.st_size, page_size), ++ PROT_READ | PROT_WRITE, ++ MAP_FILE | MAP_SHARED); ++ ++ ++ ++ /* We need to do 2 things. First, make sure that _edata and _end (and ++ hence, curbrk) are set to the correct values. At the same time, for ++ neatness and to help with debugging, mark all the types of all ld.so ++ and nm BSS symbols in the new file to be DATA, and make sure that ++ there are no COMMON symbols in the output file, as any references to ++ these can lose really big. Second, reset all of the ld.so "relocation ++ sites" in the new file to have the values that appear in the old file ++ -- the failure to do this was the biggest loser in the old version of ++ this code. */ ++ ++ /* STEP 1 */ ++ /* Reset the regular symbol table first. */ ++ reset_symtab ((struct nlist *) (new_base_addr + N_SYMOFF(new_hdr)), ++ (struct nlist *) (new_base_addr + N_SYMOFF(new_hdr) + ++ new_hdr.a_syms), ++ (char *) (new_base_addr + N_STROFF(new_hdr)), ++ new_edata, new_edata, ++ !!dynamic_addr); ++ ++ /* Now reset the ld.so symbol table. */ ++ if (dynamic_addr) ++ { ++ struct translation_struct ts; ++ struct relocation_info *tmp, *end; ++ caddr_t syms, strings; ++ ++ /* set up the structure that we use to translate addresses in the ++ old file into file offsets */ ++ ts.txtaddr = N_TXTADDR (old_hdr); ++ ts.txtoff = N_TXTOFF (old_hdr); ++ ts.dataddr = N_DATADDR (old_hdr); ++ ts.datoff = N_DATOFF (old_hdr); ++ ts.bssaddr = N_DATADDR (old_hdr) + old_hdr.a_data; ++ ts.endaddr = ts.bssaddr + old_hdr.a_bss; ++ ++ syms = new_base_addr + unexec_addr_to_offset(ld2->sdt_nzlist, &ts); ++ strings = new_base_addr + unexec_addr_to_offset(ld2->sdt_strings, &ts); ++ reset_ldso_symtab ((struct nzlist *) syms, (struct nzlist *) strings, ++ (char *) strings, ++ new_edata, new_edata, ++ !!dynamic_addr); ++ ++ /* STEP 2 */ ++ tmp = (struct relocation_info *) ++ (old_base_addr + unexec_addr_to_offset(ld2->sdt_rel, &ts)); ++ end = (struct relocation_info *) ++ (old_base_addr + unexec_addr_to_offset(ld2->sdt_hash, &ts)); ++ while (tmp < end) ++ { ++ copy_relocation_site (tmp, old_base_addr, new_base_addr, &ts); ++ tmp++; ++ } ++ } ++ ++ /* get rid of the mmap-ed file space and make the output file ++ executable -- then quit */ ++ munmap (new_base_addr, MASK_UP (new_buf.st_size, page_size)); ++ munmap (old_base_addr, MASK_UP (old_buf.st_size, page_size)); ++ unexec_fchmod (new_fd, 0755); ++ close (new_fd); ++ return 0; ++} ++ ++ ++int ++run_time_remap (char *dummy) ++{ ++ unsigned long current_sbrk = (unsigned long) sbrk (0); ++ ++ if (sbrk_of_0_at_unexec > current_sbrk) ++ { ++ errno = 0; ++ if (brk ((caddr_t) sbrk_of_0_at_unexec)) ++ fprintf (stderr, "failed to change brk addr to 0x%lx: %s\n", ++ sbrk_of_0_at_unexec, SYS_ERR); ++ } ++ ++ return 0; ++} -- cgit v1.2.3