2 Copyright (C) 1988, 1994 Free Software Foundation, Inc.
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Synched up with: FSF 19.31. */
26 On 80386 Xenix, segmentation screws prevent us from modifying the text
27 segment at all. We basically just plug a new value for "data segment
28 size" into the countless headers and copy the other records straight
29 through. The data segment is ORG'ed at the xs_rbase value of the data
30 segment's xseg record (always @ 0x1880000, thanks to the "sophisticated
31 memory management hardware" of the chip) and extends to sbrk(0), exactly.
32 This code is afraid to malloc (should it be?), and alloca has to be the
33 wimpy, malloc-based version; consequently, data is usually copied in
40 #include <sys/types.h>
48 static void fatal_unexec ();
50 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
52 if (read(_fd, _buffer, _size) != _size) \
53 fatal_unexec(_error_message, _error_arg);
55 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
56 if (write(_fd, _buffer, _size) != _size) \
57 fatal_unexec(_error_message, _error_arg);
59 #define SEEK(_fd, _position, _error_message, _error_arg) \
61 if (lseek(_fd, _position, L_SET) != _position) \
62 fatal_unexec(_error_message, _error_arg);
65 extern char *strerror ();
72 /* Should check the magic number of the old executable;
80 unexec (new_name, a_name, data_start, bss_start, entry_address)
81 char *new_name, *a_name;
82 unsigned data_start, bss_start, entry_address;
84 char *sbrk (), *datalim = sbrk (0), *data_org;
85 long segpos, textseen, textpos, textlen, datapos, datadiff, datalen;
87 struct xexec u_xexec, /* a.out header */
89 struct xext u_xext, /* extended header */
91 struct xseg u_xseg, /* segment table entry */
93 int i, nsegs, isdata = 0, infd, outfd;
95 infd = open (a_name, O_RDONLY, 0);
96 if (infd < 0) fatal_unexec ("opening %s", a_name);
98 outfd = creat (new_name, 0666);
99 if (outfd < 0) fatal_unexec ("creating %s", new_name);
101 READ (infd, u_xexecp, sizeof (struct xexec),
102 "error reading %s", a_name);
103 check_exec (u_xexecp);
104 READ (infd, u_xextp, sizeof (struct xext),
105 "error reading %s", a_name);
106 segpos = u_xextp->xe_segpos;
107 nsegs = u_xextp->xe_segsize / sizeof (struct xseg);
108 SEEK (infd, segpos, "seek error on %s", a_name);
109 for (i = 0; i < nsegs; i ++)
111 READ (infd, u_xsegp, sizeof (struct xseg),
112 "error reading %s", a_name);
113 switch (u_xsegp->xs_type)
119 textpos = u_xsegp->xs_filpos;
120 textlen = u_xsegp->xs_psize;
123 fatal_unexec ("invalid text segment in %s", a_name);
129 datapos = u_xsegp->xs_filpos;
130 datalen = datalim - (data_org = (char *)(u_xsegp->xs_rbase));
131 datadiff = datalen - u_xsegp->xs_psize;
134 fatal_unexec ("invalid data segment in %s", a_name);
139 fatal_unexec ("invalid segment record in %s", a_name);
143 u_xexecp->x_data = datalen;
145 WRITE (outfd, u_xexecp, sizeof (struct xexec),
146 "error writing %s", new_name);
147 WRITE (outfd, u_xextp, sizeof (struct xext),
148 "error writing %s", new_name);
149 SEEK (infd, segpos, "seek error on %s", a_name);
150 SEEK (outfd, segpos, "seek error on %s", new_name);
152 /* Copy the text segment record verbatim. */
154 copyrec (infd, outfd, sizeof (struct xseg), a_name, new_name);
156 /* Read, modify, write the data segment record. */
158 READ (infd, u_xsegp, sizeof (struct xseg),
159 "error reading %s", a_name);
160 u_xsegp->xs_psize = u_xsegp->xs_vsize = datalen;
161 u_xsegp->xs_attr &= (~XS_AITER & ~XS_ABSS);
162 WRITE (outfd, u_xsegp, sizeof (struct xseg),
163 "error writing %s", new_name);
165 /* Now copy any additional segment records, adjusting their
166 file position field */
168 for (i = 2; i < nsegs; i++)
170 READ (infd, u_xsegp, sizeof (struct xseg),
171 "error reading %s", a_name);
172 u_xsegp->xs_filpos += datadiff;
173 WRITE (outfd, u_xsegp, sizeof (struct xseg),
174 "error writing %s", new_name);
177 SEEK (infd, textpos, "seek error on %s", a_name);
178 SEEK (outfd, textpos, "seek error on %s", new_name);
179 copyrec (infd, outfd, textlen, a_name, new_name);
181 SEEK (outfd, datapos, "seek error on %s", new_name);
182 WRITE (outfd, data_org, datalen,
183 "write error on %s", new_name);
185 for (i = 2, segpos += (2 * sizeof (struct xseg));
187 i++, segpos += sizeof (struct xseg))
189 SEEK (infd, segpos, "seek error on %s", a_name);
190 READ (infd, u_xsegp, sizeof (struct xseg),
191 "read error on %s", a_name);
192 SEEK (infd, u_xsegp->xs_filpos, "seek error on %s", a_name);
193 /* We should be at eof in the output file here, but we must seek
194 because the xs_filpos and xs_psize fields in symbol table
195 segments are inconsistent. */
196 SEEK (outfd, u_xsegp->xs_filpos + datadiff, "seek error on %s", new_name);
197 copyrec (infd, outfd, u_xsegp->xs_psize, a_name, new_name);
205 copyrec (infd, outfd, len, in_name, out_name)
206 int infd, outfd, len;
207 char *in_name, *out_name;
217 READ (infd, buf, chunk, "error reading %s", in_name);
218 WRITE (outfd, buf, chunk, "error writing %s", out_name);
226 * After successfully building the new a.out, mark it executable
233 int um = umask (777);
235 if (stat (name, &sbuf) < 0)
236 fatal_unexec ("getting protection on %s", name);
237 sbuf.st_mode |= 0111 & ~um;
238 if (chmod (name, sbuf.st_mode) < 0)
239 fatal_unexec ("setting protection on %s", name);
243 fatal_unexec (s, va_alist)
248 fputs ("unexec: unexpected end of file, ", stderr);
250 fprintf (stderr, "unexec: %s, ", strerror (errno));
252 _doprnt (s, ap, stderr);
253 fputs (".\n", stderr);