* lisp/emacs-lisp/easy-mmode.el (define-minor-mode): Use mode function
[emacs.git] / src / unexcw.c
blob72456b33ec4c1d062a429a29c14e7621460a219f
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 /* emacs symbols that indicate where bss and data end for emacs internals */
38 extern char my_endbss[];
39 extern char my_edata[];
42 ** header for Windows executable files
44 typedef struct
46 FILHDR file_header;
47 PEAOUTHDR file_optional_header;
48 SCNHDR section_header[32];
49 } exe_header_t;
51 int debug_unexcw = 0;
54 ** Read the header from the executable into memory so we can more easily access it.
56 static exe_header_t *
57 read_exe_header (int fd, exe_header_t * exe_header_buffer)
59 int i;
60 int ret;
62 assert (fd >= 0);
63 assert (exe_header_buffer != 0);
65 ret = lseek (fd, 0L, SEEK_SET);
66 assert (ret != -1);
68 ret =
69 read (fd, &exe_header_buffer->file_header,
70 sizeof (exe_header_buffer->file_header));
71 assert (ret == sizeof (exe_header_buffer->file_header));
73 assert (exe_header_buffer->file_header.e_magic == 0x5a4d);
74 assert (exe_header_buffer->file_header.nt_signature == 0x4550);
75 #ifdef __x86_64__
76 assert (exe_header_buffer->file_header.f_magic == 0x8664);
77 #else
78 assert (exe_header_buffer->file_header.f_magic == 0x014c);
79 #endif
80 assert (exe_header_buffer->file_header.f_nscns > 0);
81 assert (exe_header_buffer->file_header.f_nscns <=
82 ARRAYELTS (exe_header_buffer->section_header));
83 assert (exe_header_buffer->file_header.f_opthdr > 0);
85 ret =
86 read (fd, &exe_header_buffer->file_optional_header,
87 sizeof (exe_header_buffer->file_optional_header));
88 assert (ret == sizeof (exe_header_buffer->file_optional_header));
90 #ifdef __x86_64__
91 assert (exe_header_buffer->file_optional_header.magic == 0x020b);
92 #else
93 assert (exe_header_buffer->file_optional_header.magic == 0x010b);
94 #endif
96 for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
98 ret =
99 read (fd, &exe_header_buffer->section_header[i],
100 sizeof (exe_header_buffer->section_header[i]));
101 assert (ret == sizeof (exe_header_buffer->section_header[i]));
104 return (exe_header_buffer);
108 ** Fix the dumped emacs executable:
110 ** - copy .data section data of interest from running executable into
111 ** output .exe file
113 ** - convert .bss section into an initialized data section (like
114 ** .data) and copy .bss section data of interest from running
115 ** executable into output .exe file
117 static void
118 fixup_executable (int fd)
120 exe_header_t exe_header_buffer;
121 exe_header_t *exe_header;
122 int i;
123 int ret;
124 int found_data = 0;
125 int found_bss = 0;
127 exe_header = read_exe_header (fd, &exe_header_buffer);
128 assert (exe_header != 0);
130 assert (exe_header->file_header.f_nscns > 0);
131 for (i = 0; i < exe_header->file_header.f_nscns; ++i)
133 unsigned long start_address =
134 exe_header->section_header[i].s_vaddr +
135 exe_header->file_optional_header.ImageBase;
136 unsigned long end_address =
137 exe_header->section_header[i].s_vaddr +
138 exe_header->file_optional_header.ImageBase +
139 exe_header->section_header[i].s_paddr;
140 if (debug_unexcw)
141 printf ("%8s start %#lx end %#lx\n",
142 exe_header->section_header[i].s_name,
143 start_address, end_address);
144 if (my_edata >= (char *) start_address
145 && my_edata < (char *) end_address)
147 /* data section */
148 ret =
149 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
150 SEEK_SET);
151 assert (ret != -1);
152 ret =
153 write (fd, (char *) start_address,
154 my_edata - (char *) start_address);
155 assert (ret == my_edata - (char *) start_address);
156 ++found_data;
157 if (debug_unexcw)
158 printf (" .data, mem start %#lx mem length %d\n",
159 start_address, my_edata - (char *) start_address);
160 if (debug_unexcw)
161 printf (" .data, file start %d file length %d\n",
162 (int) exe_header->section_header[i].s_scnptr,
163 (int) exe_header->section_header[i].s_paddr);
165 else if (my_endbss >= (char *) start_address
166 && my_endbss < (char *) end_address)
168 /* bss section */
169 ++found_bss;
170 if (exe_header->section_header[i].s_flags & 0x00000080)
172 /* convert uninitialized data section to initialized data section */
173 struct stat statbuf;
174 ret = fstat (fd, &statbuf);
175 assert (ret != -1);
177 exe_header->section_header[i].s_flags &= ~0x00000080;
178 exe_header->section_header[i].s_flags |= 0x00000040;
180 exe_header->section_header[i].s_scnptr =
181 (statbuf.st_size +
182 exe_header->file_optional_header.FileAlignment) /
183 exe_header->file_optional_header.FileAlignment *
184 exe_header->file_optional_header.FileAlignment;
186 exe_header->section_header[i].s_size =
187 (exe_header->section_header[i].s_paddr +
188 exe_header->file_optional_header.FileAlignment) /
189 exe_header->file_optional_header.FileAlignment *
190 exe_header->file_optional_header.FileAlignment;
192 /* Make sure the generated bootstrap binary isn't
193 * sparse. NT doesn't use a file cache for sparse
194 * executables, so if we bootstrap Emacs using a sparse
195 * bootstrap-emacs.exe, bootstrap takes about twenty
196 * times longer than it would otherwise. */
198 ret = posix_fallocate (fd,
199 ( exe_header->section_header[i].s_scnptr +
200 exe_header->section_header[i].s_size ),
203 assert (ret != -1);
205 ret =
206 lseek (fd,
207 (long) (exe_header->section_header[i].s_scnptr +
208 exe_header->section_header[i].s_size - 1),
209 SEEK_SET);
210 assert (ret != -1);
211 ret = write (fd, "", 1);
212 assert (ret == 1);
214 ret =
215 lseek (fd,
216 (long) ((char *) &exe_header->section_header[i] -
217 (char *) exe_header), SEEK_SET);
218 assert (ret != -1);
219 ret =
220 write (fd, &exe_header->section_header[i],
221 sizeof (exe_header->section_header[i]));
222 assert (ret == sizeof (exe_header->section_header[i]));
223 if (debug_unexcw)
224 printf (" seek to %ld, write %d\n",
225 (long) ((char *) &exe_header->section_header[i] -
226 (char *) exe_header),
227 sizeof (exe_header->section_header[i]));
229 /* write initialized data section */
230 ret =
231 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
232 SEEK_SET);
233 assert (ret != -1);
234 ret =
235 write (fd, (char *) start_address,
236 my_endbss - (char *) start_address);
237 assert (ret == (my_endbss - (char *) start_address));
238 if (debug_unexcw)
239 printf (" .bss, mem start %#lx mem length %d\n",
240 start_address, my_endbss - (char *) start_address);
241 if (debug_unexcw)
242 printf (" .bss, file start %d file length %d\n",
243 (int) exe_header->section_header[i].s_scnptr,
244 (int) exe_header->section_header[i].s_paddr);
247 assert (found_bss == 1);
248 assert (found_data == 1);
252 ** Windows likes .exe suffixes on executables.
254 static char *
255 add_exe_suffix_if_necessary (const char *name, char *modified)
257 int i = strlen (name);
258 if (i <= (sizeof (DOTEXE) - 1))
260 sprintf (modified, "%s%s", name, DOTEXE);
262 else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
264 strcpy (modified, name);
266 else
268 sprintf (modified, "%s%s", name, DOTEXE);
270 return (modified);
273 void
274 unexec (const char *outfile, const char *infile)
276 char infile_buffer[FILENAME_MAX];
277 char outfile_buffer[FILENAME_MAX];
278 int fd_in;
279 int fd_out;
280 int ret;
281 int ret2;
283 report_sheap_usage (1);
285 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
286 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
288 fd_in = emacs_open (infile, O_RDONLY | O_BINARY, 0);
289 assert (fd_in >= 0);
290 fd_out = emacs_open (outfile, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0755);
291 assert (fd_out >= 0);
292 for (;;)
294 char buffer[4096];
295 ret = read (fd_in, buffer, sizeof (buffer));
296 if (ret == 0)
298 /* eof */
299 break;
301 assert (ret > 0);
302 /* data */
303 ret2 = write (fd_out, buffer, ret);
304 assert (ret2 == ret);
306 ret = emacs_close (fd_in);
307 assert (ret == 0);
309 bss_sbrk_did_unexec = 1;
310 fixup_executable (fd_out);
311 bss_sbrk_did_unexec = 0;
313 ret = emacs_close (fd_out);
314 assert (ret == 0);