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