[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
scratch/no-purespace ec121292d5c 01/13: Unexec removal: Remove obsolete
From: |
Pip Cet |
Subject: |
scratch/no-purespace ec121292d5c 01/13: Unexec removal: Remove obsolete files |
Date: |
Tue, 20 Aug 2024 15:42:43 -0400 (EDT) |
branch: scratch/no-purespace
commit ec121292d5c44922380d6978963c803b7dece9b4
Author: Pip Cet <pipcet@protonmail.com>
Commit: Pip Cet <pipcet@protonmail.com>
Unexec removal: Remove obsolete files
* sheap.c, sheap.h, unexec.h:
unexaix.c, unexcoff.c, unexcw.c, unexelf.c, unexhp9k800.c,
unexmacosx.c, unexsol.c, unexw32.c: Files removed.
---
src/sheap.c | 79 ---
src/sheap.h | 30 --
src/unexaix.c | 611 -----------------------
src/unexcoff.c | 540 --------------------
src/unexcw.c | 302 ------------
src/unexec.h | 4 -
src/unexelf.c | 659 -------------------------
src/unexhp9k800.c | 324 ------------
src/unexmacosx.c | 1406 -----------------------------------------------------
src/unexsol.c | 28 --
src/unexw32.c | 684 --------------------------
11 files changed, 4667 deletions(-)
diff --git a/src/sheap.c b/src/sheap.c
deleted file mode 100644
index bab70c4e343..00000000000
--- a/src/sheap.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/* simulate `sbrk' with an array in .bss, for `unexec' support for Cygwin;
- complete rewrite of xemacs Cygwin `unexec' code
-
- Copyright (C) 2004-2024 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs 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 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "sheap.h"
-
-#include <stdio.h>
-#include "lisp.h"
-#include <unistd.h>
-#include <stdlib.h> /* for exit */
-
-static int debug_sheap;
-
-char bss_sbrk_buffer[STATIC_HEAP_SIZE];
-char *max_bss_sbrk_ptr;
-
-void *
-bss_sbrk (ptrdiff_t request_size)
-{
- static char *bss_sbrk_ptr;
-
- if (!bss_sbrk_ptr)
- {
- max_bss_sbrk_ptr = bss_sbrk_ptr = bss_sbrk_buffer;
-#ifdef CYGWIN
- /* Force space for fork to work. */
- sbrk (4096);
-#endif
- }
-
- int used = bss_sbrk_ptr - bss_sbrk_buffer;
-
- if (request_size < -used)
- {
- printf (("attempt to free too much: "
- "avail %d used %d failed request %"pD"d\n"),
- STATIC_HEAP_SIZE, used, request_size);
- exit (-1);
- return 0;
- }
- else if (STATIC_HEAP_SIZE - used < request_size)
- {
- printf ("static heap exhausted: avail %d used %d failed request
%"pD"d\n",
- STATIC_HEAP_SIZE, used, request_size);
- exit (-1);
- return 0;
- }
-
- void *ret = bss_sbrk_ptr;
- bss_sbrk_ptr += request_size;
- if (max_bss_sbrk_ptr < bss_sbrk_ptr)
- max_bss_sbrk_ptr = bss_sbrk_ptr;
- if (debug_sheap)
- {
- if (request_size < 0)
- printf ("freed size %"pD"d\n", request_size);
- else
- printf ("allocated %p size %"pD"d\n", ret, request_size);
- }
- return ret;
-}
diff --git a/src/sheap.h b/src/sheap.h
deleted file mode 100644
index 92f7ba5e857..00000000000
--- a/src/sheap.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Static heap allocation for GNU Emacs.
-
-Copyright 2016-2024 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs 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 3 of the License, or
-(at your option) any later version.
-
-GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-#include <stddef.h>
-#include "lisp.h"
-
-/* Size of the static heap. Guess a value that is probably too large,
- by up to a factor of four or so. Typically the unused part is not
- paged in and so does not cost much. */
-enum { STATIC_HEAP_SIZE = sizeof (Lisp_Object) << 24 };
-
-extern char bss_sbrk_buffer[STATIC_HEAP_SIZE];
-extern char *max_bss_sbrk_ptr;
-extern void *bss_sbrk (ptrdiff_t);
diff --git a/src/unexaix.c b/src/unexaix.c
deleted file mode 100644
index f9bc39cf927..00000000000
--- a/src/unexaix.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/* Dump an executable file.
- Copyright (C) 1985-1988, 1999, 2001-2024 Free Software Foundation,
- Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs 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 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-/*
-In other words, you are welcome to use, share and improve this program.
-You are forbidden to forbid anyone else to use, share and improve
-what you give them. Help stamp out software-hoarding! */
-
-
-/* Originally based on the COFF unexec.c by Spencer W. Thomas.
- *
- * Subsequently hacked on by
- * Bill Mann <Bill_Man@praxisint.com>
- * Andrew Vignaux <Andrew.Vignaux@comp.vuw.ac.nz>
- * Mike Sperber <sperber@informatik.uni-tuebingen.de>
- *
- * Synopsis:
- * unexec (const char *new_name, const *old_name);
- *
- * 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.
- *
- */
-
-#include <config.h>
-#include "unexec.h"
-#include "lisp.h"
-
-#define PERROR(file) report_error (file, new)
-#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"
-
-#include <sys/types.h>
-#include <inttypes.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-extern char _data[];
-extern char _text[];
-
-#include <filehdr.h>
-#include <aouthdr.h>
-#include <scnhdr.h>
-#include <syms.h>
-
-static struct filehdr f_hdr; /* File header */
-static struct aouthdr f_ohdr; /* Optional file header (a.out) */
-static off_t bias; /* Bias to add for growth */
-static off_t lnnoptr; /* Pointer to line-number info within
file */
-
-static off_t text_scnptr;
-static off_t data_scnptr;
-#define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1))
-static off_t load_scnptr;
-static off_t orig_load_scnptr;
-static off_t orig_data_scnptr;
-static int unrelocate_symbols (int, int, const char *, const char *);
-
-#ifndef MAX_SECTIONS
-#define MAX_SECTIONS 10
-#endif
-
-static int adjust_lnnoptrs (int, int, const char *);
-
-static int pagemask;
-
-#include "lisp.h"
-
-static _Noreturn void
-report_error (const char *file, int fd)
-{
- int err = errno;
- if (fd)
- emacs_close (fd);
- report_file_errno ("Cannot unexec", build_string (file), err);
-}
-
-#define ERROR0(msg) report_error_1 (new, msg)
-#define ERROR1(msg,x) report_error_1 (new, msg, x)
-#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y)
-
-static _Noreturn void ATTRIBUTE_FORMAT_PRINTF (2, 3)
-report_error_1 (int fd, const char *msg, ...)
-{
- va_list ap;
- emacs_close (fd);
- va_start (ap, msg);
- verror (msg, ap);
- va_end (ap);
-}
-
-static int make_hdr (int, int, const char *, const char *);
-static void mark_x (const char *);
-static int copy_text_and_data (int);
-static int copy_sym (int, int, const char *, const char *);
-static void write_segment (int, char *, char *);
-
-/* ****************************************************************
- * unexec
- *
- * driving logic.
- */
-void
-unexec (const char *new_name, const char *a_name)
-{
- int new = -1, a_out = -1;
-
- if (a_name && (a_out = emacs_open (a_name, O_RDONLY, 0)) < 0)
- {
- PERROR (a_name);
- }
- if ((new = emacs_open (new_name, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0)
- {
- PERROR (new_name);
- }
- if (make_hdr (new, a_out,
- a_name, new_name) < 0
- || copy_text_and_data (new) < 0
- || copy_sym (new, a_out, a_name, new_name) < 0
- || adjust_lnnoptrs (new, a_out, new_name) < 0
- || unrelocate_symbols (new, a_out, a_name, new_name) < 0)
- {
- emacs_close (new);
- return;
- }
-
- emacs_close (new);
- if (a_out >= 0)
- emacs_close (a_out);
-}
-
-/* ****************************************************************
- * make_hdr
- *
- * Make the header in the new a.out from the header in core.
- * Modify the text and data sizes.
- */
-static int
-make_hdr (int new, int a_out,
- const char *a_name, const char *new_name)
-{
- int scns;
- uintptr_t bss_start;
- uintptr_t data_start;
-
- struct scnhdr section[MAX_SECTIONS];
- struct scnhdr * f_thdr; /* Text section header */
- struct scnhdr * f_dhdr; /* Data section header */
- struct scnhdr * f_bhdr; /* Bss section header */
- struct scnhdr * f_lhdr; /* Loader section header */
- struct scnhdr * f_tchdr; /* Typechk section header */
- struct scnhdr * f_dbhdr; /* Debug section header */
- struct scnhdr * f_xhdr; /* Except section header */
-
- load_scnptr = orig_load_scnptr = lnnoptr = 0;
- pagemask = getpagesize () - 1;
-
- /* Adjust text/data boundary. */
- data_start = (uintptr_t) _data;
-
- data_start = data_start & ~pagemask; /* (Down) to page boundary. */
-
- bss_start = (uintptr_t) sbrk (0) + pagemask;
- bss_start &= ~ pagemask;
-
- if (data_start > bss_start) /* Can't have negative data size. */
- {
- ERROR2 (("unexec: data_start (0x%"PRIxPTR
- ") can't be greater than bss_start (0x%"PRIxPTR")"),
- data_start, bss_start);
- }
-
- /* Salvage as much info from the existing file as possible */
- f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL;
- f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL;
- if (a_out >= 0)
- {
- if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
- {
- PERROR (a_name);
- }
- if (f_hdr.f_opthdr > 0)
- {
- if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
- {
- PERROR (a_name);
- }
- }
- if (f_hdr.f_nscns > MAX_SECTIONS)
- {
- ERROR0 ("unexec: too many section headers -- increase MAX_SECTIONS");
- }
- /* Loop through section headers */
- for (scns = 0; scns < f_hdr.f_nscns; scns++) {
- struct scnhdr *s = §ion[scns];
- if (read (a_out, s, sizeof (*s)) != sizeof (*s))
- {
- PERROR (a_name);
- }
-
-#define CHECK_SCNHDR(ptr, name, flags) \
- if (strcmp (s->s_name, name) == 0) { \
- if (s->s_flags != flags) { \
- fprintf (stderr, "unexec: %lx flags where %x expected in %s section.\n",
\
- (unsigned long)s->s_flags, flags, name); \
- } \
- if (ptr) { \
- fprintf (stderr, "unexec: duplicate section header for section %s.\n", \
- name); \
- } \
- ptr = s; \
- }
- CHECK_SCNHDR (f_thdr, _TEXT, STYP_TEXT);
- CHECK_SCNHDR (f_dhdr, _DATA, STYP_DATA);
- CHECK_SCNHDR (f_bhdr, _BSS, STYP_BSS);
- CHECK_SCNHDR (f_lhdr, _LOADER, STYP_LOADER);
- CHECK_SCNHDR (f_dbhdr, _DEBUG, STYP_DEBUG);
- CHECK_SCNHDR (f_tchdr, _TYPCHK, STYP_TYPCHK);
- CHECK_SCNHDR (f_xhdr, _EXCEPT, STYP_EXCEPT);
- }
-
- if (f_thdr == 0)
- {
- ERROR1 ("unexec: couldn't find \"%s\" section", _TEXT);
- }
- if (f_dhdr == 0)
- {
- ERROR1 ("unexec: couldn't find \"%s\" section", _DATA);
- }
- if (f_bhdr == 0)
- {
- ERROR1 ("unexec: couldn't find \"%s\" section", _BSS);
- }
- }
- else
- {
- ERROR0 ("can't build a COFF file from scratch yet");
- }
- orig_data_scnptr = f_dhdr->s_scnptr;
- orig_load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0;
-
- /* Now we alter the contents of all the f_*hdr variables
- to correspond to what we want to dump. */
-
- /* Indicate that the reloc information is no longer valid for ld (bind);
- we only update it enough to fake out the exec-time loader. */
- f_hdr.f_flags |= (F_RELFLG | F_EXEC);
-
- f_ohdr.dsize = bss_start - f_ohdr.data_start;
- f_ohdr.bsize = 0;
-
- f_dhdr->s_size = f_ohdr.dsize;
- f_bhdr->s_size = f_ohdr.bsize;
- f_bhdr->s_paddr = f_ohdr.data_start + f_ohdr.dsize;
- f_bhdr->s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
-
- /* fix scnptr's */
- {
- off_t ptr = section[0].s_scnptr;
-
- bias = -1;
- for (scns = 0; scns < f_hdr.f_nscns; scns++)
- {
- struct scnhdr *s = §ion[scns];
-
- if (s->s_flags & STYP_PAD) /* .pad sections omitted in AIX 4.1 */
- {
- /*
- * the text_start should probably be o_algntext but that doesn't
- * seem to change
- */
- if (f_ohdr.text_start != 0) /* && scns != 0 */
- {
- s->s_size = 512 - (ptr % 512);
- if (s->s_size == 512)
- s->s_size = 0;
- }
- s->s_scnptr = ptr;
- }
- else if (s->s_flags & STYP_DATA)
- s->s_scnptr = ptr;
- else if (!(s->s_flags & (STYP_TEXT | STYP_BSS)))
- {
- if (bias == -1) /* if first section after bss */
- bias = ptr - s->s_scnptr;
-
- s->s_scnptr += bias;
- ptr = s->s_scnptr;
- }
-
- ptr = ptr + s->s_size;
- }
- }
-
- /* fix other pointers */
- for (scns = 0; scns < f_hdr.f_nscns; scns++)
- {
- struct scnhdr *s = §ion[scns];
-
- if (s->s_relptr != 0)
- {
- s->s_relptr += bias;
- }
- if (s->s_lnnoptr != 0)
- {
- if (lnnoptr == 0) lnnoptr = s->s_lnnoptr;
- s->s_lnnoptr += bias;
- }
- }
-
- if (f_hdr.f_symptr > 0L)
- {
- f_hdr.f_symptr += bias;
- }
-
- text_scnptr = f_thdr->s_scnptr;
- data_scnptr = f_dhdr->s_scnptr;
- load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0;
-
- if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
- {
- PERROR (new_name);
- }
-
- if (f_hdr.f_opthdr > 0)
- {
- if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
- {
- PERROR (new_name);
- }
- }
-
- for (scns = 0; scns < f_hdr.f_nscns; scns++) {
- struct scnhdr *s = §ion[scns];
- if (write (new, s, sizeof (*s)) != sizeof (*s))
- {
- PERROR (new_name);
- }
- }
-
- return (0);
-}
-
-/* ****************************************************************
-
- *
- * Copy the text and data segments from memory to the new a.out
- */
-static int
-copy_text_and_data (int new)
-{
- char *end;
- char *ptr;
-
- lseek (new, text_scnptr, SEEK_SET);
- ptr = _text;
- end = ptr + f_ohdr.tsize;
- write_segment (new, ptr, end);
-
- lseek (new, data_scnptr, SEEK_SET);
- ptr = (char *) (ptrdiff_t) f_ohdr.data_start;
- end = ptr + f_ohdr.dsize;
- write_segment (new, ptr, end);
-
- return 0;
-}
-
-#define UnexBlockSz (1<<12) /* read/write block size */
-static void
-write_segment (int new, char *ptr, char *end)
-{
- int i, nwrite, ret;
- char zeros[UnexBlockSz];
-
- for (i = 0; ptr < end;)
- {
- /* distance to next block. */
- nwrite = (((ptrdiff_t) ptr + UnexBlockSz) & -UnexBlockSz) - (ptrdiff_t)
ptr;
- /* But not beyond specified end. */
- if (nwrite > end - ptr) nwrite = end - ptr;
- ret = write (new, ptr, nwrite);
- /* If write gets a page fault, it means we reached
- a gap between the old text segment and the old data segment.
- This gap has probably been remapped into part of the text segment.
- So write zeros for it. */
- if (ret == -1 && errno == EFAULT)
- {
- memset (zeros, 0, nwrite);
- write (new, zeros, nwrite);
- }
- else if (nwrite != ret)
- {
- int write_errno = errno;
- char buf[1000];
- void *addr = ptr;
- sprintf (buf,
- "unexec write failure: addr %p, fileno %d, size 0x%x, wrote
0x%x, errno %d",
- addr, new, nwrite, ret, errno);
- errno = write_errno;
- PERROR (buf);
- }
- i += nwrite;
- ptr += nwrite;
- }
-}
-
-/* ****************************************************************
- * copy_sym
- *
- * Copy the relocation information and symbol table from the a.out to the new
- */
-static int
-copy_sym (int new, int a_out, const char *a_name, const char *new_name)
-{
- char page[UnexBlockSz];
- int n;
-
- if (a_out < 0)
- return 0;
-
- if (orig_load_scnptr == 0L)
- return 0;
-
- if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info
*/
- lseek (a_out, lnnoptr, SEEK_SET); /* start copying from there */
- else
- lseek (a_out, orig_load_scnptr, SEEK_SET); /* Position a.out to symtab. */
-
- while ((n = read (a_out, page, sizeof page)) > 0)
- {
- if (write (new, page, n) != n)
- {
- PERROR (new_name);
- }
- }
- if (n < 0)
- {
- PERROR (a_name);
- }
- return 0;
-}
-
-static int
-adjust_lnnoptrs (int writedesc, int readdesc, const char *new_name)
-{
- int nsyms;
- int naux;
- int new;
- struct syment symentry;
- union auxent auxentry;
-
- if (!lnnoptr || !f_hdr.f_symptr)
- return 0;
-
- if ((new = emacs_open (new_name, O_RDWR, 0)) < 0)
- {
- PERROR (new_name);
- return -1;
- }
-
- lseek (new, f_hdr.f_symptr, SEEK_SET);
- for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
- {
- read (new, &symentry, SYMESZ);
- if (symentry.n_sclass == C_BINCL || symentry.n_sclass == C_EINCL)
- {
- symentry.n_value += bias;
- lseek (new, -SYMESZ, SEEK_CUR);
- write (new, &symentry, SYMESZ);
- }
-
- for (naux = symentry.n_numaux; naux-- != 0; )
- {
- read (new, &auxentry, AUXESZ);
- nsyms++;
- if (naux != 0 /* skip csect auxentry (last entry) */
- && (symentry.n_sclass == C_EXT || symentry.n_sclass == C_HIDEXT))
- {
- auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
- lseek (new, -AUXESZ, SEEK_CUR);
- write (new, &auxentry, AUXESZ);
- }
- }
- }
- emacs_close (new);
-
- return 0;
-}
-
-static int
-unrelocate_symbols (int new, int a_out,
- const char *a_name, const char *new_name)
-{
- int i;
- LDHDR ldhdr;
- LDREL ldrel;
- off_t t_reloc = (intptr_t) _text - f_ohdr.text_start;
-#ifndef ALIGN_DATA_RELOC
- off_t d_reloc = (intptr_t) _data - f_ohdr.data_start;
-#else
- /* This worked (and was needed) before AIX 4.2.
- I have no idea why. -- Mike */
- off_t d_reloc = (intptr_t) _data - ALIGN (f_ohdr.data_start, 2);
-#endif
- int * p;
-
- if (load_scnptr == 0)
- return 0;
-
- lseek (a_out, orig_load_scnptr, SEEK_SET);
- if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr))
- {
- PERROR (new_name);
- }
-
-#define SYMNDX_TEXT 0
-#define SYMNDX_DATA 1
-#define SYMNDX_BSS 2
-
- for (i = 0; i < ldhdr.l_nreloc; i++)
- {
- lseek (a_out,
- orig_load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i,
- SEEK_SET);
-
- if (read (a_out, &ldrel, LDRELSZ) != LDRELSZ)
- {
- PERROR (a_name);
- }
-
- /* move the BSS loader symbols to the DATA segment */
- if (ldrel.l_symndx == SYMNDX_BSS)
- {
- ldrel.l_symndx = SYMNDX_DATA;
-
- lseek (new,
- load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i,
- SEEK_SET);
-
- if (write (new, &ldrel, LDRELSZ) != LDRELSZ)
- {
- PERROR (new_name);
- }
- }
-
- if (ldrel.l_rsecnm == f_ohdr.o_sndata)
- {
- int orig_int;
-
- lseek (a_out,
- orig_data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start),
- SEEK_SET);
-
- if (read (a_out, (void *) &orig_int, sizeof (orig_int))
- != sizeof (orig_int))
- {
- PERROR (a_name);
- }
-
- p = (int *) (intptr_t) (ldrel.l_vaddr + d_reloc);
-
- switch (ldrel.l_symndx) {
- case SYMNDX_TEXT:
- orig_int = * p - t_reloc;
- break;
-
- case SYMNDX_DATA:
- case SYMNDX_BSS:
- orig_int = * p - d_reloc;
- break;
- }
-
- if (orig_int != * p)
- {
- lseek (new,
- data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start),
- SEEK_SET);
- if (write (new, (void *) &orig_int, sizeof (orig_int))
- != sizeof (orig_int))
- {
- PERROR (new_name);
- }
- }
- }
- }
- return 0;
-}
diff --git a/src/unexcoff.c b/src/unexcoff.c
deleted file mode 100644
index 4a981da4a04..00000000000
--- a/src/unexcoff.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/* Copyright (C) 1985-1988, 1992-1994, 2001-2024 Free Software
- * Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs 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 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-
-/*
- * unexcoff.c - Convert a running program into an a.out or COFF file.
- *
- * ==================================================================
- * Note: This file is currently used only by the MSDOS (a.k.a. DJGPP)
- * build of Emacs. If you are not interested in the MSDOS build, you
- * are looking at the wrong version of unexec!
- * ==================================================================
- *
- * Author: Spencer W. Thomas
- * Computer Science Dept.
- * University of Utah
- * Date: Tue Mar 2 1982
- * Originally under the name unexec.c.
- * Modified heavily since then.
- *
- * Synopsis:
- * unexec (const char *new_name, const char *old_name);
- *
- * 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.
- *
- * 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.
- */
-
-#include <config.h>
-#include "unexec.h"
-#include "lisp.h"
-
-#define PERROR(file) report_error (file, new)
-
-#ifdef HAVE_UNEXEC /* all rest of file! */
-
-#ifdef HAVE_COFF_H
-#include <coff.h>
-#ifdef MSDOS
-#include <fcntl.h> /* for O_RDONLY, O_RDWR */
-#include <crt0.h> /* for _crt0_startup_flags and its bits */
-#include <sys/exceptn.h>
-static int save_djgpp_startup_flags;
-#include <libc/atexit.h>
-static struct __atexit *save_atexit_ptr;
-#define filehdr external_filehdr
-#define scnhdr external_scnhdr
-#define syment external_syment
-#define auxent external_auxent
-#define n_numaux e_numaux
-#define n_type e_type
-struct aouthdr
-{
- unsigned short magic; /* type of file */
- unsigned short vstamp; /* version stamp */
- unsigned long tsize; /* text size in bytes, padded to FW
bdry*/
- unsigned long dsize; /* initialized data " "
*/
- unsigned long bsize; /* uninitialized data " "
*/
- unsigned long entry; /* entry pt.
*/
- unsigned long text_start;/* base of text used for this file */
- unsigned long data_start;/* base of data used for this file */
-};
-#endif /* MSDOS */
-#else /* not HAVE_COFF_H */
-#include <a.out.h>
-#endif /* not HAVE_COFF_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 /* makedev */
-#include <errno.h>
-
-#include <sys/file.h>
-
-extern int etext;
-
-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_start
-
-static long text_scnptr;
-static long data_scnptr;
-
-static long coff_offset;
-
-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. */
-
-#define ADDR_CORRECT(x) ((char *) (x) - (char *) 0)
-
-#include "lisp.h"
-
-static void
-report_error (const char *file, int fd)
-{
- int err = errno;
- if (fd)
- emacs_close (fd);
- report_file_errno ("Cannot unexec", build_string (file), err);
-}
-
-#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 -1
-
-static void
-report_error_1 (int fd, const char *msg, int a1, int a2)
-{
- emacs_close (fd);
- error (msg, a1, a2);
-}
-
-static int make_hdr (int, int, const char *, const char *);
-static int copy_text_and_data (int, int);
-static int copy_sym (int, int, const char *, const char *);
-static void mark_x (const char *);
-
-/* ****************************************************************
- * make_hdr
- *
- * Make the header in the new a.out from the header in core.
- * Modify the text and data sizes.
- */
-static int
-make_hdr (int new, int a_out,
- const char *a_name, const char *new_name)
-{
- 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;
- unsigned int bss_start;
- unsigned int data_start;
-
- pagemask = getpagesize () - 1;
-
- /* Adjust text/data boundary. */
- data_start = (int) DATA_START;
- data_start = ADDR_CORRECT (data_start);
- data_start = data_start & ~pagemask; /* (Down) to page boundary. */
-
- bss_start = ADDR_CORRECT (sbrk (0)) + pagemask;
- bss_start &= ~ pagemask;
-
- 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);
- }
-
- coff_offset = 0L; /* stays zero, except in DJGPP */
-
- /* Salvage as much info from the existing file as possible */
- if (a_out >= 0)
- {
-#ifdef MSDOS
- /* Support the coff-go32-exe format with a prepended stub, since
- this is what GCC 2.8.0 and later generates by default in DJGPP. */
- unsigned short mz_header[3];
-
- if (read (a_out, &mz_header, sizeof (mz_header)) != sizeof (mz_header))
- {
- PERROR (a_name);
- }
- if (mz_header[0] == 0x5a4d || mz_header[0] == 0x4d5a) /* "MZ" or "ZM" */
- {
- coff_offset = (long)mz_header[2] * 512L;
- if (mz_header[1])
- coff_offset += (long)mz_header[1] - 512L;
- lseek (a_out, coff_offset, 0);
- }
- else
- lseek (a_out, 0L, 0);
-#endif /* MSDOS */
- 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 */
- lseek (a_out, coff_offset + sizeof (f_hdr) + f_hdr.f_opthdr, 0);
- 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. */
-
- f_hdr.f_flags |= (F_RELFLG | F_EXEC);
- f_ohdr.dsize = bss_start - f_ohdr.data_start;
- f_ohdr.bsize = 0;
- f_thdr.s_size = f_ohdr.tsize;
- f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
- f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
- lnnoptr = f_thdr.s_lnnoptr;
- text_scnptr = f_thdr.s_scnptr;
- f_dhdr.s_paddr = f_ohdr.data_start;
- f_dhdr.s_vaddr = f_ohdr.data_start;
- f_dhdr.s_size = f_ohdr.dsize;
- f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
- data_scnptr = f_dhdr.s_scnptr;
- f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
- f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
- f_bhdr.s_size = f_ohdr.bsize;
- f_bhdr.s_scnptr = 0L;
- bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
-
- if (f_hdr.f_symptr > 0L)
- {
- f_hdr.f_symptr += bias;
- }
-
- if (f_thdr.s_lnnoptr > 0L)
- {
- f_thdr.s_lnnoptr += bias;
- }
-
- if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
- {
- PERROR (new_name);
- }
-
- if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
- {
- PERROR (new_name);
- }
-
- if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
- {
- PERROR (new_name);
- }
-
- if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
- {
- PERROR (new_name);
- }
-
- if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
- {
- PERROR (new_name);
- }
-
- return (0);
-
-}
-
-void
-write_segment (int new, const char *ptr, const char *end)
-{
- register int i, nwrite, ret;
- /* This is the normal amount to write at once.
- It is the size of block that NFS uses. */
- int writesize = 1 << 13;
- int pagesize = getpagesize ();
- char zeros[1 << 13];
-
- memset (zeros, 0, sizeof (zeros));
-
- for (i = 0; ptr < end;)
- {
- /* Distance to next multiple of writesize. */
- nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr;
- /* But not beyond specified end. */
- if (nwrite > end - ptr) nwrite = end - ptr;
- ret = write (new, ptr, nwrite);
- /* If write gets a page fault, it means we reached
- a gap between the old text segment and the old data segment.
- This gap has probably been remapped into part of the text segment.
- So write zeros for it. */
- if (ret == -1 && errno == EFAULT)
- {
- /* Write only a page of zeros at once,
- so that we don't overshoot the start
- of the valid memory in the old data segment. */
- if (nwrite > pagesize)
- nwrite = pagesize;
- write (new, zeros, nwrite);
- }
- i += nwrite;
- ptr += nwrite;
- }
-}
-/* ****************************************************************
- * copy_text_and_data
- *
- * Copy the text and data segments from memory to the new a.out
- */
-static int
-copy_text_and_data (int new, int a_out)
-{
- register char *end;
- register char *ptr;
-
-#ifdef MSDOS
- /* Dump the original table of exception handlers, not the one
- where our exception hooks are registered. */
- __djgpp_exception_toggle ();
-
- /* Switch off startup flags that might have been set at runtime
- and which might change the way that dumped Emacs works. */
- save_djgpp_startup_flags = _crt0_startup_flags;
- _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR);
-
- /* Zero out the 'atexit' chain in the dumped executable, to avoid
- calling the atexit functions twice. (emacs.c:main installs an
- atexit function.) */
- save_atexit_ptr = __atexit_ptr;
- __atexit_ptr = NULL;
-#endif
-
- lseek (new, (long) text_scnptr, 0);
- ptr = (char *) f_ohdr.text_start;
- end = ptr + f_ohdr.tsize;
- write_segment (new, ptr, end);
-
- lseek (new, (long) data_scnptr, 0);
- ptr = (char *) f_ohdr.data_start;
- end = ptr + f_ohdr.dsize;
- write_segment (new, ptr, end);
-
-#ifdef MSDOS
- /* Restore our exception hooks. */
- __djgpp_exception_toggle ();
-
- /* Restore the startup flags. */
- _crt0_startup_flags = save_djgpp_startup_flags;
-
- /* Restore the atexit chain. */
- __atexit_ptr = save_atexit_ptr;
-#endif
-
-
- return 0;
-}
-
-/* ****************************************************************
- * copy_sym
- *
- * Copy the relocation information and symbol table from the a.out to the new
- */
-static int
-copy_sym (int new, int a_out, const char *a_name, const char *new_name)
-{
- char page[1024];
- int n;
-
- if (a_out < 0)
- return 0;
-
- if (SYMS_START == 0L)
- return 0;
-
- if (lnnoptr) /* if there is line number info */
- lseek (a_out, coff_offset + lnnoptr, 0); /* start copying from there */
- else
- lseek (a_out, coff_offset + SYMS_START, 0); /* Position a.out to
symtab. */
-
- while ((n = read (a_out, page, sizeof page)) > 0)
- {
- if (write (new, page, n) != n)
- {
- PERROR (new_name);
- }
- }
- if (n < 0)
- {
- PERROR (a_name);
- }
- return 0;
-}
-
-
-/*
- * If the COFF file contains a symbol table and a line number section,
- * then any auxiliary entries that have values for x_lnnoptr must
- * be adjusted by the amount that the line number section has moved
- * in the file (bias computed in make_hdr). The #@$%&* designers of
- * the auxiliary entry structures used the absolute file offsets for
- * the line number entry rather than an offset from the start of the
- * line number section!
- *
- * When I figure out how to scan through the symbol table and pick out
- * the auxiliary entries that need adjustment, this routine will
- * be fixed. As it is now, all such entries are wrong and sdb
- * will complain. Fred Fish, UniSoft Systems Inc.
- */
-
-/* This function is probably very slow. Instead of reopening the new
- file for input and output it should copy from the old to the new
- using the two descriptors already open (WRITEDESC and READDESC).
- Instead of reading one small structure at a time it should use
- a reasonable size buffer. But I don't have time to work on such
- things, so I am installing it as submitted to me. -- RMS. */
-
-int
-adjust_lnnoptrs (int writedesc, int readdesc, const char *new_name)
-{
- register int nsyms;
- register int new;
- struct syment symentry;
- union auxent auxentry;
-
- if (!lnnoptr || !f_hdr.f_symptr)
- return 0;
-
-#ifdef MSDOS
- if ((new = writedesc) < 0)
-#else
- if ((new = emacs_open (new_name, O_RDWR, 0)) < 0)
-#endif
- {
- PERROR (new_name);
- return -1;
- }
-
- lseek (new, f_hdr.f_symptr, 0);
- for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
- {
- read (new, &symentry, SYMESZ);
- if (symentry.n_numaux)
- {
- read (new, &auxentry, AUXESZ);
- nsyms++;
- if (ISFCN (symentry.n_type) || symentry.n_type == 0x2400)
- {
- auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
- lseek (new, -AUXESZ, 1);
- write (new, &auxentry, AUXESZ);
- }
- }
- }
-#ifndef MSDOS
- emacs_close (new);
-#endif
- return 0;
-}
-
-/* ****************************************************************
- * unexec
- *
- * driving logic.
- */
-void
-unexec (const char *new_name, const char *a_name)
-{
- int new = -1, a_out = -1;
-
- if (a_name && (a_out = emacs_open (a_name, O_RDONLY, 0)) < 0)
- {
- PERROR (a_name);
- }
- if ((new = emacs_open (new_name, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0)
- {
- PERROR (new_name);
- }
-
- if (make_hdr (new, a_out, a_name, new_name) < 0
- || copy_text_and_data (new, a_out) < 0
- || copy_sym (new, a_out, a_name, new_name) < 0
- || adjust_lnnoptrs (new, a_out, new_name) < 0
- )
- {
- emacs_close (new);
- return;
- }
-
- emacs_close (new);
- if (a_out >= 0)
- emacs_close (a_out);
-}
-
-#endif /* HAVE_UNEXEC */
diff --git a/src/unexcw.c b/src/unexcw.c
deleted file mode 100644
index 5c91498cc6c..00000000000
--- a/src/unexcw.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* unexec() support for Cygwin;
- complete rewrite of xemacs Cygwin unexec() code
-
- Copyright (C) 2004-2024 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs 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 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-#include <config.h>
-#include "unexec.h"
-#include "lisp.h"
-#include <stdio.h>
-#include <fcntl.h>
-#include <a.out.h>
-#include <unistd.h>
-#include <assert.h>
-
-#define DOTEXE ".exe"
-
-/*
-** header for Windows executable files
-*/
-typedef struct
-{
- FILHDR file_header;
- PEAOUTHDR file_optional_header;
- SCNHDR section_header[32];
-} exe_header_t;
-
-int debug_unexcw = 0;
-
-/*
-** Read the header from the executable into memory so we can more easily
access it.
-*/
-static exe_header_t *
-read_exe_header (int fd, exe_header_t * exe_header_buffer)
-{
- int i;
- MAYBE_UNUSED int ret;
-
- assert (fd >= 0);
- assert (exe_header_buffer != 0);
-
- ret = lseek (fd, 0L, SEEK_SET);
- assert (ret != -1);
-
- ret =
- read (fd, &exe_header_buffer->file_header,
- sizeof (exe_header_buffer->file_header));
- assert (ret == sizeof (exe_header_buffer->file_header));
-
- assert (exe_header_buffer->file_header.e_magic == 0x5a4d);
- assert (exe_header_buffer->file_header.nt_signature == 0x4550);
-#ifdef __x86_64__
- assert (exe_header_buffer->file_header.f_magic == 0x8664);
-#else
- assert (exe_header_buffer->file_header.f_magic == 0x014c);
-#endif
- assert (exe_header_buffer->file_header.f_nscns > 0);
- assert (exe_header_buffer->file_header.f_nscns <=
- ARRAYELTS (exe_header_buffer->section_header));
- assert (exe_header_buffer->file_header.f_opthdr > 0);
-
- ret =
- read (fd, &exe_header_buffer->file_optional_header,
- sizeof (exe_header_buffer->file_optional_header));
- assert (ret == sizeof (exe_header_buffer->file_optional_header));
-
-#ifdef __x86_64__
- assert (exe_header_buffer->file_optional_header.magic == 0x020b);
-#else
- assert (exe_header_buffer->file_optional_header.magic == 0x010b);
-#endif
-
- for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
- {
- ret =
- read (fd, &exe_header_buffer->section_header[i],
- sizeof (exe_header_buffer->section_header[i]));
- assert (ret == sizeof (exe_header_buffer->section_header[i]));
- }
-
- return (exe_header_buffer);
-}
-
-/*
-** Fix the dumped emacs executable:
-**
-** - copy .data section data of interest from running executable into
-** output .exe file
-**
-** - convert .bss section into an initialized data section (like
-** .data) and copy .bss section data of interest from running
-** executable into output .exe file
-*/
-static void
-fixup_executable (int fd)
-{
- exe_header_t exe_header_buffer;
- exe_header_t *exe_header;
- int i;
- MAYBE_UNUSED int ret;
- int found_data = 0;
- int found_bss = 0;
-
- exe_header = read_exe_header (fd, &exe_header_buffer);
- assert (exe_header != 0);
-
- assert (exe_header->file_header.f_nscns > 0);
- for (i = 0; i < exe_header->file_header.f_nscns; ++i)
- {
- unsigned long start_address =
- exe_header->section_header[i].s_vaddr +
- exe_header->file_optional_header.ImageBase;
- unsigned long end_address =
- exe_header->section_header[i].s_vaddr +
- exe_header->file_optional_header.ImageBase +
- exe_header->section_header[i].s_paddr;
- if (debug_unexcw)
- printf ("%8s start %#lx end %#lx\n",
- exe_header->section_header[i].s_name,
- start_address, end_address);
- if (my_edata >= (char *) start_address
- && my_edata < (char *) end_address)
- {
- /* data section */
- ret =
- lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
- SEEK_SET);
- assert (ret != -1);
- ret =
- write (fd, (char *) start_address,
- my_edata - (char *) start_address);
- assert (ret == my_edata - (char *) start_address);
- ++found_data;
- if (debug_unexcw)
- printf (" .data, mem start %#lx mem length %td\n",
- start_address, my_edata - (char *) start_address);
- if (debug_unexcw)
- printf (" .data, file start %d file length %d\n",
- (int) exe_header->section_header[i].s_scnptr,
- (int) exe_header->section_header[i].s_paddr);
- }
- else if (my_endbss >= (char *) start_address
- && my_endbss < (char *) end_address)
- {
- /* bss section */
- ++found_bss;
- if (exe_header->section_header[i].s_flags & 0x00000080)
- {
- /* convert uninitialized data section to initialized data section
*/
- struct stat statbuf;
- ret = fstat (fd, &statbuf);
- assert (ret != -1);
-
- exe_header->section_header[i].s_flags &= ~0x00000080;
- exe_header->section_header[i].s_flags |= 0x00000040;
-
- exe_header->section_header[i].s_scnptr =
- (statbuf.st_size +
- exe_header->file_optional_header.FileAlignment) /
- exe_header->file_optional_header.FileAlignment *
- exe_header->file_optional_header.FileAlignment;
-
- exe_header->section_header[i].s_size =
- (exe_header->section_header[i].s_paddr +
- exe_header->file_optional_header.FileAlignment) /
- exe_header->file_optional_header.FileAlignment *
- exe_header->file_optional_header.FileAlignment;
-
- /* Make sure the generated bootstrap binary isn't
- * sparse. NT doesn't use a file cache for sparse
- * executables, so if we bootstrap Emacs using a sparse
- * bootstrap-emacs.exe, bootstrap takes about twenty
- * times longer than it would otherwise. */
-
- ret = posix_fallocate (fd,
- ( exe_header->section_header[i].s_scnptr +
- exe_header->section_header[i].s_size ),
- 1);
-
- assert (ret != -1);
-
- ret =
- lseek (fd,
- (long) (exe_header->section_header[i].s_scnptr +
- exe_header->section_header[i].s_size - 1),
- SEEK_SET);
- assert (ret != -1);
- ret = write (fd, "", 1);
- assert (ret == 1);
-
- ret =
- lseek (fd,
- (long) ((char *) &exe_header->section_header[i] -
- (char *) exe_header), SEEK_SET);
- assert (ret != -1);
- ret =
- write (fd, &exe_header->section_header[i],
- sizeof (exe_header->section_header[i]));
- assert (ret == sizeof (exe_header->section_header[i]));
- if (debug_unexcw)
- printf (" seek to %ld, write %zu\n",
- (long) ((char *) &exe_header->section_header[i] -
- (char *) exe_header),
- sizeof (exe_header->section_header[i]));
- }
- /* write initialized data section */
- ret =
- lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
- SEEK_SET);
- assert (ret != -1);
- ret =
- write (fd, (char *) start_address,
- my_endbss - (char *) start_address);
- assert (ret == (my_endbss - (char *) start_address));
- if (debug_unexcw)
- printf (" .bss, mem start %#lx mem length %td\n",
- start_address, my_endbss - (char *) start_address);
- if (debug_unexcw)
- printf (" .bss, file start %d file length %d\n",
- (int) exe_header->section_header[i].s_scnptr,
- (int) exe_header->section_header[i].s_paddr);
- }
- }
- assert (found_bss == 1);
- assert (found_data == 1);
-}
-
-/*
-** Windows likes .exe suffixes on executables.
-*/
-static char *
-add_exe_suffix_if_necessary (const char *name, char *modified)
-{
- int i = strlen (name);
- if (i <= (sizeof (DOTEXE) - 1))
- {
- sprintf (modified, "%s%s", name, DOTEXE);
- }
- else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
- {
- strcpy (modified, name);
- }
- else
- {
- sprintf (modified, "%s%s", name, DOTEXE);
- }
- return (modified);
-}
-
-void
-unexec (const char *outfile, const char *infile)
-{
- char infile_buffer[FILENAME_MAX];
- char outfile_buffer[FILENAME_MAX];
- int fd_in;
- int fd_out;
- int ret;
- MAYBE_UNUSED int ret2;
-
- infile = add_exe_suffix_if_necessary (infile, infile_buffer);
- outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
-
- fd_in = emacs_open (infile, O_RDONLY, 0);
- assert (fd_in >= 0);
- fd_out = emacs_open (outfile, O_RDWR | O_TRUNC | O_CREAT, 0755);
- assert (fd_out >= 0);
- for (;;)
- {
- char buffer[4096];
- ret = read (fd_in, buffer, sizeof (buffer));
- if (ret == 0)
- {
- /* eof */
- break;
- }
- assert (ret > 0);
- /* data */
- ret2 = write (fd_out, buffer, ret);
- assert (ret2 == ret);
- }
- ret = emacs_close (fd_in);
- assert (ret == 0);
-
- fixup_executable (fd_out);
-
- ret = emacs_close (fd_out);
- assert (ret == 0);
-}
diff --git a/src/unexec.h b/src/unexec.h
deleted file mode 100644
index cdb2e8016ea..00000000000
--- a/src/unexec.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef EMACS_UNEXEC_H
-#define EMACS_UNEXEC_H
-void unexec (const char *, const char *);
-#endif /* EMACS_UNEXEC_H */
diff --git a/src/unexelf.c b/src/unexelf.c
deleted file mode 100644
index a9a8f2d6ce9..00000000000
--- a/src/unexelf.c
+++ /dev/null
@@ -1,659 +0,0 @@
-/* Copyright (C) 1985-1988, 1990, 1992, 1999-2024 Free Software
- Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs 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 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-/*
-In other words, you are welcome to use, share and improve this program.
-You are forbidden to forbid anyone else to use, share and improve
-what 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 (const char *new_name, const char *old_name);
- *
- * Takes a snapshot of the program and makes an a.out format file in the
- * file named by the string argument new_name.
- * If old_name is non-NULL, the symbol table will be taken from the given file.
- * On some machines, an existing old_name file is required.
- *
- */
-
-/* We do not use mmap because that fails with NFS.
- Instead we read the whole file, modify it, and write it out. */
-
-#include <config.h>
-#include "unexec.h"
-#include "lisp.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <memory.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#ifdef __QNX__
-# include <sys/elf.h>
-#elif !defined __NetBSD__ && !defined __OpenBSD__
-# include <elf.h>
-#endif
-#include <sys/mman.h>
-#if defined (_SYSTYPE_SYSV)
-#include <sys/elf_mips.h>
-#include <sym.h>
-#endif /* _SYSTYPE_SYSV */
-
-#ifndef MAP_ANON
-#ifdef MAP_ANONYMOUS
-#define MAP_ANON MAP_ANONYMOUS
-#else
-#define MAP_ANON 0
-#endif
-#endif
-
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *) -1)
-#endif
-
-#if defined (__alpha__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
-/* Declare COFF debugging symbol table. This used to be in
- /usr/include/sym.h, but this file is no longer included in Red Hat
- 5.0 and presumably in any other glibc 2.x based distribution. */
-typedef struct {
- short magic;
- short vstamp;
- int ilineMax;
- int idnMax;
- int ipdMax;
- int isymMax;
- int ioptMax;
- int iauxMax;
- int issMax;
- int issExtMax;
- int ifdMax;
- int crfd;
- int iextMax;
- long cbLine;
- long cbLineOffset;
- long cbDnOffset;
- long cbPdOffset;
- long cbSymOffset;
- long cbOptOffset;
- long cbAuxOffset;
- long cbSsOffset;
- long cbSsExtOffset;
- long cbFdOffset;
- long cbRfdOffset;
- long cbExtOffset;
-} HDRR, *pHDRR;
-#define cbHDRR sizeof (HDRR)
-#define hdrNil ((pHDRR)0)
-#endif
-
-#ifdef __NetBSD__
-/*
- * NetBSD does not have normal-looking user-land ELF support.
- */
-# if defined __alpha__ || defined __sparc_v9__ || defined _LP64
-# define ELFSIZE 64
-# else
-# define ELFSIZE 32
-# endif
-# include <sys/exec_elf.h>
-
-# ifndef PT_LOAD
-# define PT_LOAD Elf_pt_load
-# if 0 /* was in pkgsrc
patches for 20.7 */
-# define SHT_PROGBITS Elf_sht_progbits
-# endif
-# define SHT_SYMTAB Elf_sht_symtab
-# define SHT_DYNSYM Elf_sht_dynsym
-# define SHT_NULL Elf_sht_null
-# define SHT_NOBITS Elf_sht_nobits
-# define SHT_REL Elf_sht_rel
-# define SHT_RELA Elf_sht_rela
-
-# define SHN_UNDEF Elf_eshn_undefined
-# define SHN_ABS Elf_eshn_absolute
-# define SHN_COMMON Elf_eshn_common
-# endif /* !PT_LOAD */
-
-# ifdef __alpha__
-# include <sys/exec_ecoff.h>
-# define HDRR struct ecoff_symhdr
-# define pHDRR HDRR *
-# endif /* __alpha__ */
-
-#ifdef __mips__ /* was in pkgsrc patches for 20.7 */
-# define SHT_MIPS_DEBUG DT_MIPS_FLAGS
-# define HDRR struct Elf_Shdr
-#endif /* __mips__ */
-#endif /* __NetBSD__ */
-
-#ifdef __OpenBSD__
-# include <sys/exec_elf.h>
-#endif
-
-#if __GNU_LIBRARY__ - 0 >= 6
-# include <link.h> /* get ElfW etc */
-#endif
-
-#ifndef ElfW
-# define ElfBitsW(bits, type) Elf##bits##_##type
-# ifndef ELFSIZE
-# ifdef _LP64
-# define ELFSIZE 64
-# else
-# define ELFSIZE 32
-# endif
-# endif
- /* This macro expands `bits' before invoking ElfBitsW. */
-# define ElfExpandBitsW(bits, type) ElfBitsW (bits, type)
-# define ElfW(type) ElfExpandBitsW (ELFSIZE, type)
-#endif
-
-/* The code often converts ElfW (Half) values like e_shentsize to ptrdiff_t;
- check that this doesn't lose information. */
-#include <intprops.h>
-#include <verify.h>
-verify ((! TYPE_SIGNED (ElfW (Half))
- || PTRDIFF_MIN <= TYPE_MINIMUM (ElfW (Half)))
- && TYPE_MAXIMUM (ElfW (Half)) <= PTRDIFF_MAX);
-
-#ifdef UNEXELF_DEBUG
-# define DEBUG_LOG(expr) fprintf (stderr, #expr " 0x%"PRIxMAX"\n", \
- (uintmax_t) (expr))
-#endif
-
-/* Get the address of a particular section or program header entry,
- * accounting for the size of the entries.
- */
-
-static void *
-entry_address (void *section_h, ptrdiff_t idx, ptrdiff_t entsize)
-{
- char *h = section_h;
- return h + idx * entsize;
-}
-
-#define OLD_SECTION_H(n) \
- (*(ElfW (Shdr) *) entry_address (old_section_h, n, old_file_h->e_shentsize))
-#define NEW_SECTION_H(n) \
- (*(ElfW (Shdr) *) entry_address (new_section_h, n, new_file_h->e_shentsize))
-#define OLD_PROGRAM_H(n) \
- (*(ElfW (Phdr) *) entry_address (old_program_h, n, old_file_h->e_phentsize))
-
-typedef unsigned char byte;
-
-/* ****************************************************************
- * unexec
- *
- * driving logic.
- *
- * In ELF, this works by replacing the old bss SHT_NOBITS section with
- * a new, larger, SHT_PROGBITS section.
- *
- */
-void
-unexec (const char *new_name, const char *old_name)
-{
- int new_file, old_file;
- off_t new_file_size;
-
- /* Pointers to the base of the image of the two files. */
- caddr_t old_base, new_base;
-
-#if MAP_ANON == 0
- int mmap_fd;
-#else
-# define mmap_fd -1
-#endif
-
- /* Pointers to the file, program and section headers for the old and
- new files. */
- ElfW (Ehdr) *old_file_h, *new_file_h;
- ElfW (Phdr) *old_program_h, *new_program_h;
- ElfW (Shdr) *old_section_h, *new_section_h;
-
- /* Point to the section name table. */
- char *old_section_names, *new_section_names;
-
- ElfW (Phdr) *old_bss_seg, *new_bss_seg;
- ElfW (Addr) old_bss_addr, new_bss_addr;
- ElfW (Word) old_bss_size, bss_size_growth, new_data2_size;
- ElfW (Off) old_bss_offset, new_data2_offset;
-
- ptrdiff_t n;
- ptrdiff_t old_bss_index;
- struct stat stat_buf;
- off_t old_file_size;
-
- /* Open the old file, allocate a buffer of the right size, and read
- in the file contents. */
-
- old_file = emacs_open (old_name, O_RDONLY, 0);
-
- if (old_file < 0)
- fatal ("Can't open %s for reading: %s", old_name, strerror (errno));
-
- if (fstat (old_file, &stat_buf) != 0)
- fatal ("Can't fstat (%s): %s", old_name, strerror (errno));
-
-#if MAP_ANON == 0
- mmap_fd = emacs_open ("/dev/zero", O_RDONLY, 0);
- if (mmap_fd < 0)
- fatal ("Can't open /dev/zero for reading: %s", strerror (errno));
-#endif
-
- /* We cannot use malloc here because that may use sbrk. If it does,
- we'd dump our temporary buffers with Emacs, and we'd have to be
- extra careful to use the correct value of sbrk(0) after
- allocating all buffers in the code below, which we aren't. */
- old_file_size = stat_buf.st_size;
- if (! (0 <= old_file_size && old_file_size <= SIZE_MAX))
- fatal ("File size out of range");
- old_base = mmap (NULL, old_file_size, PROT_READ | PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
- if (old_base == MAP_FAILED)
- fatal ("Can't allocate buffer for %s: %s", old_name, strerror (errno));
-
- if (read (old_file, old_base, old_file_size) != old_file_size)
- fatal ("Didn't read all of %s: %s", old_name, strerror (errno));
-
- /* Get pointers to headers & section names */
-
- old_file_h = (ElfW (Ehdr) *) old_base;
- old_program_h = (ElfW (Phdr) *) ((byte *) old_base + old_file_h->e_phoff);
- old_section_h = (ElfW (Shdr) *) ((byte *) old_base + old_file_h->e_shoff);
- old_section_names = (char *) old_base
- + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
-
- /* Find the PT_LOAD header covering the highest address. This
- segment will be where bss sections are located, past p_filesz. */
- old_bss_seg = 0;
- for (n = old_file_h->e_phnum; --n >= 0; )
- {
- ElfW (Phdr) *seg = &OLD_PROGRAM_H (n);
- if (seg->p_type == PT_LOAD
- && (old_bss_seg == 0
- || seg->p_vaddr > old_bss_seg->p_vaddr))
- old_bss_seg = seg;
- }
- eassume (old_bss_seg);
- if (!old_bss_seg)
- emacs_abort ();
-
- /* Note that old_bss_addr may be lower than the first bss section
- address, since the section may need aligning. */
- old_bss_addr = old_bss_seg->p_vaddr + old_bss_seg->p_filesz;
- old_bss_offset = old_bss_seg->p_offset + old_bss_seg->p_filesz;
- old_bss_size = old_bss_seg->p_memsz - old_bss_seg->p_filesz;
-
- /* Find the last bss style section in the bss segment range. */
- old_bss_index = -1;
- for (n = old_file_h->e_shnum; --n > 0; )
- {
- ElfW (Shdr) *shdr = &OLD_SECTION_H (n);
- if (shdr->sh_type == SHT_NOBITS
- && shdr->sh_addr >= old_bss_addr
- && shdr->sh_addr + shdr->sh_size <= old_bss_addr + old_bss_size
- && (old_bss_index == -1
- || OLD_SECTION_H (old_bss_index).sh_addr < shdr->sh_addr))
- old_bss_index = n;
- }
-
- if (old_bss_index == -1)
- fatal ("no bss section found");
-
- void *no_break = (void *) (intptr_t) -1;
- void *new_break = no_break;
-#ifdef HAVE_SBRK
- new_break = sbrk (0);
-#endif
- if (new_break == no_break)
- new_break = (byte *) old_bss_addr + old_bss_size;
- new_bss_addr = (ElfW (Addr)) new_break;
- bss_size_growth = new_bss_addr - old_bss_addr;
- new_data2_size = bss_size_growth;
- new_data2_size += alignof (ElfW (Shdr)) - 1;
- new_data2_size -= new_data2_size % alignof (ElfW (Shdr));
-
- new_data2_offset = old_bss_offset;
-
-#ifdef UNEXELF_DEBUG
- fprintf (stderr, "old_bss_index %td\n", old_bss_index);
- DEBUG_LOG (old_bss_addr);
- DEBUG_LOG (old_bss_size);
- DEBUG_LOG (old_bss_offset);
- DEBUG_LOG (new_bss_addr);
- DEBUG_LOG (new_data2_size);
- DEBUG_LOG (new_data2_offset);
-#endif
-
- if (new_bss_addr < old_bss_addr + old_bss_size)
- fatal (".bss shrank when undumping");
-
- /* Set the output file to the right size. Allocate a buffer to hold
- the image of the new file. Set pointers to various interesting
- objects. */
-
- new_file = emacs_open (new_name, O_RDWR | O_CREAT, 0777);
- if (new_file < 0)
- fatal ("Can't creat (%s): %s", new_name, strerror (errno));
-
- new_file_size = old_file_size + new_data2_size;
-
- if (ftruncate (new_file, new_file_size))
- fatal ("Can't ftruncate (%s): %s", new_name, strerror (errno));
-
- new_base = mmap (NULL, new_file_size, PROT_READ | PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
- if (new_base == MAP_FAILED)
- fatal ("Can't allocate buffer for %s: %s", old_name, strerror (errno));
-
- /* Make our new file, program and section headers as copies of the
- originals. */
-
- new_file_h = (ElfW (Ehdr) *) new_base;
- memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
-
- /* Fix up file header. Section header is further away now. */
-
- if (new_file_h->e_shoff >= old_bss_offset)
- new_file_h->e_shoff += new_data2_size;
-
- new_program_h = (ElfW (Phdr) *) ((byte *) new_base + new_file_h->e_phoff);
- new_section_h = (ElfW (Shdr) *) ((byte *) new_base + new_file_h->e_shoff);
-
- memcpy (new_program_h, old_program_h,
- old_file_h->e_phnum * old_file_h->e_phentsize);
- memcpy (new_section_h, old_section_h,
- old_file_h->e_shnum * old_file_h->e_shentsize);
-
-#ifdef UNEXELF_DEBUG
- DEBUG_LOG (old_file_h->e_shoff);
- fprintf (stderr, "Old section count %td\n", (ptrdiff_t) old_file_h->e_shnum);
- DEBUG_LOG (new_file_h->e_shoff);
- fprintf (stderr, "New section count %td\n", (ptrdiff_t) new_file_h->e_shnum);
-#endif
-
- /* Fix up program header. Extend the writable data segment so
- that the bss area is covered too. */
-
- new_bss_seg = new_program_h + (old_bss_seg - old_program_h);
- new_bss_seg->p_filesz = new_bss_addr - new_bss_seg->p_vaddr;
- new_bss_seg->p_memsz = new_bss_seg->p_filesz;
-
- /* Copy over what we have in memory now for the bss area. */
- memcpy (new_base + new_data2_offset, (caddr_t) old_bss_addr,
- bss_size_growth);
-
- /* Walk through all section headers, copying data and updating. */
- for (n = 1; n < old_file_h->e_shnum; n++)
- {
- caddr_t src;
- ElfW (Shdr) *old_shdr = &OLD_SECTION_H (n);
- ElfW (Shdr) *new_shdr = &NEW_SECTION_H (n);
-
- if (new_shdr->sh_type == SHT_NOBITS
- && new_shdr->sh_addr >= old_bss_addr
- && (new_shdr->sh_addr + new_shdr->sh_size
- <= old_bss_addr + old_bss_size))
- {
- /* This section now has file backing. */
- new_shdr->sh_type = SHT_PROGBITS;
-
- /* SHT_NOBITS sections do not need a valid sh_offset, so it
- might be incorrect. Write the correct value. */
- new_shdr->sh_offset = (new_shdr->sh_addr - new_bss_seg->p_vaddr
- + new_bss_seg->p_offset);
-
- /* If this is was a SHT_NOBITS .plt section, then it is
- probably a PowerPC PLT. If it is PowerPC64 ELFv1 then
- glibc ld.so doesn't initialize the toc pointer word. A
- non-zero toc pointer word can defeat Power7 thread safety
- during lazy update of a PLT entry. This only matters if
- emacs becomes multi-threaded. */
- if (strcmp (old_section_names + new_shdr->sh_name, ".plt") == 0)
- memset (new_shdr->sh_offset + new_base, 0, new_shdr->sh_size);
-
- /* Extend the size of the last bss section to cover dumped
- data. */
- if (n == old_bss_index)
- new_shdr->sh_size = new_bss_addr - new_shdr->sh_addr;
-
- /* We have already copied this section from the current
- process. */
- continue;
- }
-
- /* Any section that was originally placed after the .bss
- section should now be offset by NEW_DATA2_SIZE. */
- if (new_shdr->sh_offset >= old_bss_offset)
- new_shdr->sh_offset += new_data2_size;
-
- /* Now, start to copy the content of sections. */
- if (new_shdr->sh_type == SHT_NULL
- || new_shdr->sh_type == SHT_NOBITS)
- continue;
-
- /* Some sections are copied from the current process instead of
- the old file. */
- if (!strcmp (old_section_names + new_shdr->sh_name, ".data")
- || !strcmp (old_section_names + new_shdr->sh_name, ".sdata")
- || !strcmp (old_section_names + new_shdr->sh_name, ".lit4")
- || !strcmp (old_section_names + new_shdr->sh_name, ".lit8")
- || !strcmp (old_section_names + new_shdr->sh_name, ".sdata1")
- || !strcmp (old_section_names + new_shdr->sh_name, ".data1"))
- src = (caddr_t) old_shdr->sh_addr;
- else
- src = old_base + old_shdr->sh_offset;
-
- memcpy (new_shdr->sh_offset + new_base, src, new_shdr->sh_size);
-
-#if (defined __alpha__ && !defined __OpenBSD__) || defined _SYSTYPE_SYSV
- /* Update Alpha and MIPS COFF debug symbol table. */
- if (strcmp (old_section_names + new_shdr->sh_name, ".mdebug") == 0
- && new_shdr->sh_offset - old_shdr->sh_offset != 0
-#if defined _SYSTYPE_SYSV
- && new_shdr->sh_type == SHT_MIPS_DEBUG
-#endif
- )
- {
- ptrdiff_t diff = new_shdr->sh_offset - old_shdr->sh_offset;
- HDRR *phdr = (HDRR *) (new_shdr->sh_offset + new_base);
-
- phdr->cbLineOffset += diff;
- phdr->cbDnOffset += diff;
- phdr->cbPdOffset += diff;
- phdr->cbSymOffset += diff;
- phdr->cbOptOffset += diff;
- phdr->cbAuxOffset += diff;
- phdr->cbSsOffset += diff;
- phdr->cbSsExtOffset += diff;
- phdr->cbFdOffset += diff;
- phdr->cbRfdOffset += diff;
- phdr->cbExtOffset += diff;
- }
-#endif /* __alpha__ || _SYSTYPE_SYSV */
- }
-
- /* Update the symbol values of _edata and _end. */
- for (n = new_file_h->e_shnum; 0 < --n; )
- {
- byte *symnames;
- ElfW (Sym) *symp, *symendp;
- ElfW (Shdr) *sym_shdr = &NEW_SECTION_H (n);
-
- if (sym_shdr->sh_type != SHT_DYNSYM
- && sym_shdr->sh_type != SHT_SYMTAB)
- continue;
-
- symnames = ((byte *) new_base
- + NEW_SECTION_H (sym_shdr->sh_link).sh_offset);
- symp = (ElfW (Sym) *) (sym_shdr->sh_offset + new_base);
- symendp = (ElfW (Sym) *) ((byte *) symp + sym_shdr->sh_size);
-
- for (; symp < symendp; symp ++)
- {
- if (strcmp ((char *) (symnames + symp->st_name), "_end") == 0
- || strcmp ((char *) (symnames + symp->st_name), "end") == 0
- || strcmp ((char *) (symnames + symp->st_name), "_edata") == 0
- || strcmp ((char *) (symnames + symp->st_name), "edata") == 0)
- memcpy (&symp->st_value, &new_bss_addr, sizeof (new_bss_addr));
-
- /* Strictly speaking, #ifdef below is not necessary. But we
- keep it to indicate that this kind of change may also be
- necessary for other unexecs to support GNUstep. */
-#ifdef NS_IMPL_GNUSTEP
- /* ObjC runtime modifies the values of some data structures
- such as classes and selectors in the .data section after
- loading. As the dump process copies the .data section
- from the current process, that causes problems when the
- modified classes are reinitialized in the dumped
- executable. We copy such data from the old file, not
- from the current process. */
- if (strncmp ((char *) (symnames + symp->st_name),
- "_OBJC_", sizeof ("_OBJC_") - 1) == 0)
- {
- ElfW (Shdr) *new_shdr = &NEW_SECTION_H (symp->st_shndx);
- if (new_shdr->sh_type != SHT_NOBITS)
- {
- ElfW (Shdr) *old_shdr = &OLD_SECTION_H (symp->st_shndx);
- ptrdiff_t reladdr = symp->st_value - new_shdr->sh_addr;
- ptrdiff_t newoff = reladdr + new_shdr->sh_offset;
-
- if (old_shdr->sh_type == SHT_NOBITS)
- memset (new_base + newoff, 0, symp->st_size);
- else
- {
- ptrdiff_t oldoff = reladdr + old_shdr->sh_offset;
- memcpy (new_base + newoff, old_base + oldoff,
- symp->st_size);
- }
- }
- }
-#endif
- }
- }
-
- /* Modify the names of sections we changed from SHT_NOBITS to
- SHT_PROGBITS. This is really just cosmetic, but some tools that
- (wrongly) operate on section names rather than types might be
- confused by a SHT_PROGBITS .bss section. */
- new_section_names = ((char *) new_base
- + NEW_SECTION_H (new_file_h->e_shstrndx).sh_offset);
- for (n = new_file_h->e_shnum; 0 < --n; )
- {
- ElfW (Shdr) *old_shdr = &OLD_SECTION_H (n);
- ElfW (Shdr) *new_shdr = &NEW_SECTION_H (n);
-
- /* Replace the leading '.' with ','. When .shstrtab is string
- merged this will rename both .bss and .rela.bss to ,bss and
- .rela,bss. */
- if (old_shdr->sh_type == SHT_NOBITS
- && new_shdr->sh_type == SHT_PROGBITS)
- *(new_section_names + new_shdr->sh_name) = ',';
- }
-
- /* This loop seeks out relocation sections for the data section, so
- that it can undo relocations performed by the runtime loader.
-
- The following approach does not work on x86 platforms that use
- the GNU Gold linker, which can generate .rel.dyn relocation
- sections containing R_386_32 entries that the following code does
- not grok. Emacs works around this problem by avoiding C
- constructs that generate such entries, which is horrible hack.
-
- FIXME: Presumably more problems like this will crop up as linkers
- get fancier. We really need to stop assuming that Emacs can grok
- arbitrary linker output. See Bug#27248. */
- for (n = new_file_h->e_shnum; 0 < --n; )
- {
- ElfW (Shdr) *rel_shdr = &NEW_SECTION_H (n);
- ElfW (Shdr) *shdr;
-
- switch (rel_shdr->sh_type)
- {
- default:
- break;
- case SHT_REL:
- case SHT_RELA:
- /* This code handles two different size structs, but there should
- be no harm in that provided that r_offset is always the first
- member. */
- shdr = &NEW_SECTION_H (rel_shdr->sh_info);
- if (!strcmp (old_section_names + shdr->sh_name, ".data")
- || !strcmp (old_section_names + shdr->sh_name, ".sdata")
- || !strcmp (old_section_names + shdr->sh_name, ".lit4")
- || !strcmp (old_section_names + shdr->sh_name, ".lit8")
- || !strcmp (old_section_names + shdr->sh_name, ".sdata1")
- || !strcmp (old_section_names + shdr->sh_name, ".data1"))
- {
- ElfW (Addr) offset = shdr->sh_addr - shdr->sh_offset;
- caddr_t reloc = old_base + rel_shdr->sh_offset, end;
- for (end = reloc + rel_shdr->sh_size;
- reloc < end;
- reloc += rel_shdr->sh_entsize)
- {
- ElfW (Addr) addr = ((ElfW (Rel) *) reloc)->r_offset - offset;
- /* Ignore R_*_NONE relocs. */
- if (((ElfW (Rel) *) reloc)->r_offset == 0)
- continue;
- /* Assume reloc applies to a word.
- ??? This is not always true, eg. TLS module/index
- pair in .got which occupies two words. */
- memcpy (new_base + addr, old_base + addr,
- sizeof (ElfW (Addr)));
- }
- }
- break;
- }
- }
-
- /* Write out new_file, and free the buffers. */
-
- if (write (new_file, new_base, new_file_size) != new_file_size)
- fatal ("Didn't write %lu bytes to %s: %s",
- (unsigned long) new_file_size, new_name, strerror (errno));
- munmap (old_base, old_file_size);
- munmap (new_base, new_file_size);
-
- /* Close the files and make the new file executable. */
-
-#if MAP_ANON == 0
- emacs_close (mmap_fd);
-#endif
-
- if (emacs_close (old_file) != 0)
- fatal ("Can't close (%s): %s", old_name, strerror (errno));
-
- if (emacs_close (new_file) != 0)
- fatal ("Can't close (%s): %s", new_name, strerror (errno));
-}
diff --git a/src/unexhp9k800.c b/src/unexhp9k800.c
deleted file mode 100644
index d2943eb18c9..00000000000
--- a/src/unexhp9k800.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/* Unexec for HP 9000 Series 800 machines.
-
- This file is in the public domain.
-
- Author: John V. Morris
-
- This file was written by John V. Morris at Hewlett Packard.
- Both the author and Hewlett Packard Co. have disclaimed the
- copyright on this file, and it is therefore in the public domain.
- (Search for "hp9k800" in copyright.list.)
-*/
-
-/*
- Bob Desinger <hpsemc!bd@hplabs.hp.com>
-
- Note that the GNU project considers support for HP operation a
- peripheral activity which should not be allowed to divert effort
- from development of the GNU system. Changes in this code will be
- installed when users send them in, but aside from that we don't
- plan to think about it, or about whether other Emacs maintenance
- might break it.
-
-
- Unexec creates a copy of the old a.out file, and replaces the old data
- area with the current data area. When the new file is executed, the
- process will see the same data structures and data values that the
- original process had when unexec was called.
-
- Unlike other versions of unexec, this one copies symbol table and
- debug information to the new a.out file. Thus, the new a.out file
- may be debugged with symbolic debuggers.
-
- If you fix any bugs in this, I'd like to incorporate your fixes.
- Send them to uunet!hpda!hpsemc!jmorris or jmorris%hpsemc@hplabs.HP.COM.
-
- CAVEATS:
- This routine saves the current value of all static and external
- variables. This means that any data structure that needs to be
- initialized must be explicitly reset. Variables will not have their
- expected default values.
-
- Unfortunately, the HP-UX signal handler has internal initialization
- flags which are not explicitly reset. Thus, for signals to work in
- conjunction with this routine, the following code must executed when
- the new process starts up.
-
- void _sigreturn ();
- ...
- sigsetreturn (_sigreturn);
-*/
-
-#include <config.h>
-#include "unexec.h"
-#include "lisp.h"
-#include "sysstdio.h"
-
-#include <fcntl.h>
-#include <errno.h>
-#include <a.out.h>
-#include <dl.h>
-
-/* brk value to restore, stored as a global.
- This is really used only if we used shared libraries. */
-static long brk_on_dump = 0;
-
-/* Called from main, if we use shared libraries. */
-int
-run_time_remap (char *ignored)
-{
- brk ((char *) brk_on_dump);
-}
-
-#undef roundup
-#define roundup(x,n) (((x) + ((n) - 1)) & ~((n) - 1)) /* n is power of 2 */
-
-/* Report a fatal error and exit. */
-static _Noreturn void
-unexec_error (char const *msg)
-{
- perror (msg);
- exit (1);
-}
-
-/* Do an lseek and check the result. */
-static void
-check_lseek (int fd, off_t offset, int whence)
-{
- if (lseek (fd, offset, whence) < 0)
- unexec_error ("Cannot lseek");
-}
-
-/* Save current data space in the file, update header. */
-
-static void
-save_data_space (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr,
- int size)
-{
- /* Write the entire data space out to the file */
- if (write (file, auxhdr->exec_dmem, size) != size)
- unexec_error ("Can't save new data space");
-
- /* Update the header to reflect the new data size */
- auxhdr->exec_dsize = size;
- auxhdr->exec_bsize = 0;
-}
-
-/* Update the values of file pointers when something is inserted. */
-
-static void
-update_file_ptrs (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr,
- unsigned int location, int offset)
-{
- struct subspace_dictionary_record subspace;
- int i;
-
- /* Increase the overall size of the module */
- hdr->som_length += offset;
-
- /* Update the various file pointers in the header */
-#define update(ptr) if (ptr > location) ptr = ptr + offset
- update (hdr->aux_header_location);
- update (hdr->space_strings_location);
- update (hdr->init_array_location);
- update (hdr->compiler_location);
- update (hdr->symbol_location);
- update (hdr->fixup_request_location);
- update (hdr->symbol_strings_location);
- update (hdr->unloadable_sp_location);
- update (auxhdr->exec_tfile);
- update (auxhdr->exec_dfile);
-
- /* Do for each subspace dictionary entry */
- check_lseek (file, hdr->subspace_location, 0);
- for (i = 0; i < hdr->subspace_total; i++)
- {
- ptrdiff_t subspace_size = sizeof subspace;
- if (read (file, &subspace, subspace_size) != subspace_size)
- unexec_error ("Can't read subspace record");
-
- /* If subspace has a file location, update it */
- if (subspace.initialization_length > 0
- && subspace.file_loc_init_value > location)
- {
- subspace.file_loc_init_value += offset;
- check_lseek (file, -subspace_size, 1);
- if (write (file, &subspace, subspace_size) != subspace_size)
- unexec_error ("Can't update subspace record");
- }
- }
-
- /* Do for each initialization pointer record */
- /* (I don't think it applies to executable files, only relocatables) */
-#undef update
-}
-
-/* Read in the header records from an a.out file. */
-
-static void
-read_header (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr)
-{
-
- /* Read the header in */
- check_lseek (file, 0, 0);
- if (read (file, hdr, sizeof (*hdr)) != sizeof (*hdr))
- unexec_error ("Couldn't read header from a.out file");
-
- if (hdr->a_magic != EXEC_MAGIC && hdr->a_magic != SHARE_MAGIC
- && hdr->a_magic != DEMAND_MAGIC)
- {
- fputs ("a.out file doesn't have valid magic number\n", stderr);
- exit (1);
- }
-
- check_lseek (file, hdr->aux_header_location, 0);
- if (read (file, auxhdr, sizeof (*auxhdr)) != sizeof (*auxhdr))
- unexec_error ("Couldn't read auxiliary header from a.out file");
-}
-
-/* Write out the header records into an a.out file. */
-
-static void
-write_header (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr)
-{
- /* Update the checksum */
- hdr->checksum = calculate_checksum (hdr);
-
- /* Write the header back into the a.out file */
- check_lseek (file, 0, 0);
- if (write (file, hdr, sizeof (*hdr)) != sizeof (*hdr))
- unexec_error ("Couldn't write header to a.out file");
- check_lseek (file, hdr->aux_header_location, 0);
- if (write (file, auxhdr, sizeof (*auxhdr)) != sizeof (*auxhdr))
- unexec_error ("Couldn't write auxiliary header to a.out file");
-}
-
-/* Calculate the checksum of a SOM header record. */
-
-static int
-calculate_checksum (struct header *hdr)
-{
- int checksum, i, *ptr;
-
- checksum = 0; ptr = (int *) hdr;
-
- for (i = 0; i < sizeof (*hdr) / sizeof (int) - 1; i++)
- checksum ^= ptr[i];
-
- return (checksum);
-}
-
-/* Copy size bytes from the old file to the new one. */
-
-static void
-copy_file (int old, int new, int size)
-{
- int len;
- int buffer[8192]; /* word aligned will be faster */
-
- for (; size > 0; size -= len)
- {
- len = min (size, sizeof (buffer));
- if (read (old, buffer, len) != len)
- unexec_error ("Read failure on a.out file");
- if (write (new, buffer, len) != len)
- unexec_error ("Write failure in a.out file");
- }
-}
-
-/* Copy the rest of the file, up to EOF. */
-
-static void
-copy_rest (int old, int new)
-{
- int buffer[4096];
- int len;
-
- /* Copy bytes until end of file or error */
- while ((len = read (old, buffer, sizeof (buffer))) > 0)
- if (write (new, buffer, len) != len) break;
-
- if (len != 0)
- unexec_error ("Unable to copy the rest of the file");
-}
-
-#ifdef DEBUG
-static void
-display_header (struct header *hdr, struct som_exec_auxhdr *auxhdr)
-{
- /* Display the header information (debug) */
- printf ("\n\nFILE HEADER\n");
- printf ("magic number %d \n", hdr->a_magic);
- printf ("text loc %.8x size %d \n", auxhdr->exec_tmem, auxhdr->exec_tsize);
- printf ("data loc %.8x size %d \n", auxhdr->exec_dmem, auxhdr->exec_dsize);
- printf ("entry %x \n", auxhdr->exec_entry);
- printf ("Bss segment size %u\n", auxhdr->exec_bsize);
- printf ("\n");
- printf ("data file loc %d size %d\n",
- auxhdr->exec_dfile, auxhdr->exec_dsize);
- printf ("som_length %d\n", hdr->som_length);
- printf ("unloadable sploc %d size %d\n",
- hdr->unloadable_sp_location, hdr->unloadable_sp_size);
-}
-#endif /* DEBUG */
-
-
-/* Create a new a.out file, same as old but with current data space */
-void
-unexec (const char *new_name, /* name of the new a.out file to be created
*/
- const char *old_name) /* name of the old a.out file */
-{
- int old, new;
- int old_size, new_size;
- struct header hdr;
- struct som_exec_auxhdr auxhdr;
- long i;
-
- /* For the greatest flexibility, should create a temporary file in
- the same directory as the new file. When everything is complete,
- rename the temp file to the new name.
- This way, a program could update its own a.out file even while
- it is still executing. If problems occur, everything is still
- intact. NOT implemented. */
-
- /* Open the input and output a.out files. */
- old = emacs_open (old_name, O_RDONLY, 0);
- if (old < 0)
- unexec_error (old_name);
- new = emacs_open (new_name, O_CREAT | O_RDWR | O_TRUNC, 0777);
- if (new < 0)
- unexec_error (new_name);
-
- /* Read the old headers. */
- read_header (old, &hdr, &auxhdr);
-
- brk_on_dump = (long) sbrk (0);
-
- /* Decide how large the new and old data areas are. */
- old_size = auxhdr.exec_dsize;
- /* I suspect these two statements are separate
- to avoid a compiler bug in hpux version 8. */
- i = (long) sbrk (0);
- new_size = i - auxhdr.exec_dmem;
-
- /* Copy the old file to the new, up to the data space. */
- check_lseek (old, 0, 0);
- copy_file (old, new, auxhdr.exec_dfile);
-
- /* Skip the old data segment and write a new one. */
- check_lseek (old, old_size, 1);
- save_data_space (new, &hdr, &auxhdr, new_size);
-
- /* Copy the rest of the file. */
- copy_rest (old, new);
-
- /* Update file pointers since we probably changed size of data area. */
- update_file_ptrs (new, &hdr, &auxhdr, auxhdr.exec_dfile, new_size-old_size);
-
- /* Save the modified header. */
- write_header (new, &hdr, &auxhdr);
-
- /* Close the binary file. */
- emacs_close (old);
- emacs_close (new);
-}
diff --git a/src/unexmacosx.c b/src/unexmacosx.c
deleted file mode 100644
index 7b2326441b4..00000000000
--- a/src/unexmacosx.c
+++ /dev/null
@@ -1,1406 +0,0 @@
-/* Dump Emacs in Mach-O format for use on macOS.
- Copyright (C) 2001-2024 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs 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 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-/* Contributed by Andrew Choi (akochoi@mac.com). */
-
-/* Documentation note.
-
- Consult the following documents/files for a description of the
- Mach-O format: the file loader.h, man pages for Mach-O and ld, old
- NEXTSTEP documents of the Mach-O format. The tool otool dumps the
- mach header (-h option) and the load commands (-l option) in a
- Mach-O file. The tool nm on macOS displays the symbol table in
- a Mach-O file. For examples of unexec for the Mach-O format, see
- the file unexnext.c in the GNU Emacs distribution, the file
- unexdyld.c in the Darwin port of GNU Emacs 20.7, and unexdyld.c in
- the Darwin port of XEmacs 21.1. Also the Darwin Libc source
- contains the source code for malloc_freezedry and malloc_jumpstart.
- Read that to see what they do. This file was written completely
- from scratch, making use of information from the above sources. */
-
-/* The macOS implementation of unexec makes use of Darwin's `zone'
- memory allocator. All calls to malloc, realloc, and free in Emacs
- are redirected to unexec_malloc, unexec_realloc, and unexec_free in
- this file. When temacs is run, all memory requests are handled in
- the zone EmacsZone. The Darwin memory allocator library calls
- maintain the data structures to manage this zone. Dumping writes
- its contents to data segments of the executable file. When emacs
- is run, the loader recreates the contents of the zone in memory.
- However since the initialization routine of the zone memory
- allocator is run again, this `zone' can no longer be used as a
- heap. That is why emacs uses the ordinary malloc system call to
- allocate memory. Also, when a block of memory needs to be
- reallocated and the new size is larger than the old one, a new
- block must be obtained by malloc and the old contents copied to
- it. */
-
-/* Peculiarity of the Mach-O files generated by ld in macOS
- (possible causes of future bugs if changed).
-
- The file offset of the start of the __TEXT segment is zero. Since
- the Mach header and load commands are located at the beginning of a
- Mach-O file, copying the contents of the __TEXT segment from the
- input file overwrites them in the output file. Despite this,
- unexec works fine as written below because the segment load command
- for __TEXT appears, and is therefore processed, before all other
- load commands except the segment load command for __PAGEZERO, which
- remains unchanged.
-
- Although the file offset of the start of the __TEXT segment is
- zero, none of the sections it contains actually start there. In
- fact, the earliest one starts a few hundred bytes beyond the end of
- the last load command. The linker option -headerpad controls the
- minimum size of this padding. Its setting can be changed in
- s/darwin.h. A value of 0x690, e.g., leaves room for 30 additional
- load commands for the newly created __DATA segments (at 56 bytes
- each). Unexec fails if there is not enough room for these new
- segments.
-
- The __TEXT segment contains the sections __text, __cstring,
- __picsymbol_stub, and __const and the __DATA segment contains the
- sections __data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __bss,
- and __common. The other segments do not contain any sections.
- These sections are copied from the input file to the output file,
- except for __data, __bss, and __common, which are dumped from
- memory. The types of the sections __bss and __common are changed
- from S_ZEROFILL to S_REGULAR. Note that the number of sections and
- their relative order in the input and output files remain
- unchanged. Otherwise all n_sect fields in the nlist records in the
- symbol table (specified by the LC_SYMTAB load command) will have to
- be changed accordingly.
-*/
-
-#include <config.h>
-
-/* Although <config.h> redefines malloc to unexec_malloc, etc., this
- file wants stdlib.h to declare the originals. */
-#undef malloc
-#undef realloc
-#undef free
-
-#include <stdlib.h>
-
-#include "unexec.h"
-#include "lisp.h"
-#include "sysstdio.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <mach/mach.h>
-#include <mach/vm_map.h>
-#include <mach-o/loader.h>
-#include <mach-o/reloc.h>
-#ifdef HAVE_MALLOC_MALLOC_H
-#include <malloc/malloc.h>
-#else
-#include <objc/malloc.h>
-#endif
-
-#include <assert.h>
-
-/* LC_DATA_IN_CODE is not defined in mach-o/loader.h on Mac OS X 10.7.
- But it is used if we build with "Command Line Tools for Xcode 4.5
- (Mac OS X Lion) - September 2012". */
-#ifndef LC_DATA_IN_CODE
-#define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */
-#endif
-
-#ifdef _LP64
-#define mach_header mach_header_64
-#define segment_command segment_command_64
-#undef VM_REGION_BASIC_INFO_COUNT
-#define VM_REGION_BASIC_INFO_COUNT VM_REGION_BASIC_INFO_COUNT_64
-#undef VM_REGION_BASIC_INFO
-#define VM_REGION_BASIC_INFO VM_REGION_BASIC_INFO_64
-#undef LC_SEGMENT
-#define LC_SEGMENT LC_SEGMENT_64
-#define vm_region vm_region_64
-#define section section_64
-#undef MH_MAGIC
-#define MH_MAGIC MH_MAGIC_64
-#endif
-
-#define VERBOSE 1
-
-/* Size of buffer used to copy data from the input file to the output
- file in function unexec_copy. */
-#define UNEXEC_COPY_BUFSZ 1024
-
-/* Regions with memory addresses above this value are assumed to be
- mapped to dynamically loaded libraries and will not be dumped. */
-#define VM_DATA_TOP (20 * 1024 * 1024)
-
-/* Type of an element on the list of regions to be dumped. */
-struct region_t {
- vm_address_t address;
- vm_size_t size;
- vm_prot_t protection;
- vm_prot_t max_protection;
-
- struct region_t *next;
-};
-
-/* Head and tail of the list of regions to be dumped. */
-static struct region_t *region_list_head = 0;
-static struct region_t *region_list_tail = 0;
-
-/* Pointer to array of load commands. */
-static struct load_command **lca;
-
-/* Number of load commands. */
-static int nlc;
-
-/* The highest VM address of segments loaded by the input file.
- Regions with addresses beyond this are assumed to be allocated
- dynamically and thus require dumping. */
-static vm_address_t infile_lc_highest_addr = 0;
-
-/* The lowest file offset used by the all sections in the __TEXT
- segments. This leaves room at the beginning of the file to store
- the Mach-O header. Check this value against header size to ensure
- the added load commands for the new __DATA segments did not
- overwrite any of the sections in the __TEXT segment. */
-static unsigned long text_seg_lowest_offset = 0x10000000;
-
-/* Mach header. */
-static struct mach_header mh;
-
-/* Offset at which the next load command should be written. */
-static unsigned long curr_header_offset = sizeof (struct mach_header);
-
-/* Offset at which the next segment should be written. */
-static unsigned long curr_file_offset = 0;
-
-static unsigned long pagesize;
-#define ROUNDUP_TO_PAGE_BOUNDARY(x) (((x) + pagesize - 1) & ~(pagesize - 1))
-
-static int infd, outfd;
-
-static int in_dumped_exec = 0;
-
-static malloc_zone_t *emacs_zone;
-
-/* file offset of input file's data segment */
-static off_t data_segment_old_fileoff = 0;
-
-static struct segment_command *data_segment_scp;
-
-/* Read N bytes from infd into memory starting at address DEST.
- Return true if successful, false otherwise. */
-static int
-unexec_read (void *dest, size_t n)
-{
- return n == read (infd, dest, n);
-}
-
-/* Write COUNT bytes from memory starting at address SRC to outfd
- starting at offset DEST. Return true if successful, false
- otherwise. */
-static int
-unexec_write (off_t dest, const void *src, size_t count)
-{
- task_t task = mach_task_self();
- if (task == MACH_PORT_NULL || task == MACH_PORT_DEAD)
- return false;
-
- if (lseek (outfd, dest, SEEK_SET) != dest)
- return 0;
-
- /* We use the Mach virtual memory API to read our process memory
- because using src directly would be undefined behavior and fails
- under Address Sanitizer. */
- bool success = false;
- vm_offset_t data;
- mach_msg_type_number_t data_count;
- if (vm_read (task, (uintptr_t) src, count, &data, &data_count)
- == KERN_SUCCESS)
- {
- success =
- write (outfd, (const void *) (uintptr_t) data, data_count) == count;
- vm_deallocate (task, data, data_count);
- }
- return success;
-}
-
-/* Write COUNT bytes of zeros to outfd starting at offset DEST.
- Return true if successful, false otherwise. */
-static int
-unexec_write_zero (off_t dest, size_t count)
-{
- char buf[UNEXEC_COPY_BUFSZ];
- ssize_t bytes;
-
- memset (buf, 0, UNEXEC_COPY_BUFSZ);
- if (lseek (outfd, dest, SEEK_SET) != dest)
- return 0;
-
- while (count > 0)
- {
- bytes = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count;
- if (write (outfd, buf, bytes) != bytes)
- return 0;
- count -= bytes;
- }
-
- return 1;
-}
-
-/* Copy COUNT bytes from starting offset SRC in infd to starting
- offset DEST in outfd. Return true if successful, false
- otherwise. */
-static int
-unexec_copy (off_t dest, off_t src, ssize_t count)
-{
- ssize_t bytes_read;
- ssize_t bytes_to_read;
-
- char buf[UNEXEC_COPY_BUFSZ];
-
- if (lseek (infd, src, SEEK_SET) != src)
- return 0;
-
- if (lseek (outfd, dest, SEEK_SET) != dest)
- return 0;
-
- while (count > 0)
- {
- bytes_to_read = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count;
- bytes_read = read (infd, buf, bytes_to_read);
- if (bytes_read <= 0)
- return 0;
- if (write (outfd, buf, bytes_read) != bytes_read)
- return 0;
- count -= bytes_read;
- }
-
- return 1;
-}
-
-/* Debugging and informational messages routines. */
-
-static _Noreturn void
-unexec_error (const char *format, ...)
-{
- va_list ap;
-
- va_start (ap, format);
- fputs ("unexec: ", stderr);
- vfprintf (stderr, format, ap);
- putc ('\n', stderr);
- va_end (ap);
- exit (1);
-}
-
-static void
-print_prot (vm_prot_t prot)
-{
- if (prot == VM_PROT_NONE)
- printf ("none");
- else
- {
- putchar (prot & VM_PROT_READ ? 'r' : ' ');
- putchar (prot & VM_PROT_WRITE ? 'w' : ' ');
- putchar (prot & VM_PROT_EXECUTE ? 'x' : ' ');
- putchar (' ');
- }
-}
-
-static void
-print_region (vm_address_t address, vm_size_t size, vm_prot_t prot,
- vm_prot_t max_prot)
-{
- printf ("%#10lx %#8lx ", (long) address, (long) size);
- print_prot (prot);
- putchar (' ');
- print_prot (max_prot);
- putchar ('\n');
-}
-
-static void
-print_region_list (void)
-{
- struct region_t *r;
-
- printf (" address size prot maxp\n");
-
- for (r = region_list_head; r; r = r->next)
- print_region (r->address, r->size, r->protection, r->max_protection);
-}
-
-/* Build the list of regions that need to be dumped. Regions with
- addresses above VM_DATA_TOP are omitted. Adjacent regions with
- identical protection are merged. Note that non-writable regions
- cannot be omitted because they some regions created at run time are
- read-only. */
-static void
-build_region_list (void)
-{
- task_t target_task = mach_task_self ();
- vm_address_t address = (vm_address_t) 0;
- vm_size_t size;
- struct vm_region_basic_info info;
- mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
- mach_port_t object_name;
- struct region_t *r;
-
-#if VERBOSE
- printf ("--- List of All Regions ---\n");
- printf (" address size prot maxp\n");
-#endif
-
- while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
- (vm_region_info_t) &info, &info_count, &object_name)
- == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT)
- {
- /* Done when we reach addresses of shared libraries, which are
- loaded in high memory. */
- if (address >= VM_DATA_TOP)
- break;
-
-#if VERBOSE
- print_region (address, size, info.protection, info.max_protection);
-#endif
-
- /* If a region immediately follows the previous one (the one
- most recently added to the list) and has identical
- protection, merge it with the latter. Otherwise create a
- new list element for it. */
- if (region_list_tail
- && info.protection == region_list_tail->protection
- && info.max_protection == region_list_tail->max_protection
- && region_list_tail->address + region_list_tail->size == address)
- {
- region_list_tail->size += size;
- }
- else
- {
- r = malloc (sizeof *r);
-
- if (!r)
- unexec_error ("cannot allocate region structure");
-
- r->address = address;
- r->size = size;
- r->protection = info.protection;
- r->max_protection = info.max_protection;
-
- r->next = 0;
- if (region_list_head == 0)
- {
- region_list_head = r;
- region_list_tail = r;
- }
- else
- {
- region_list_tail->next = r;
- region_list_tail = r;
- }
-
- /* Deallocate (unused) object name returned by
- vm_region. */
- if (object_name != MACH_PORT_NULL)
- mach_port_deallocate (target_task, object_name);
- }
-
- address += size;
- }
-
- printf ("--- List of Regions to be Dumped ---\n");
- print_region_list ();
-}
-
-
-#define MAX_UNEXEC_REGIONS 400
-
-static int num_unexec_regions;
-typedef struct {
- vm_range_t range;
- vm_size_t filesize;
-} unexec_region_info;
-static unexec_region_info unexec_regions[MAX_UNEXEC_REGIONS];
-
-static void
-unexec_regions_recorder (task_t task, void *rr, unsigned type,
- vm_range_t *ranges, unsigned num)
-{
- vm_address_t p;
- vm_size_t filesize;
-
- while (num && num_unexec_regions < MAX_UNEXEC_REGIONS)
- {
- /* Subtract the size of trailing null bytes from filesize. It
- can be smaller than vmsize in segment commands. In such a
- case, trailing bytes are initialized with zeros. */
- for (p = ranges->address + ranges->size; p > ranges->address; p--)
- if (*(((char *) p)-1))
- break;
- filesize = p - ranges->address;
-
- unexec_regions[num_unexec_regions].filesize = filesize;
- unexec_regions[num_unexec_regions++].range = *ranges;
- printf ("%#10lx (sz: %#8lx/%#8lx)\n", (long) (ranges->address),
- (long) filesize, (long) (ranges->size));
- ranges++; num--;
- }
-}
-
-static kern_return_t
-unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr)
-{
- *ptr = (void *) address;
- return KERN_SUCCESS;
-}
-
-static void
-find_emacs_zone_regions (void)
-{
- num_unexec_regions = 0;
-
- emacs_zone->introspect->enumerator (mach_task_self (), 0,
- MALLOC_PTR_REGION_RANGE_TYPE
- | MALLOC_ADMIN_REGION_RANGE_TYPE,
- (vm_address_t) emacs_zone,
- unexec_reader,
- unexec_regions_recorder);
-
- if (num_unexec_regions == MAX_UNEXEC_REGIONS)
- unexec_error ("find_emacs_zone_regions: too many regions");
-}
-
-static int
-unexec_regions_sort_compare (const void *a, const void *b)
-{
- vm_address_t aa = ((unexec_region_info *) a)->range.address;
- vm_address_t bb = ((unexec_region_info *) b)->range.address;
-
- if (aa < bb)
- return -1;
- else if (aa > bb)
- return 1;
- else
- return 0;
-}
-
-static void
-unexec_regions_merge (void)
-{
- qsort (unexec_regions, num_unexec_regions, sizeof (unexec_regions[0]),
- &unexec_regions_sort_compare);
-
- /* Align each region start address to a page boundary. */
- for (unexec_region_info *cur = unexec_regions;
- cur < unexec_regions + num_unexec_regions; cur++)
- {
- vm_size_t padsize = cur->range.address & (pagesize - 1);
- if (padsize)
- {
- cur->range.address -= padsize;
- cur->range.size += padsize;
- cur->filesize += padsize;
-
- unexec_region_info *prev = cur == unexec_regions ? NULL : cur - 1;
- if (prev
- && prev->range.address + prev->range.size > cur->range.address)
- {
- prev->range.size = cur->range.address - prev->range.address;
- if (prev->filesize > prev->range.size)
- prev->filesize = prev->range.size;
- }
- }
- }
-
- int n = 0;
- unexec_region_info r = unexec_regions[0];
- for (int i = 1; i < num_unexec_regions; i++)
- {
- if (r.range.address + r.range.size == unexec_regions[i].range.address
- && r.range.size - r.filesize < 2 * pagesize)
- {
- r.filesize = r.range.size + unexec_regions[i].filesize;
- r.range.size += unexec_regions[i].range.size;
- }
- else
- {
- unexec_regions[n++] = r;
- r = unexec_regions[i];
- }
- }
- unexec_regions[n++] = r;
- num_unexec_regions = n;
-}
-
-
-/* More informational messages routines. */
-
-static void
-print_load_command_name (int lc)
-{
- switch (lc)
- {
- case LC_SEGMENT:
-#ifndef _LP64
- printf ("LC_SEGMENT ");
-#else
- printf ("LC_SEGMENT_64 ");
-#endif
- break;
- case LC_LOAD_DYLINKER:
- printf ("LC_LOAD_DYLINKER ");
- break;
- case LC_LOAD_DYLIB:
- printf ("LC_LOAD_DYLIB ");
- break;
- case LC_SYMTAB:
- printf ("LC_SYMTAB ");
- break;
- case LC_DYSYMTAB:
- printf ("LC_DYSYMTAB ");
- break;
- case LC_UNIXTHREAD:
- printf ("LC_UNIXTHREAD ");
- break;
- case LC_PREBOUND_DYLIB:
- printf ("LC_PREBOUND_DYLIB");
- break;
- case LC_TWOLEVEL_HINTS:
- printf ("LC_TWOLEVEL_HINTS");
- break;
-#ifdef LC_UUID
- case LC_UUID:
- printf ("LC_UUID ");
- break;
-#endif
-#ifdef LC_DYLD_INFO
- case LC_DYLD_INFO:
- printf ("LC_DYLD_INFO ");
- break;
- case LC_DYLD_INFO_ONLY:
- printf ("LC_DYLD_INFO_ONLY");
- break;
-#endif
-#ifdef LC_VERSION_MIN_MACOSX
- case LC_VERSION_MIN_MACOSX:
- printf ("LC_VERSION_MIN_MACOSX");
- break;
-#endif
-#ifdef LC_FUNCTION_STARTS
- case LC_FUNCTION_STARTS:
- printf ("LC_FUNCTION_STARTS");
- break;
-#endif
-#ifdef LC_MAIN
- case LC_MAIN:
- printf ("LC_MAIN ");
- break;
-#endif
-#ifdef LC_DATA_IN_CODE
- case LC_DATA_IN_CODE:
- printf ("LC_DATA_IN_CODE ");
- break;
-#endif
-#ifdef LC_SOURCE_VERSION
- case LC_SOURCE_VERSION:
- printf ("LC_SOURCE_VERSION");
- break;
-#endif
-#ifdef LC_DYLIB_CODE_SIGN_DRS
- case LC_DYLIB_CODE_SIGN_DRS:
- printf ("LC_DYLIB_CODE_SIGN_DRS");
- break;
-#endif
- default:
- printf ("unknown ");
- }
-}
-
-static void
-print_load_command (struct load_command *lc)
-{
- print_load_command_name (lc->cmd);
- printf ("%8d", lc->cmdsize);
-
- if (lc->cmd == LC_SEGMENT)
- {
- struct segment_command *scp;
- struct section *sectp;
- int j;
-
- scp = (struct segment_command *) lc;
- printf (" %-16.16s %#10lx %#8lx\n",
- scp->segname, (long) (scp->vmaddr), (long) (scp->vmsize));
-
- sectp = (struct section *) (scp + 1);
- for (j = 0; j < scp->nsects; j++)
- {
- printf (" %-16.16s %#10lx %#8lx\n",
- sectp->sectname, (long) (sectp->addr), (long) (sectp->size));
- sectp++;
- }
- }
- else
- printf ("\n");
-}
-
-/* Read header and load commands from input file. Store the latter in
- the global array lca. Store the total number of load commands in
- global variable nlc. */
-static void
-read_load_commands (void)
-{
- int i;
-
- if (!unexec_read (&mh, sizeof (struct mach_header)))
- unexec_error ("cannot read mach-o header");
-
- if (mh.magic != MH_MAGIC)
- unexec_error ("input file not in Mach-O format");
-
- if (mh.filetype != MH_EXECUTE)
- unexec_error ("input Mach-O file is not an executable object file");
-
-#if VERBOSE
- printf ("--- Header Information ---\n");
- printf ("Magic = 0x%08x\n", mh.magic);
- printf ("CPUType = %d\n", mh.cputype);
- printf ("CPUSubType = %d\n", mh.cpusubtype);
- printf ("FileType = 0x%x\n", mh.filetype);
- printf ("NCmds = %d\n", mh.ncmds);
- printf ("SizeOfCmds = %d\n", mh.sizeofcmds);
- printf ("Flags = 0x%08x\n", mh.flags);
-#endif
-
- nlc = mh.ncmds;
- lca = malloc (nlc * sizeof *lca);
-
- for (i = 0; i < nlc; i++)
- {
- struct load_command lc;
- /* Load commands are variable-size: so read the command type and
- size first and then read the rest. */
- if (!unexec_read (&lc, sizeof (struct load_command)))
- unexec_error ("cannot read load command");
- lca[i] = malloc (lc.cmdsize);
- memcpy (lca[i], &lc, sizeof (struct load_command));
- if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command)))
- unexec_error ("cannot read content of load command");
- if (lc.cmd == LC_SEGMENT)
- {
- struct segment_command *scp = (struct segment_command *) lca[i];
-
- if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr)
- infile_lc_highest_addr = scp->vmaddr + scp->vmsize;
-
- if (strncmp (scp->segname, SEG_TEXT, 16) == 0)
- {
- struct section *sectp = (struct section *) (scp + 1);
- int j;
-
- for (j = 0; j < scp->nsects; j++)
- if (sectp->offset < text_seg_lowest_offset)
- text_seg_lowest_offset = sectp->offset;
- }
- }
- }
-
- printf ("Highest address of load commands in input file: %#8lx\n",
- (unsigned long)infile_lc_highest_addr);
-
- printf ("Lowest offset of all sections in __TEXT segment: %#8lx\n",
- text_seg_lowest_offset);
-
- printf ("--- List of Load Commands in Input File ---\n");
- printf ("# cmd cmdsize name address size\n");
-
- for (i = 0; i < nlc; i++)
- {
- printf ("%1d ", i);
- print_load_command (lca[i]);
- }
-}
-
-/* Copy a LC_SEGMENT load command other than the __DATA segment from
- the input file to the output file, adjusting the file offset of the
- segment and the file offsets of sections contained in it. */
-static void
-copy_segment (struct load_command *lc)
-{
- struct segment_command *scp = (struct segment_command *) lc;
- unsigned long old_fileoff = scp->fileoff;
- struct section *sectp;
- int j;
-
- scp->fileoff = curr_file_offset;
-
- sectp = (struct section *) (scp + 1);
- for (j = 0; j < scp->nsects; j++)
- {
- sectp->offset += curr_file_offset - old_fileoff;
- sectp++;
- }
-
- printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
- scp->segname, (long) (scp->fileoff), (long) (scp->filesize),
- (long) (scp->vmsize), (long) (scp->vmaddr));
-
- if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
- unexec_error ("cannot copy segment from input to output file");
- curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
-
- if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
- unexec_error ("cannot write load command to header");
-
- curr_header_offset += lc->cmdsize;
-}
-
-/* Copy a LC_SEGMENT load command for the __DATA segment in the input
- file to the output file. We assume that only one such segment load
- command exists in the input file and it contains the sections
- __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and
- __dyld. The first three of these should be dumped from memory and
- the rest should be copied from the input file. Note that the
- sections __bss and __common contain no data in the input file
- because their flag fields have the value S_ZEROFILL. Dumping these
- from memory makes it necessary to adjust file offset fields in
- subsequently dumped load commands. Then, create new __DATA segment
- load commands for regions on the region list other than the one
- corresponding to the __DATA segment in the input file. */
-static void
-copy_data_segment (struct load_command *lc)
-{
- struct segment_command *scp = (struct segment_command *) lc;
- struct section *sectp;
- int j;
- unsigned long header_offset, old_file_offset;
-
- /* The new filesize of the segment is set to its vmsize because data
- blocks for segments must start at region boundaries. Note that
- this may leave unused locations at the end of the segment data
- block because the total of the sizes of all sections in the
- segment is generally smaller than vmsize. */
- scp->filesize = scp->vmsize;
-
- printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
- scp->segname, curr_file_offset, (long)(scp->filesize),
- (long)(scp->vmsize), (long) (scp->vmaddr));
-
- /* Offsets in the output file for writing the next section structure
- and segment data block, respectively. */
- header_offset = curr_header_offset + sizeof (struct segment_command);
-
- sectp = (struct section *) (scp + 1);
- for (j = 0; j < scp->nsects; j++)
- {
- old_file_offset = sectp->offset;
- sectp->offset = sectp->addr - scp->vmaddr + curr_file_offset;
- /* The __data section is dumped from memory. The __bss and
- __common sections are also dumped from memory but their flag
- fields require changing (from S_ZEROFILL to S_REGULAR). The
- other three kinds of sections are just copied from the input
- file. */
- if (strncmp (sectp->sectname, SECT_DATA, 16) == 0)
- {
- unsigned long my_size;
-
- /* The __data section is basically dumped from memory. But
- initialized data in statically linked libraries are
- copied from the input file. In particular,
- add_image_hook.names and add_image_hook.pointers stored
- by libarclite_macosx.a, are restored so that they will be
- reinitialized when the dumped binary is executed. */
- my_size = (unsigned long)my_edata - sectp->addr;
- if (!(sectp->addr <= (unsigned long)my_edata
- && my_size <= sectp->size))
- unexec_error ("my_edata is not in section %s", SECT_DATA);
- if (!unexec_write (sectp->offset, (void *) sectp->addr, my_size))
- unexec_error ("cannot write section %s", SECT_DATA);
- if (!unexec_copy (sectp->offset + my_size, old_file_offset + my_size,
- sectp->size - my_size))
- unexec_error ("cannot copy section %s", SECT_DATA);
- if (!unexec_write (header_offset, sectp, sizeof (struct section)))
- unexec_error ("cannot write section %s's header", SECT_DATA);
- }
- else if (strncmp (sectp->sectname, SECT_COMMON, 16) == 0)
- {
- sectp->flags = S_REGULAR;
- if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
- unexec_error ("cannot write section %.16s", sectp->sectname);
- if (!unexec_write (header_offset, sectp, sizeof (struct section)))
- unexec_error ("cannot write section %.16s's header",
sectp->sectname);
- }
- else if (strncmp (sectp->sectname, SECT_BSS, 16) == 0)
- {
- unsigned long my_size;
-
- sectp->flags = S_REGULAR;
-
- /* Clear uninitialized local variables in statically linked
- libraries. In particular, function pointers stored by
- libSystemStub.a, which is introduced in Mac OS X 10.4 for
- binary compatibility with respect to long double, are
- cleared so that they will be reinitialized when the
- dumped binary is executed on other versions of OS. */
- my_size = (unsigned long)my_endbss_static - sectp->addr;
- if (!(sectp->addr <= (unsigned long)my_endbss_static
- && my_size <= sectp->size))
- unexec_error ("my_endbss_static is not in section %.16s",
- sectp->sectname);
- if (!unexec_write (sectp->offset, (void *) sectp->addr, my_size))
- unexec_error ("cannot write section %.16s", sectp->sectname);
- if (!unexec_write_zero (sectp->offset + my_size,
- sectp->size - my_size))
- unexec_error ("cannot write section %.16s", sectp->sectname);
- if (!unexec_write (header_offset, sectp, sizeof (struct section)))
- unexec_error ("cannot write section %.16s's header",
sectp->sectname);
- }
- else if (strncmp (sectp->sectname, "__bss", 5) == 0
- || strncmp (sectp->sectname, "__pu_bss", 8) == 0)
- {
- sectp->flags = S_REGULAR;
-
- /* These sections are produced by GCC 4.6+.
-
- FIXME: We possibly ought to clear uninitialized local
- variables in statically linked libraries like for
- SECT_BSS (__bss) above, but setting up the markers we
- need in lastfile.c would be rather messy. See
- darwin_output_aligned_bss () in gcc/config/darwin.c for
- the root of the problem, keeping in mind that the
- sections are numbered by their alignment in GCC 4.6, but
- by log2(alignment) in GCC 4.7. */
-
- if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
- unexec_error ("cannot copy section %.16s", sectp->sectname);
- if (!unexec_write (header_offset, sectp, sizeof (struct section)))
- unexec_error ("cannot write section %.16s's header",
sectp->sectname);
- }
- else if (strncmp (sectp->sectname, "__la_symbol_ptr", 16) == 0
- || strncmp (sectp->sectname, "__nl_symbol_ptr", 16) == 0
- || strncmp (sectp->sectname, "__got", 16) == 0
- || strncmp (sectp->sectname, "__la_sym_ptr2", 16) == 0
- || strncmp (sectp->sectname, "__dyld", 16) == 0
- || strncmp (sectp->sectname, "__const", 16) == 0
- || strncmp (sectp->sectname, "__cfstring", 16) == 0
- || strncmp (sectp->sectname, "__gcc_except_tab", 16) == 0
- || strncmp (sectp->sectname, "__program_vars", 16) == 0
- || strncmp (sectp->sectname, "__mod_init_func", 16) == 0
- || strncmp (sectp->sectname, "__mod_term_func", 16) == 0
- || strncmp (sectp->sectname, "__static_data", 16) == 0
- || strncmp (sectp->sectname, "__objc_", 7) == 0)
- {
- if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
- unexec_error ("cannot copy section %.16s", sectp->sectname);
- if (!unexec_write (header_offset, sectp, sizeof (struct section)))
- unexec_error ("cannot write section %.16s's header",
sectp->sectname);
- }
- else
- unexec_error ("unrecognized section %.16s in __DATA segment",
- sectp->sectname);
-
- printf (" section %-16.16s at %#8lx - %#8lx (sz: %#8lx)\n",
- sectp->sectname, (long) (sectp->offset),
- (long) (sectp->offset + sectp->size), (long) (sectp->size));
-
- header_offset += sizeof (struct section);
- sectp++;
- }
-
- curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
-
- if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
- unexec_error ("cannot write header of __DATA segment");
- curr_header_offset += lc->cmdsize;
-
- /* Create new __DATA segment load commands for regions on the region
- list that do not corresponding to any segment load commands in
- the input file.
- */
- for (j = 0; j < num_unexec_regions; j++)
- {
- struct segment_command sc;
-
- sc.cmd = LC_SEGMENT;
- sc.cmdsize = sizeof (struct segment_command);
- strncpy (sc.segname, SEG_DATA, 16);
- sc.vmaddr = unexec_regions[j].range.address;
- sc.vmsize = unexec_regions[j].range.size;
- sc.fileoff = curr_file_offset;
- sc.filesize = unexec_regions[j].filesize;
- sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
- sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
- sc.nsects = 0;
- sc.flags = 0;
-
- printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
- sc.segname, (long) (sc.fileoff), (long) (sc.filesize),
- (long) (sc.vmsize), (long) (sc.vmaddr));
-
- if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.filesize))
- unexec_error ("cannot write new __DATA segment");
- curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (sc.filesize);
-
- if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
- unexec_error ("cannot write new __DATA segment's header");
- curr_header_offset += sc.cmdsize;
- mh.ncmds++;
- }
-}
-
-/* Copy a LC_SYMTAB load command from the input file to the output
- file, adjusting the file offset fields. */
-static void
-copy_symtab (struct load_command *lc, long delta)
-{
- struct symtab_command *stp = (struct symtab_command *) lc;
-
- stp->symoff += delta;
- stp->stroff += delta;
-
- printf ("Writing LC_SYMTAB command\n");
-
- if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
- unexec_error ("cannot write symtab command to header");
-
- curr_header_offset += lc->cmdsize;
-}
-
-/* Fix up relocation entries. */
-static void
-unrelocate (const char *name, off_t reloff, int nrel, vm_address_t base)
-{
- int i, unreloc_count;
- struct relocation_info reloc_info;
- struct scattered_relocation_info *sc_reloc_info
- = (struct scattered_relocation_info *) &reloc_info;
- vm_address_t location;
-
- for (unreloc_count = 0, i = 0; i < nrel; i++)
- {
- if (lseek (infd, reloff, L_SET) != reloff)
- unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i);
- if (!unexec_read (&reloc_info, sizeof (reloc_info)))
- unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i);
- reloff += sizeof (reloc_info);
-
- if (sc_reloc_info->r_scattered == 0)
- switch (reloc_info.r_type)
- {
- case GENERIC_RELOC_VANILLA:
- location = base + reloc_info.r_address;
- if (location >= data_segment_scp->vmaddr
- && location < (data_segment_scp->vmaddr
- + data_segment_scp->vmsize))
- {
- off_t src_off = data_segment_old_fileoff
- + (location - data_segment_scp->vmaddr);
- off_t dst_off = data_segment_scp->fileoff
- + (location - data_segment_scp->vmaddr);
-
- if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length))
- unexec_error ("unrelocate: %s:%d cannot copy original value",
- name, i);
- unreloc_count++;
- }
- break;
- default:
- unexec_error ("unrelocate: %s:%d cannot handle type = %d",
- name, i, reloc_info.r_type);
- }
- else
- unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d",
- name, i, sc_reloc_info->r_type);
- }
-
- if (nrel > 0)
- printf ("Fixed up %d/%d %s relocation entries in data segment.\n",
- unreloc_count, nrel, name);
-}
-
-/* Copy a LC_DYSYMTAB load command from the input file to the output
- file, adjusting the file offset fields. */
-static void
-copy_dysymtab (struct load_command *lc, long delta)
-{
- struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
- vm_address_t base;
-
-#ifdef _LP64
- /* First writable segment address. */
- base = data_segment_scp->vmaddr;
-#else
- /* First segment address in the file (unless MH_SPLIT_SEGS set). */
- base = 0;
-#endif
-
- unrelocate ("local", dstp->locreloff, dstp->nlocrel, base);
- unrelocate ("external", dstp->extreloff, dstp->nextrel, base);
-
- if (dstp->nextrel > 0) {
- dstp->extreloff += delta;
- }
-
- if (dstp->nlocrel > 0) {
- dstp->locreloff += delta;
- }
-
- if (dstp->nindirectsyms > 0)
- dstp->indirectsymoff += delta;
-
- printf ("Writing LC_DYSYMTAB command\n");
-
- if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
- unexec_error ("cannot write symtab command to header");
-
- curr_header_offset += lc->cmdsize;
-}
-
-/* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output
- file, adjusting the file offset fields. */
-static void
-copy_twolevelhints (struct load_command *lc, long delta)
-{
- struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc;
-
- if (tlhp->nhints > 0) {
- tlhp->offset += delta;
- }
-
- printf ("Writing LC_TWOLEVEL_HINTS command\n");
-
- if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
- unexec_error ("cannot write two level hint command to header");
-
- curr_header_offset += lc->cmdsize;
-}
-
-#ifdef LC_DYLD_INFO
-/* Copy a LC_DYLD_INFO(_ONLY) load command from the input file to the output
- file, adjusting the file offset fields. */
-static void
-copy_dyld_info (struct load_command *lc, long delta)
-{
- struct dyld_info_command *dip = (struct dyld_info_command *) lc;
-
- if (dip->rebase_off > 0)
- dip->rebase_off += delta;
- if (dip->bind_off > 0)
- dip->bind_off += delta;
- if (dip->weak_bind_off > 0)
- dip->weak_bind_off += delta;
- if (dip->lazy_bind_off > 0)
- dip->lazy_bind_off += delta;
- if (dip->export_off > 0)
- dip->export_off += delta;
-
- printf ("Writing ");
- print_load_command_name (lc->cmd);
- printf (" command\n");
-
- if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
- unexec_error ("cannot write dyld info command to header");
-
- curr_header_offset += lc->cmdsize;
-}
-#endif
-
-#ifdef LC_FUNCTION_STARTS
-/* Copy a LC_FUNCTION_STARTS/LC_DATA_IN_CODE/LC_DYLIB_CODE_SIGN_DRS
- load command from the input file to the output file, adjusting the
- data offset field. */
-static void
-copy_linkedit_data (struct load_command *lc, long delta)
-{
- struct linkedit_data_command *ldp = (struct linkedit_data_command *) lc;
-
- if (ldp->dataoff > 0)
- ldp->dataoff += delta;
-
- printf ("Writing ");
- print_load_command_name (lc->cmd);
- printf (" command\n");
-
- if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
- unexec_error ("cannot write linkedit data command to header");
-
- curr_header_offset += lc->cmdsize;
-}
-#endif
-
-/* Copy other kinds of load commands from the input file to the output
- file, ones that do not require adjustments of file offsets. */
-static void
-copy_other (struct load_command *lc)
-{
- printf ("Writing ");
- print_load_command_name (lc->cmd);
- printf (" command\n");
-
- if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
- unexec_error ("cannot write symtab command to header");
-
- curr_header_offset += lc->cmdsize;
-}
-
-/* Loop through all load commands and dump them. Then write the Mach
- header. */
-static void
-dump_it (void)
-{
- int i;
- long linkedit_delta = 0;
-
- printf ("--- Load Commands written to Output File ---\n");
-
- for (i = 0; i < nlc; i++)
- switch (lca[i]->cmd)
- {
- case LC_SEGMENT:
- {
- struct segment_command *scp = (struct segment_command *) lca[i];
- if (strncmp (scp->segname, SEG_DATA, 16) == 0)
- {
- /* save data segment file offset and segment_command for
- unrelocate */
- if (data_segment_old_fileoff)
- unexec_error ("cannot handle multiple DATA segments"
- " in input file");
- data_segment_old_fileoff = scp->fileoff;
- data_segment_scp = scp;
-
- copy_data_segment (lca[i]);
- }
- else
- {
- if (strncmp (scp->segname, SEG_LINKEDIT, 16) == 0)
- {
- if (linkedit_delta)
- unexec_error ("cannot handle multiple LINKEDIT segments"
- " in input file");
- linkedit_delta = curr_file_offset - scp->fileoff;
- }
-
- copy_segment (lca[i]);
- }
- }
- break;
- case LC_SYMTAB:
- copy_symtab (lca[i], linkedit_delta);
- break;
- case LC_DYSYMTAB:
- copy_dysymtab (lca[i], linkedit_delta);
- break;
- case LC_TWOLEVEL_HINTS:
- copy_twolevelhints (lca[i], linkedit_delta);
- break;
-#ifdef LC_DYLD_INFO
- case LC_DYLD_INFO:
- case LC_DYLD_INFO_ONLY:
- copy_dyld_info (lca[i], linkedit_delta);
- break;
-#endif
-#ifdef LC_FUNCTION_STARTS
- case LC_FUNCTION_STARTS:
-#ifdef LC_DATA_IN_CODE
- case LC_DATA_IN_CODE:
-#endif
-#ifdef LC_DYLIB_CODE_SIGN_DRS
- case LC_DYLIB_CODE_SIGN_DRS:
-#endif
- copy_linkedit_data (lca[i], linkedit_delta);
- break;
-#endif
- default:
- copy_other (lca[i]);
- break;
- }
-
- if (curr_header_offset > text_seg_lowest_offset)
- unexec_error ("not enough room for load commands for new __DATA segments"
- " (increase headerpad_extra in configure.in to at least %lX)",
- num_unexec_regions * sizeof (struct segment_command));
-
- printf ("%ld unused bytes follow Mach-O header\n",
- text_seg_lowest_offset - curr_header_offset);
-
- mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header);
- if (!unexec_write (0, &mh, sizeof (struct mach_header)))
- unexec_error ("cannot write final header contents");
-}
-
-/* Take a snapshot of Emacs and make a Mach-O format executable file
- from it. The file names of the output and input files are outfile
- and infile, respectively. The three other parameters are
- ignored. */
-void
-unexec (const char *outfile, const char *infile)
-{
- if (in_dumped_exec)
- unexec_error ("Unexec from a dumped executable is not supported.");
-
- pagesize = getpagesize ();
- infd = emacs_open (infile, O_RDONLY, 0);
- if (infd < 0)
- {
- unexec_error ("%s: %s", infile, strerror (errno));
- }
-
- outfd = emacs_open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0777);
- if (outfd < 0)
- {
- emacs_close (infd);
- unexec_error ("%s: %s", outfile, strerror (errno));
- }
-
- build_region_list ();
- read_load_commands ();
-
- find_emacs_zone_regions ();
- unexec_regions_merge ();
-
- in_dumped_exec = 1;
-
- dump_it ();
-
- emacs_close (outfd);
-}
-
-
-void
-unexec_init_emacs_zone (void)
-{
- emacs_zone = malloc_create_zone (0, 0);
- malloc_set_zone_name (emacs_zone, "EmacsZone");
-}
-
-#ifndef MACOSX_MALLOC_MULT16
-#define MACOSX_MALLOC_MULT16 1
-#endif
-
-typedef struct unexec_malloc_header {
- union {
- char c[8];
- size_t size;
- } u;
-} unexec_malloc_header_t;
-
-#if MACOSX_MALLOC_MULT16
-
-#define ptr_in_unexec_regions(p) ((((vm_address_t) (p)) & 8) != 0)
-
-#else
-
-int
-ptr_in_unexec_regions (void *ptr)
-{
- int i;
-
- for (i = 0; i < num_unexec_regions; i++)
- if ((vm_address_t) ptr - unexec_regions[i].range.address
- < unexec_regions[i].range.size)
- return 1;
-
- return 0;
-}
-
-#endif
-
-void *
-unexec_malloc (size_t size)
-{
- if (in_dumped_exec)
- {
- void *p;
-
- p = malloc (size);
-#if MACOSX_MALLOC_MULT16
- assert (((vm_address_t) p % 16) == 0);
-#endif
- return p;
- }
- else
- {
- unexec_malloc_header_t *ptr;
-
- ptr = (unexec_malloc_header_t *)
- malloc_zone_malloc (emacs_zone, size + sizeof (unexec_malloc_header_t));
- ptr->u.size = size;
- ptr++;
-#if MACOSX_MALLOC_MULT16
- assert (((vm_address_t) ptr % 16) == 8);
-#endif
- return (void *) ptr;
- }
-}
-
-void *
-unexec_realloc (void *old_ptr, size_t new_size)
-{
- if (in_dumped_exec)
- {
- void *p;
-
- if (ptr_in_unexec_regions (old_ptr))
- {
- size_t old_size = ((unexec_malloc_header_t *) old_ptr)[-1].u.size;
- size_t size = new_size > old_size ? old_size : new_size;
-
- p = malloc (new_size);
- if (size)
- memcpy (p, old_ptr, size);
- }
- else
- {
- p = realloc (old_ptr, new_size);
- }
-#if MACOSX_MALLOC_MULT16
- assert (((vm_address_t) p % 16) == 0);
-#endif
- return p;
- }
- else
- {
- unexec_malloc_header_t *ptr;
-
- ptr = (unexec_malloc_header_t *)
- malloc_zone_realloc (emacs_zone, (unexec_malloc_header_t *) old_ptr - 1,
- new_size + sizeof (unexec_malloc_header_t));
- ptr->u.size = new_size;
- ptr++;
-#if MACOSX_MALLOC_MULT16
- assert (((vm_address_t) ptr % 16) == 8);
-#endif
- return (void *) ptr;
- }
-}
-
-void
-unexec_free (void *ptr)
-{
- if (ptr == NULL)
- return;
- if (in_dumped_exec)
- {
- if (!ptr_in_unexec_regions (ptr))
- free (ptr);
- }
- else
- malloc_zone_free (emacs_zone, (unexec_malloc_header_t *) ptr - 1);
-}
diff --git a/src/unexsol.c b/src/unexsol.c
deleted file mode 100644
index 0f84099d39e..00000000000
--- a/src/unexsol.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Trivial unexec for Solaris. */
-
-#include <config.h>
-#include "unexec.h"
-
-#include <dlfcn.h>
-
-#include "lisp.h"
-#include "buffer.h"
-#include "coding.h"
-
-void
-unexec (const char *new_name, const char *old_name)
-{
- Lisp_Object data;
- Lisp_Object errstring;
-
- if (! dldump (0, new_name, RTLD_MEMORY))
- return;
-
- data = list1 (build_string (new_name));
- synchronize_system_messages_locale ();
- errstring = code_convert_string_norecord (build_string (dlerror ()),
- Vlocale_coding_system, 0);
-
- xsignal (Qfile_error,
- Fcons (build_string ("Cannot unexec"), Fcons (errstring, data)));
-}
diff --git a/src/unexw32.c b/src/unexw32.c
deleted file mode 100644
index f0a910781cc..00000000000
--- a/src/unexw32.c
+++ /dev/null
@@ -1,684 +0,0 @@
-/* unexec for GNU Emacs on Windows NT.
- Copyright (C) 1994, 2001-2024 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs 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 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
-
-/*
- Geoff Voelker (voelker@cs.washington.edu) 8-12-94
-*/
-
-#include <config.h>
-#include "unexec.h"
-#include "lisp.h"
-#include "w32common.h"
-#include "w32.h"
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <time.h>
-#include <windows.h>
-
-/* Include relevant definitions from IMAGEHLP.H, which can be found
- in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
-
-PIMAGE_NT_HEADERS (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
- DWORD FileLength,
- LPDWORD HeaderSum,
- LPDWORD CheckSum);
-
-extern char my_begdata[];
-extern char my_begbss[];
-extern char *my_begbss_static;
-
-#include "w32heap.h"
-
-void get_section_info (file_data *p_file);
-void copy_executable_and_dump_data (file_data *, file_data *);
-void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
-
-/* Cached info about the .data section in the executable. */
-PIMAGE_SECTION_HEADER data_section;
-PCHAR data_start = 0;
-DWORD_PTR data_size = 0;
-
-/* Cached info about the .bss section in the executable. */
-PIMAGE_SECTION_HEADER bss_section;
-PCHAR bss_start = 0;
-DWORD_PTR bss_size = 0;
-DWORD_PTR extra_bss_size = 0;
-/* bss data that is static might be discontiguous from non-static. */
-PIMAGE_SECTION_HEADER bss_section_static;
-PCHAR bss_start_static = 0;
-DWORD_PTR bss_size_static = 0;
-DWORD_PTR extra_bss_size_static = 0;
-
-/* File handling. */
-
-/* Implementation note: this and the next functions work with ANSI
- codepage encoded file names! */
-
-int
-open_output_file (file_data *p_file, char *filename, unsigned long size)
-{
- HANDLE file;
- HANDLE file_mapping;
- void *file_base;
-
- /* We delete any existing FILENAME because loadup.el will create a
- hard link to it under the name emacs-XX.YY.ZZ.nn.exe. Evidently,
- overwriting a file on Unix breaks any hard links to it, but that
- doesn't happen on Windows. If we don't delete the file before
- creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard
- links to the same file, which defeats the purpose of these hard
- links: being able to run previous builds. */
- DeleteFileA (filename);
- file = CreateFileA (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
- if (file == INVALID_HANDLE_VALUE)
- return FALSE;
-
- file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
- 0, size, NULL);
- if (!file_mapping)
- return FALSE;
-
- file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
- if (file_base == 0)
- return FALSE;
-
- p_file->name = filename;
- p_file->size = size;
- p_file->file = file;
- p_file->file_mapping = file_mapping;
- p_file->file_base = file_base;
-
- return TRUE;
-}
-
-
-/* Routines to manipulate NT executable file sections. */
-
-/* Return pointer to section header for named section. */
-IMAGE_SECTION_HEADER *
-find_section (const char * name, IMAGE_NT_HEADERS * nt_header)
-{
- PIMAGE_SECTION_HEADER section;
- int i;
-
- section = IMAGE_FIRST_SECTION (nt_header);
-
- for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
- {
- if (strcmp ((char *)section->Name, name) == 0)
- return section;
- section++;
- }
- return NULL;
-}
-
-#if 0 /* unused */
-/* Return pointer to section header for section containing the given
- offset in its raw data area. */
-static IMAGE_SECTION_HEADER *
-offset_to_section (DWORD_PTR offset, IMAGE_NT_HEADERS * nt_header)
-{
- PIMAGE_SECTION_HEADER section;
- int i;
-
- section = IMAGE_FIRST_SECTION (nt_header);
-
- for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
- {
- if (offset >= section->PointerToRawData
- && offset < section->PointerToRawData + section->SizeOfRawData)
- return section;
- section++;
- }
- return NULL;
-}
-#endif
-
-/* Return offset to an object in dst, given offset in src. We assume
- there is at least one section in both src and dst images, and that
- the some sections may have been added to dst (after sections in src). */
-static DWORD_PTR
-relocate_offset (DWORD_PTR offset,
- IMAGE_NT_HEADERS * src_nt_header,
- IMAGE_NT_HEADERS * dst_nt_header)
-{
- PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header);
- PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
- int i = 0;
-
- while (offset >= src_section->PointerToRawData)
- {
- if (offset < src_section->PointerToRawData + src_section->SizeOfRawData)
- break;
- i++;
- if (i == src_nt_header->FileHeader.NumberOfSections)
- {
- /* Handle offsets after the last section. */
- dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
- dst_section += dst_nt_header->FileHeader.NumberOfSections - 1;
- while (dst_section->PointerToRawData == 0)
- dst_section--;
- while (src_section->PointerToRawData == 0)
- src_section--;
- return offset
- + (dst_section->PointerToRawData + dst_section->SizeOfRawData)
- - (src_section->PointerToRawData + src_section->SizeOfRawData);
- }
- src_section++;
- dst_section++;
- }
- return offset +
- (dst_section->PointerToRawData - src_section->PointerToRawData);
-}
-
-#define RVA_TO_OFFSET(rva, section) \
- ((section)->PointerToRawData + ((DWORD_PTR)(rva) -
(section)->VirtualAddress))
-
-#define RVA_TO_SECTION_OFFSET(rva, section) \
- ((DWORD_PTR)(rva) - (section)->VirtualAddress)
-
-/* Convert address in executing image to RVA. */
-#define PTR_TO_RVA(ptr) ((DWORD_PTR)(ptr) - (DWORD_PTR) GetModuleHandle (NULL))
-
-#define PTR_TO_OFFSET(ptr, pfile_data) \
- ((unsigned char *)(ptr) - (pfile_data)->file_base)
-
-#define OFFSET_TO_PTR(offset, pfile_data) \
- ((pfile_data)->file_base + (DWORD_PTR)(offset))
-
-#if 0 /* unused */
-#define OFFSET_TO_RVA(offset, section) \
- ((section)->VirtualAddress + ((DWORD_PTR)(offset) -
(section)->PointerToRawData))
-
-#define RVA_TO_PTR(var,section,filedata) \
- ((unsigned char *)(RVA_TO_OFFSET (var,section) +
(filedata).file_base))
-#endif
-
-
-/* Flip through the executable and cache the info necessary for dumping. */
-void
-get_section_info (file_data *p_infile)
-{
- PIMAGE_DOS_HEADER dos_header;
- PIMAGE_NT_HEADERS nt_header;
- int overlap;
-
- dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
- if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
- {
- printf ("Unknown EXE header in %s...bailing.\n", p_infile->name);
- exit (1);
- }
- nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
- dos_header->e_lfanew);
- if (nt_header == NULL)
- {
- printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n",
- p_infile->name);
- exit (1);
- }
-
- /* Check the NT header signature ... */
- if (nt_header->Signature != IMAGE_NT_SIGNATURE)
- {
- printf ("Invalid IMAGE_NT_SIGNATURE 0x%lx in %s...bailing.\n",
- nt_header->Signature, p_infile->name);
- exit (1);
- }
-
- /* Locate the ".data" and ".bss" sections for Emacs. (Note that the
- actual section names are probably different from these, and might
- actually be the same section.)
-
- We do this as follows: first we determine the virtual address
- ranges in this process for the data and bss variables that we wish
- to preserve. Then we map these VAs to the section entries in the
- source image. Finally, we determine the new size of the raw data
- area for the bss section, so we can make the new image the correct
- size. */
-
- /* We arrange for the Emacs initialized data to be in a separate
- section if possible, because we cannot rely on my_begdata and
- my_edata marking out the full extent of the initialized data, at
- least on the Alpha where the linker freely reorders variables
- across libraries. If we can arrange for this, all we need to do is
- find the start and size of the EMDATA section. */
- data_section = find_section ("EMDATA", nt_header);
- if (data_section)
- {
- data_start = (char *) nt_header->OptionalHeader.ImageBase +
- data_section->VirtualAddress;
- data_size = data_section->Misc.VirtualSize;
- }
- else
- {
- /* Fallback on the old method if compiler doesn't support the
- data_set #pragma (or its equivalent). */
- data_start = my_begdata;
- data_size = my_edata - my_begdata;
- data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header);
- if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header))
- {
- printf ("Initialized data is not in a single section...bailing\n");
- exit (1);
- }
- }
-
- /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker
- globally segregates all static and public bss data (ie. across all
- linked modules, not just per module), so we must take both static
- and public bss areas into account to determine the true extent of
- the bss area used by Emacs.
-
- To be strictly correct, we dump the static and public bss areas
- used by Emacs separately if non-overlapping (since otherwise we are
- dumping bss data belonging to system libraries, eg. the static bss
- system data on the Alpha). */
-
- bss_start = my_begbss;
- bss_size = my_endbss - my_begbss;
- bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header);
- if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header))
- {
- printf ("Uninitialized data is not in a single section...bailing\n");
- exit (1);
- }
- /* Compute how much the .bss section's raw data will grow. */
- extra_bss_size =
- ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section),
- nt_header->OptionalHeader.FileAlignment)
- - bss_section->SizeOfRawData;
-
- bss_start_static = my_begbss_static;
- bss_size_static = my_endbss_static - my_begbss_static;
- bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static),
nt_header);
- if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static),
nt_header))
- {
- printf ("Uninitialized static data is not in a single
section...bailing\n");
- exit (1);
- }
- /* Compute how much the static .bss section's raw data will grow. */
- extra_bss_size_static =
- ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static),
bss_section_static),
- nt_header->OptionalHeader.FileAlignment)
- - bss_section_static->SizeOfRawData;
-
- /* Combine the bss sections into one if they overlap. */
-#ifdef _ALPHA_
- overlap = 1; /* force all bss data to be dumped */
-#else
- overlap = 0;
-#endif
- if (bss_start < bss_start_static)
- {
- if (bss_start_static < bss_start + bss_size)
- overlap = 1;
- }
- else
- {
- if (bss_start < bss_start_static + bss_size_static)
- overlap = 1;
- }
- if (overlap)
- {
- if (bss_section != bss_section_static)
- {
- printf ("BSS data not in a single section...bailing\n");
- exit (1);
- }
- bss_start = min (bss_start, bss_start_static);
- bss_size = max (my_endbss, my_endbss_static) - bss_start;
- bss_section_static = 0;
- extra_bss_size = max (extra_bss_size, extra_bss_size_static);
- extra_bss_size_static = 0;
- }
-}
-
-/* Format to print a DWORD_PTR value. */
-#if defined MINGW_W64 && defined _WIN64
-# define pDWP "16llx"
-#else
-# define pDWP "08lx"
-#endif
-
-/* The dump routines. */
-
-void
-copy_executable_and_dump_data (file_data *p_infile,
- file_data *p_outfile)
-{
- unsigned char *dst, *dst_save;
- PIMAGE_DOS_HEADER dos_header;
- PIMAGE_NT_HEADERS nt_header;
- PIMAGE_NT_HEADERS dst_nt_header;
- PIMAGE_SECTION_HEADER section;
- PIMAGE_SECTION_HEADER dst_section;
- DWORD_PTR offset;
- int i;
- int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0;
-
-#define COPY_CHUNK(message, src, size, verbose)
\
- do {
\
- unsigned char *s = (void *)(src);
\
- DWORD_PTR count = (size); \
- if (verbose)
\
- {
\
- printf ("%s\n", (message));
\
- printf ("\t0x%"pDWP" Offset in input file.\n", (DWORD_PTR)(s -
p_infile->file_base)); \
- printf ("\t0x%"pDWP" Offset in output file.\n", (DWORD_PTR)(dst -
p_outfile->file_base)); \
- printf ("\t0x%"pDWP" Size in bytes.\n", count);
\
- }
\
- memcpy (dst, s, count);
\
- dst += count;
\
- } while (0)
-
-#define COPY_PROC_CHUNK(message, src, size, verbose)
\
- do {
\
- unsigned char *s = (void *)(src);
\
- DWORD_PTR count = (size); \
- if (verbose)
\
- {
\
- printf ("%s\n", (message));
\
- printf ("\t0x%p Address in process.\n", s);
\
- printf ("\t0x%p Base output file.\n", p_outfile->file_base); \
- printf ("\t0x%"pDWP" Offset in output file.\n", (DWORD_PTR)(dst -
p_outfile->file_base)); \
- printf ("\t0x%p Address in output file.\n", dst); \
- printf ("\t0x%"pDWP" Size in bytes.\n", count);
\
- }
\
- memcpy (dst, s, count);
\
- dst += count;
\
- } while (0)
-
-#define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile)
-#define ROUND_UP_DST(align) \
- (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align)))
-#define ROUND_UP_DST_AND_ZERO(align)
\
- do {
\
- unsigned char *newdst = p_outfile->file_base
\
- + ROUND_UP (DST_TO_OFFSET (), (align));
\
- /* Zero the alignment slop; it may actually initialize real data. */
\
- memset (dst, 0, newdst - dst);
\
- dst = newdst;
\
- } while (0)
-
- /* Copy the source image sequentially, ie. section by section after
- copying the headers and section table, to simplify the process of
- dumping the raw data for the bss and heap sections.
-
- Note that dst is updated implicitly by each COPY_CHUNK. */
-
- dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base;
- nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
- dos_header->e_lfanew);
- section = IMAGE_FIRST_SECTION (nt_header);
-
- dst = (unsigned char *) p_outfile->file_base;
-
- COPY_CHUNK ("Copying DOS header...", dos_header,
- (DWORD_PTR) nt_header - (DWORD_PTR) dos_header, be_verbose);
- dst_nt_header = (PIMAGE_NT_HEADERS) dst;
- COPY_CHUNK ("Copying NT header...", nt_header,
- (DWORD_PTR) section - (DWORD_PTR) nt_header, be_verbose);
- dst_section = (PIMAGE_SECTION_HEADER) dst;
- COPY_CHUNK ("Copying section table...", section,
- nt_header->FileHeader.NumberOfSections * sizeof (*section),
- be_verbose);
-
- /* Align the first section's raw data area, and set the header size
- field accordingly. */
- ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
- dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET ();
-
- for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
- {
- char msg[100];
- /* Windows section names are fixed 8-char strings, only
- zero-terminated if the name is shorter than 8 characters. */
- sprintf (msg, "Copying raw data for %.8s...", section->Name);
-
- dst_save = dst;
-
- /* Update the file-relative offset for this section's raw data (if
- it has any) in case things have been relocated; we will update
- the other offsets below once we know where everything is. */
- if (dst_section->PointerToRawData)
- dst_section->PointerToRawData = DST_TO_OFFSET ();
-
- /* Can always copy the original raw data. */
- COPY_CHUNK
- (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile),
- section->SizeOfRawData, be_verbose);
- /* Ensure alignment slop is zeroed. */
- ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment);
-
- /* Note that various sections below may be aliases. */
- if (section == data_section)
- {
- dst = dst_save
- + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section);
- COPY_PROC_CHUNK ("Dumping initialized data...",
- data_start, data_size, be_verbose);
- dst = dst_save + dst_section->SizeOfRawData;
- }
- if (section == bss_section)
- {
- /* Dump contents of bss variables, adjusting the section's raw
- data size as necessary. */
- dst = dst_save
- + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section);
- COPY_PROC_CHUNK ("Dumping bss data...", bss_start,
- bss_size, be_verbose);
- ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
- dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
- /* Determine new size of raw data area. */
- dst = max (dst, dst_save + dst_section->SizeOfRawData);
- dst_section->SizeOfRawData = dst - dst_save;
- dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
- dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
- }
- if (section == bss_section_static)
- {
- /* Dump contents of static bss variables, adjusting the
- section's raw data size as necessary. */
- dst = dst_save
- + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static),
dst_section);
- COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static,
- bss_size_static, be_verbose);
- ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
- dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile);
- /* Determine new size of raw data area. */
- dst = max (dst, dst_save + dst_section->SizeOfRawData);
- dst_section->SizeOfRawData = dst - dst_save;
- dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
- dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
- }
-
- /* Align the section's raw data area. */
- ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment);
-
- section++;
- dst_section++;
- }
-
- /* Copy remainder of source image. */
- do
- section--;
- while (section->PointerToRawData == 0);
- offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData,
- nt_header->OptionalHeader.FileAlignment);
- COPY_CHUNK
- ("Copying remainder of executable...",
- OFFSET_TO_PTR (offset, p_infile),
- p_infile->size - offset, be_verbose);
-
- /* Final size for new image. */
- p_outfile->size = DST_TO_OFFSET ();
-
- /* Now patch up remaining file-relative offsets. */
- section = IMAGE_FIRST_SECTION (nt_header);
- dst_section = IMAGE_FIRST_SECTION (dst_nt_header);
-
-#define ADJUST_OFFSET(var) \
- do { \
- if ((var) != 0) \
- (var) = relocate_offset ((var), nt_header, dst_nt_header); \
- } while (0)
-
- dst_nt_header->OptionalHeader.SizeOfInitializedData = 0;
- dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0;
- for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++)
- {
- /* Recompute data sizes for completeness. */
- if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
- dst_nt_header->OptionalHeader.SizeOfInitializedData +=
- ROUND_UP (dst_section[i].Misc.VirtualSize,
dst_nt_header->OptionalHeader.FileAlignment);
- else if (dst_section[i].Characteristics &
IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- dst_nt_header->OptionalHeader.SizeOfUninitializedData +=
- ROUND_UP (dst_section[i].Misc.VirtualSize,
dst_nt_header->OptionalHeader.FileAlignment);
-
- ADJUST_OFFSET (dst_section[i].PointerToLinenumbers);
- }
-
- ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable);
-
- /* Update offsets in debug directory entries. */
- {
- IMAGE_DATA_DIRECTORY debug_dir =
- dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
- PIMAGE_DEBUG_DIRECTORY debug_entry;
-
- section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header);
- if (section)
- {
- debug_entry = (PIMAGE_DEBUG_DIRECTORY)
- (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) +
p_outfile->file_base);
- debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY);
-
- for (i = 0; i < debug_dir.Size; i++, debug_entry++)
- ADJUST_OFFSET (debug_entry->PointerToRawData);
- }
- }
-}
-
-
-/* Dump out .data and .bss sections into a new executable. */
-void
-unexec (const char *new_name, const char *old_name)
-{
- file_data in_file, out_file;
- char out_filename[MAX_PATH], in_filename[MAX_PATH], new_name_a[MAX_PATH];
- unsigned long size;
- char *p;
- char *q;
-
- /* Ignore old_name, and get our actual location from the OS. */
- if (!GetModuleFileNameA (NULL, in_filename, MAX_PATH))
- abort ();
-
- /* Can't use dostounix_filename here, since that needs its file name
- argument encoded in UTF-8. */
- for (p = in_filename; *p; p = CharNextA (p))
- if (*p == '\\')
- *p = '/';
-
- strcpy (out_filename, in_filename);
- filename_to_ansi (new_name, new_name_a);
-
- /* Change the base of the output filename to match the requested name. */
- if ((p = strrchr (out_filename, '/')) == NULL)
- abort ();
- /* The filenames have already been expanded, and will be in Unix
- format, so it is safe to expect an absolute name. */
- if ((q = strrchr (new_name_a, '/')) == NULL)
- abort ();
- strcpy (p, q);
-
-#ifdef ENABLE_CHECKING
- report_temacs_memory_usage ();
-#endif
-
- /* Make sure that the output filename has the ".exe" extension...patch
- it up if not. */
- p = out_filename + strlen (out_filename) - 4;
- if (strcmp (p, ".exe"))
- strcat (out_filename, ".exe");
-
- printf ("Dumping from %s\n", in_filename);
- printf (" to %s\n", out_filename);
-
- /* Open the undumped executable file. */
- if (!open_input_file (&in_file, in_filename))
- {
- printf ("Failed to open %s (%lu)...bailing.\n",
- in_filename, GetLastError ());
- exit (1);
- }
-
- /* Get the interesting section info, like start and size of .bss... */
- get_section_info (&in_file);
-
- /* The size of the dumped executable is the size of the original
- executable plus the size of the heap and the size of the .bss section. */
- size = in_file.size +
- extra_bss_size +
- extra_bss_size_static;
- if (!open_output_file (&out_file, out_filename, size))
- {
- printf ("Failed to open %s (%lu)...bailing.\n",
- out_filename, GetLastError ());
- exit (1);
- }
-
- copy_executable_and_dump_data (&in_file, &out_file);
-
- /* Patch up header fields; profiler is picky about this. */
- {
- PIMAGE_DOS_HEADER dos_header;
- PIMAGE_NT_HEADERS nt_header;
- HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
- DWORD headersum;
- DWORD checksum;
-
- dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
- nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header +
dos_header->e_lfanew);
-
- nt_header->OptionalHeader.CheckSum = 0;
- /* nt_header->FileHeader.TimeDateStamp = time (NULL); */
- /* dos_header->e_cp = size / 512; */
- /* nt_header->OptionalHeader.SizeOfImage = size; */
-
- pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp,
"CheckSumMappedFile");
- if (pfnCheckSumMappedFile)
- {
- /* nt_header->FileHeader.TimeDateStamp = time (NULL); */
- pfnCheckSumMappedFile (out_file.file_base,
- out_file.size,
- &headersum,
- &checksum);
- nt_header->OptionalHeader.CheckSum = checksum;
- }
- FreeLibrary (hImagehelp);
- }
-
- close_file_data (&in_file);
- close_file_data (&out_file);
-}
-
-/* eof */
- branch scratch/no-purespace created (now 1e8513ee38e), Pip Cet, 2024/08/20
- scratch/no-purespace 2f3a9111981 04/13: Unexec removal: Adjust and simplify W32-specific code, Pip Cet, 2024/08/20
- scratch/no-purespace ec121292d5c 01/13: Unexec removal: Remove obsolete files,
Pip Cet <=
- scratch/no-purespace 04350a6ece0 03/13: Unexec removal: Remove HYBRID_MALLOC support, Pip Cet, 2024/08/20
- scratch/no-purespace d1fc482192e 05/13: Pure storage removal: Remove puresize.h, Pip Cet, 2024/08/20
- scratch/no-purespace 5f48bd7f026 09/13: Pure storage removal: Remove purecopy hash table flag, Pip Cet, 2024/08/20
- scratch/no-purespace f0cf0c12ace 02/13: Unexec removal: Main part, Pip Cet, 2024/08/20
- scratch/no-purespace 46a4894244d 06/13: Pure storage removal: Main part, Pip Cet, 2024/08/20
- scratch/no-purespace 5099385e63d 10/13: Pure storage removal: Remove docstring hack, Pip Cet, 2024/08/20
- scratch/no-purespace 813b4414b02 12/13: Pure storage removal: Remove documentation, Pip Cet, 2024/08/20
- scratch/no-purespace 7ef3be39939 11/13: Pure storage removal: Adjust nativecomp code, Pip Cet, 2024/08/20
- scratch/no-purespace 1e8513ee38e 13/13: Pure storage removal: Bump nativecomp ABI, Pip Cet, 2024/08/20
- scratch/no-purespace 289e5dc03a0 08/13: Pure storage removal: Remove support for pinned objects, Pip Cet, 2024/08/20