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