[TMP] enable load_prefer_newer
[bpt/emacs.git] / src / unexcw.c
1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
3
4 Copyright (C) 2004-2014 Free Software Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
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.
12
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.
17
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/>. */
20
21 #include <config.h>
22 #include "unexec.h"
23 #include "lisp.h"
24
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <a.out.h>
28 #include <unistd.h>
29 #include <assert.h>
30
31 #define DOTEXE ".exe"
32
33 extern void report_sheap_usage (int);
34
35 extern int bss_sbrk_did_unexec;
36
37 extern int __malloc_initialized;
38
39 /* emacs symbols that indicate where bss and data end for emacs internals */
40 extern char my_endbss[];
41 extern char my_edata[];
42
43 /*
44 ** header for Windows executable files
45 */
46 typedef struct
47 {
48 FILHDR file_header;
49 PEAOUTHDR file_optional_header;
50 SCNHDR section_header[32];
51 } exe_header_t;
52
53 int debug_unexcw = 0;
54
55 /*
56 ** Read the header from the executable into memory so we can more easily access it.
57 */
58 static exe_header_t *
59 read_exe_header (int fd, exe_header_t * exe_header_buffer)
60 {
61 int i;
62 int ret;
63
64 assert (fd >= 0);
65 assert (exe_header_buffer != 0);
66
67 ret = lseek (fd, 0L, SEEK_SET);
68 assert (ret != -1);
69
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));
74
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 ARRAYELTS (exe_header_buffer->section_header));
85 assert (exe_header_buffer->file_header.f_opthdr > 0);
86
87 ret =
88 read (fd, &exe_header_buffer->file_optional_header,
89 sizeof (exe_header_buffer->file_optional_header));
90 assert (ret == sizeof (exe_header_buffer->file_optional_header));
91
92 #ifdef __x86_64__
93 assert (exe_header_buffer->file_optional_header.magic == 0x020b);
94 #else
95 assert (exe_header_buffer->file_optional_header.magic == 0x010b);
96 #endif
97
98 for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
99 {
100 ret =
101 read (fd, &exe_header_buffer->section_header[i],
102 sizeof (exe_header_buffer->section_header[i]));
103 assert (ret == sizeof (exe_header_buffer->section_header[i]));
104 }
105
106 return (exe_header_buffer);
107 }
108
109 /*
110 ** Fix the dumped emacs executable:
111 **
112 ** - copy .data section data of interest from running executable into
113 ** output .exe file
114 **
115 ** - convert .bss section into an initialized data section (like
116 ** .data) and copy .bss section data of interest from running
117 ** executable into output .exe file
118 */
119 static void
120 fixup_executable (int fd)
121 {
122 exe_header_t exe_header_buffer;
123 exe_header_t *exe_header;
124 int i;
125 int ret;
126 int found_data = 0;
127 int found_bss = 0;
128
129 exe_header = read_exe_header (fd, &exe_header_buffer);
130 assert (exe_header != 0);
131
132 assert (exe_header->file_header.f_nscns > 0);
133 for (i = 0; i < exe_header->file_header.f_nscns; ++i)
134 {
135 unsigned long start_address =
136 exe_header->section_header[i].s_vaddr +
137 exe_header->file_optional_header.ImageBase;
138 unsigned long end_address =
139 exe_header->section_header[i].s_vaddr +
140 exe_header->file_optional_header.ImageBase +
141 exe_header->section_header[i].s_paddr;
142 if (debug_unexcw)
143 printf ("%8s start %#lx end %#lx\n",
144 exe_header->section_header[i].s_name,
145 start_address, end_address);
146 if (my_edata >= (char *) start_address
147 && my_edata < (char *) end_address)
148 {
149 /* data section */
150 ret =
151 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
152 SEEK_SET);
153 assert (ret != -1);
154 ret =
155 write (fd, (char *) start_address,
156 my_edata - (char *) start_address);
157 assert (ret == my_edata - (char *) start_address);
158 ++found_data;
159 if (debug_unexcw)
160 printf (" .data, mem start %#lx mem length %d\n",
161 start_address, my_edata - (char *) start_address);
162 if (debug_unexcw)
163 printf (" .data, file start %d file length %d\n",
164 (int) exe_header->section_header[i].s_scnptr,
165 (int) exe_header->section_header[i].s_paddr);
166 }
167 else if (my_endbss >= (char *) start_address
168 && my_endbss < (char *) end_address)
169 {
170 /* bss section */
171 ++found_bss;
172 if (exe_header->section_header[i].s_flags & 0x00000080)
173 {
174 /* convert uninitialized data section to initialized data section */
175 struct stat statbuf;
176 ret = fstat (fd, &statbuf);
177 assert (ret != -1);
178
179 exe_header->section_header[i].s_flags &= ~0x00000080;
180 exe_header->section_header[i].s_flags |= 0x00000040;
181
182 exe_header->section_header[i].s_scnptr =
183 (statbuf.st_size +
184 exe_header->file_optional_header.FileAlignment) /
185 exe_header->file_optional_header.FileAlignment *
186 exe_header->file_optional_header.FileAlignment;
187
188 exe_header->section_header[i].s_size =
189 (exe_header->section_header[i].s_paddr +
190 exe_header->file_optional_header.FileAlignment) /
191 exe_header->file_optional_header.FileAlignment *
192 exe_header->file_optional_header.FileAlignment;
193
194 /* Make sure the generated bootstrap binary isn't
195 * sparse. NT doesn't use a file cache for sparse
196 * executables, so if we bootstrap Emacs using a sparse
197 * bootstrap-emacs.exe, bootstrap takes about twenty
198 * times longer than it would otherwise. */
199
200 ret = posix_fallocate (fd,
201 ( exe_header->section_header[i].s_scnptr +
202 exe_header->section_header[i].s_size ),
203 1);
204
205 assert (ret != -1);
206
207 ret =
208 lseek (fd,
209 (long) (exe_header->section_header[i].s_scnptr +
210 exe_header->section_header[i].s_size - 1),
211 SEEK_SET);
212 assert (ret != -1);
213 ret = write (fd, "", 1);
214 assert (ret == 1);
215
216 ret =
217 lseek (fd,
218 (long) ((char *) &exe_header->section_header[i] -
219 (char *) exe_header), SEEK_SET);
220 assert (ret != -1);
221 ret =
222 write (fd, &exe_header->section_header[i],
223 sizeof (exe_header->section_header[i]));
224 assert (ret == sizeof (exe_header->section_header[i]));
225 if (debug_unexcw)
226 printf (" seek to %ld, write %d\n",
227 (long) ((char *) &exe_header->section_header[i] -
228 (char *) exe_header),
229 sizeof (exe_header->section_header[i]));
230 }
231 /* write initialized data section */
232 ret =
233 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
234 SEEK_SET);
235 assert (ret != -1);
236 /* force the dumped emacs to reinitialize malloc */
237 __malloc_initialized = 0;
238 ret =
239 write (fd, (char *) start_address,
240 my_endbss - (char *) start_address);
241 __malloc_initialized = 1;
242 assert (ret == (my_endbss - (char *) start_address));
243 if (debug_unexcw)
244 printf (" .bss, mem start %#lx mem length %d\n",
245 start_address, my_endbss - (char *) start_address);
246 if (debug_unexcw)
247 printf (" .bss, file start %d file length %d\n",
248 (int) exe_header->section_header[i].s_scnptr,
249 (int) exe_header->section_header[i].s_paddr);
250 }
251 }
252 assert (found_bss == 1);
253 assert (found_data == 1);
254 }
255
256 /*
257 ** Windows likes .exe suffixes on executables.
258 */
259 static char *
260 add_exe_suffix_if_necessary (const char *name, char *modified)
261 {
262 int i = strlen (name);
263 if (i <= (sizeof (DOTEXE) - 1))
264 {
265 sprintf (modified, "%s%s", name, DOTEXE);
266 }
267 else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
268 {
269 strcpy (modified, name);
270 }
271 else
272 {
273 sprintf (modified, "%s%s", name, DOTEXE);
274 }
275 return (modified);
276 }
277
278 void
279 unexec (const char *outfile, const char *infile)
280 {
281 char infile_buffer[FILENAME_MAX];
282 char outfile_buffer[FILENAME_MAX];
283 int fd_in;
284 int fd_out;
285 int ret;
286 int ret2;
287
288 report_sheap_usage (1);
289
290 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
291 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
292
293 fd_in = emacs_open (infile, O_RDONLY | O_BINARY, 0);
294 assert (fd_in >= 0);
295 fd_out = emacs_open (outfile, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0755);
296 assert (fd_out >= 0);
297 for (;;)
298 {
299 char buffer[4096];
300 ret = read (fd_in, buffer, sizeof (buffer));
301 if (ret == 0)
302 {
303 /* eof */
304 break;
305 }
306 assert (ret > 0);
307 /* data */
308 ret2 = write (fd_out, buffer, ret);
309 assert (ret2 == ret);
310 }
311 ret = emacs_close (fd_in);
312 assert (ret == 0);
313
314 bss_sbrk_did_unexec = 1;
315 fixup_executable (fd_out);
316 bss_sbrk_did_unexec = 0;
317
318 ret = emacs_close (fd_out);
319 assert (ret == 0);
320 }