Update copyright year to 2014 by running admin/update-copyright.
[emacs.git] / src / unexcw.c
blobfcca5e5cbf201c3169738d7fe7db3b3480736d0d
1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
4 Copyright (C) 2004-2014 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 #include <config.h>
22 #include "unexec.h"
23 #include "lisp.h"
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <a.out.h>
28 #include <unistd.h>
29 #include <assert.h>
31 #define DOTEXE ".exe"
33 extern void report_sheap_usage (int);
35 extern int bss_sbrk_did_unexec;
37 extern int __malloc_initialized;
39 /* emacs symbols that indicate where bss and data end for emacs internals */
40 extern char my_endbss[];
41 extern char my_edata[];
44 ** header for Windows executable files
46 typedef struct
48 FILHDR file_header;
49 PEAOUTHDR file_optional_header;
50 SCNHDR section_header[32];
51 } exe_header_t;
53 int debug_unexcw = 0;
56 ** Read the header from the executable into memory so we can more easily access it.
58 static exe_header_t *
59 read_exe_header (int fd, exe_header_t * exe_header_buffer)
61 int i;
62 int ret;
64 assert (fd >= 0);
65 assert (exe_header_buffer != 0);
67 ret = lseek (fd, 0L, SEEK_SET);
68 assert (ret != -1);
70 ret =
71 read (fd, &exe_header_buffer->file_header,
72 sizeof (exe_header_buffer->file_header));
73 assert (ret == sizeof (exe_header_buffer->file_header));
75 assert (exe_header_buffer->file_header.e_magic == 0x5a4d);
76 assert (exe_header_buffer->file_header.nt_signature == 0x4550);
77 #ifdef __x86_64__
78 assert (exe_header_buffer->file_header.f_magic == 0x8664);
79 #else
80 assert (exe_header_buffer->file_header.f_magic == 0x014c);
81 #endif
82 assert (exe_header_buffer->file_header.f_nscns > 0);
83 assert (exe_header_buffer->file_header.f_nscns <=
84 sizeof (exe_header_buffer->section_header) /
85 sizeof (exe_header_buffer->section_header[0]));
86 assert (exe_header_buffer->file_header.f_opthdr > 0);
88 ret =
89 read (fd, &exe_header_buffer->file_optional_header,
90 sizeof (exe_header_buffer->file_optional_header));
91 assert (ret == sizeof (exe_header_buffer->file_optional_header));
93 #ifdef __x86_64__
94 assert (exe_header_buffer->file_optional_header.magic == 0x020b);
95 #else
96 assert (exe_header_buffer->file_optional_header.magic == 0x010b);
97 #endif
99 for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
101 ret =
102 read (fd, &exe_header_buffer->section_header[i],
103 sizeof (exe_header_buffer->section_header[i]));
104 assert (ret == sizeof (exe_header_buffer->section_header[i]));
107 return (exe_header_buffer);
111 ** Fix the dumped emacs executable:
113 ** - copy .data section data of interest from running executable into
114 ** output .exe file
116 ** - convert .bss section into an initialized data section (like
117 ** .data) and copy .bss section data of interest from running
118 ** executable into output .exe file
120 static void
121 fixup_executable (int fd)
123 exe_header_t exe_header_buffer;
124 exe_header_t *exe_header;
125 int i;
126 int ret;
127 int found_data = 0;
128 int found_bss = 0;
130 exe_header = read_exe_header (fd, &exe_header_buffer);
131 assert (exe_header != 0);
133 assert (exe_header->file_header.f_nscns > 0);
134 for (i = 0; i < exe_header->file_header.f_nscns; ++i)
136 unsigned long start_address =
137 exe_header->section_header[i].s_vaddr +
138 exe_header->file_optional_header.ImageBase;
139 unsigned long end_address =
140 exe_header->section_header[i].s_vaddr +
141 exe_header->file_optional_header.ImageBase +
142 exe_header->section_header[i].s_paddr;
143 if (debug_unexcw)
144 printf ("%8s start %#lx end %#lx\n",
145 exe_header->section_header[i].s_name,
146 start_address, end_address);
147 if (my_edata >= (char *) start_address
148 && my_edata < (char *) end_address)
150 /* data section */
151 ret =
152 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
153 SEEK_SET);
154 assert (ret != -1);
155 ret =
156 write (fd, (char *) start_address,
157 my_edata - (char *) start_address);
158 assert (ret == my_edata - (char *) start_address);
159 ++found_data;
160 if (debug_unexcw)
161 printf (" .data, mem start %#lx mem length %d\n",
162 start_address, my_edata - (char *) start_address);
163 if (debug_unexcw)
164 printf (" .data, file start %d file length %d\n",
165 (int) exe_header->section_header[i].s_scnptr,
166 (int) exe_header->section_header[i].s_paddr);
168 else if (my_endbss >= (char *) start_address
169 && my_endbss < (char *) end_address)
171 /* bss section */
172 ++found_bss;
173 if (exe_header->section_header[i].s_flags & 0x00000080)
175 /* convert uninitialized data section to initialized data section */
176 struct stat statbuf;
177 ret = fstat (fd, &statbuf);
178 assert (ret != -1);
180 exe_header->section_header[i].s_flags &= ~0x00000080;
181 exe_header->section_header[i].s_flags |= 0x00000040;
183 exe_header->section_header[i].s_scnptr =
184 (statbuf.st_size +
185 exe_header->file_optional_header.FileAlignment) /
186 exe_header->file_optional_header.FileAlignment *
187 exe_header->file_optional_header.FileAlignment;
189 exe_header->section_header[i].s_size =
190 (exe_header->section_header[i].s_paddr +
191 exe_header->file_optional_header.FileAlignment) /
192 exe_header->file_optional_header.FileAlignment *
193 exe_header->file_optional_header.FileAlignment;
195 /* Make sure the generated bootstrap binary isn't
196 * sparse. NT doesn't use a file cache for sparse
197 * executables, so if we bootstrap Emacs using a sparse
198 * bootstrap-emacs.exe, bootstrap takes about twenty
199 * times longer than it would otherwise. */
201 ret = posix_fallocate (fd,
202 ( exe_header->section_header[i].s_scnptr +
203 exe_header->section_header[i].s_size ),
206 assert (ret != -1);
208 ret =
209 lseek (fd,
210 (long) (exe_header->section_header[i].s_scnptr +
211 exe_header->section_header[i].s_size - 1),
212 SEEK_SET);
213 assert (ret != -1);
214 ret = write (fd, "", 1);
215 assert (ret == 1);
217 ret =
218 lseek (fd,
219 (long) ((char *) &exe_header->section_header[i] -
220 (char *) exe_header), SEEK_SET);
221 assert (ret != -1);
222 ret =
223 write (fd, &exe_header->section_header[i],
224 sizeof (exe_header->section_header[i]));
225 assert (ret == sizeof (exe_header->section_header[i]));
226 if (debug_unexcw)
227 printf (" seek to %ld, write %d\n",
228 (long) ((char *) &exe_header->section_header[i] -
229 (char *) exe_header),
230 sizeof (exe_header->section_header[i]));
232 /* write initialized data section */
233 ret =
234 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
235 SEEK_SET);
236 assert (ret != -1);
237 /* force the dumped emacs to reinitialize malloc */
238 __malloc_initialized = 0;
239 ret =
240 write (fd, (char *) start_address,
241 my_endbss - (char *) start_address);
242 __malloc_initialized = 1;
243 assert (ret == (my_endbss - (char *) start_address));
244 if (debug_unexcw)
245 printf (" .bss, mem start %#lx mem length %d\n",
246 start_address, my_endbss - (char *) start_address);
247 if (debug_unexcw)
248 printf (" .bss, file start %d file length %d\n",
249 (int) exe_header->section_header[i].s_scnptr,
250 (int) exe_header->section_header[i].s_paddr);
253 assert (found_bss == 1);
254 assert (found_data == 1);
258 ** Windows likes .exe suffixes on executables.
260 static char *
261 add_exe_suffix_if_necessary (const char *name, char *modified)
263 int i = strlen (name);
264 if (i <= (sizeof (DOTEXE) - 1))
266 sprintf (modified, "%s%s", name, DOTEXE);
268 else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
270 strcpy (modified, name);
272 else
274 sprintf (modified, "%s%s", name, DOTEXE);
276 return (modified);
279 void
280 unexec (const char *outfile, const char *infile)
282 char infile_buffer[FILENAME_MAX];
283 char outfile_buffer[FILENAME_MAX];
284 int fd_in;
285 int fd_out;
286 int ret;
287 int ret2;
289 if (bss_sbrk_did_unexec)
291 /* can only dump once */
292 printf ("You can only dump Emacs once on this platform.\n");
293 return;
296 report_sheap_usage (1);
298 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
299 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
301 fd_in = emacs_open (infile, O_RDONLY | O_BINARY, 0);
302 assert (fd_in >= 0);
303 fd_out = emacs_open (outfile, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0755);
304 assert (fd_out >= 0);
305 for (;;)
307 char buffer[4096];
308 ret = read (fd_in, buffer, sizeof (buffer));
309 if (ret == 0)
311 /* eof */
312 break;
314 assert (ret > 0);
315 /* data */
316 ret2 = write (fd_out, buffer, ret);
317 assert (ret2 == ret);
319 ret = emacs_close (fd_in);
320 assert (ret == 0);
322 bss_sbrk_did_unexec = 1;
323 fixup_executable (fd_out);
324 bss_sbrk_did_unexec = 0;
326 ret = emacs_close (fd_out);
327 assert (ret == 0);