emacs-lisp/package.el: Move the compatibility-table building logic.
[emacs.git] / src / unexcw.c
blobbe8857878ebacadbbcc6389141751d4d638823fc
1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
4 Copyright (C) 2004-2015 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;
38 ** header for Windows executable files
40 typedef struct
42 FILHDR file_header;
43 PEAOUTHDR file_optional_header;
44 SCNHDR section_header[32];
45 } exe_header_t;
47 int debug_unexcw = 0;
50 ** Read the header from the executable into memory so we can more easily access it.
52 static exe_header_t *
53 read_exe_header (int fd, exe_header_t * exe_header_buffer)
55 int i;
56 int ret;
58 assert (fd >= 0);
59 assert (exe_header_buffer != 0);
61 ret = lseek (fd, 0L, SEEK_SET);
62 assert (ret != -1);
64 ret =
65 read (fd, &exe_header_buffer->file_header,
66 sizeof (exe_header_buffer->file_header));
67 assert (ret == sizeof (exe_header_buffer->file_header));
69 assert (exe_header_buffer->file_header.e_magic == 0x5a4d);
70 assert (exe_header_buffer->file_header.nt_signature == 0x4550);
71 #ifdef __x86_64__
72 assert (exe_header_buffer->file_header.f_magic == 0x8664);
73 #else
74 assert (exe_header_buffer->file_header.f_magic == 0x014c);
75 #endif
76 assert (exe_header_buffer->file_header.f_nscns > 0);
77 assert (exe_header_buffer->file_header.f_nscns <=
78 ARRAYELTS (exe_header_buffer->section_header));
79 assert (exe_header_buffer->file_header.f_opthdr > 0);
81 ret =
82 read (fd, &exe_header_buffer->file_optional_header,
83 sizeof (exe_header_buffer->file_optional_header));
84 assert (ret == sizeof (exe_header_buffer->file_optional_header));
86 #ifdef __x86_64__
87 assert (exe_header_buffer->file_optional_header.magic == 0x020b);
88 #else
89 assert (exe_header_buffer->file_optional_header.magic == 0x010b);
90 #endif
92 for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i)
94 ret =
95 read (fd, &exe_header_buffer->section_header[i],
96 sizeof (exe_header_buffer->section_header[i]));
97 assert (ret == sizeof (exe_header_buffer->section_header[i]));
100 return (exe_header_buffer);
104 ** Fix the dumped emacs executable:
106 ** - copy .data section data of interest from running executable into
107 ** output .exe file
109 ** - convert .bss section into an initialized data section (like
110 ** .data) and copy .bss section data of interest from running
111 ** executable into output .exe file
113 static void
114 fixup_executable (int fd)
116 exe_header_t exe_header_buffer;
117 exe_header_t *exe_header;
118 int i;
119 int ret;
120 int found_data = 0;
121 int found_bss = 0;
123 exe_header = read_exe_header (fd, &exe_header_buffer);
124 assert (exe_header != 0);
126 assert (exe_header->file_header.f_nscns > 0);
127 for (i = 0; i < exe_header->file_header.f_nscns; ++i)
129 unsigned long start_address =
130 exe_header->section_header[i].s_vaddr +
131 exe_header->file_optional_header.ImageBase;
132 unsigned long end_address =
133 exe_header->section_header[i].s_vaddr +
134 exe_header->file_optional_header.ImageBase +
135 exe_header->section_header[i].s_paddr;
136 if (debug_unexcw)
137 printf ("%8s start %#lx end %#lx\n",
138 exe_header->section_header[i].s_name,
139 start_address, end_address);
140 if (my_edata >= (char *) start_address
141 && my_edata < (char *) end_address)
143 /* data section */
144 ret =
145 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
146 SEEK_SET);
147 assert (ret != -1);
148 ret =
149 write (fd, (char *) start_address,
150 my_edata - (char *) start_address);
151 assert (ret == my_edata - (char *) start_address);
152 ++found_data;
153 if (debug_unexcw)
154 printf (" .data, mem start %#lx mem length %d\n",
155 start_address, my_edata - (char *) start_address);
156 if (debug_unexcw)
157 printf (" .data, file start %d file length %d\n",
158 (int) exe_header->section_header[i].s_scnptr,
159 (int) exe_header->section_header[i].s_paddr);
161 else if (my_endbss >= (char *) start_address
162 && my_endbss < (char *) end_address)
164 /* bss section */
165 ++found_bss;
166 if (exe_header->section_header[i].s_flags & 0x00000080)
168 /* convert uninitialized data section to initialized data section */
169 struct stat statbuf;
170 ret = fstat (fd, &statbuf);
171 assert (ret != -1);
173 exe_header->section_header[i].s_flags &= ~0x00000080;
174 exe_header->section_header[i].s_flags |= 0x00000040;
176 exe_header->section_header[i].s_scnptr =
177 (statbuf.st_size +
178 exe_header->file_optional_header.FileAlignment) /
179 exe_header->file_optional_header.FileAlignment *
180 exe_header->file_optional_header.FileAlignment;
182 exe_header->section_header[i].s_size =
183 (exe_header->section_header[i].s_paddr +
184 exe_header->file_optional_header.FileAlignment) /
185 exe_header->file_optional_header.FileAlignment *
186 exe_header->file_optional_header.FileAlignment;
188 /* Make sure the generated bootstrap binary isn't
189 * sparse. NT doesn't use a file cache for sparse
190 * executables, so if we bootstrap Emacs using a sparse
191 * bootstrap-emacs.exe, bootstrap takes about twenty
192 * times longer than it would otherwise. */
194 ret = posix_fallocate (fd,
195 ( exe_header->section_header[i].s_scnptr +
196 exe_header->section_header[i].s_size ),
199 assert (ret != -1);
201 ret =
202 lseek (fd,
203 (long) (exe_header->section_header[i].s_scnptr +
204 exe_header->section_header[i].s_size - 1),
205 SEEK_SET);
206 assert (ret != -1);
207 ret = write (fd, "", 1);
208 assert (ret == 1);
210 ret =
211 lseek (fd,
212 (long) ((char *) &exe_header->section_header[i] -
213 (char *) exe_header), SEEK_SET);
214 assert (ret != -1);
215 ret =
216 write (fd, &exe_header->section_header[i],
217 sizeof (exe_header->section_header[i]));
218 assert (ret == sizeof (exe_header->section_header[i]));
219 if (debug_unexcw)
220 printf (" seek to %ld, write %d\n",
221 (long) ((char *) &exe_header->section_header[i] -
222 (char *) exe_header),
223 sizeof (exe_header->section_header[i]));
225 /* write initialized data section */
226 ret =
227 lseek (fd, (long) (exe_header->section_header[i].s_scnptr),
228 SEEK_SET);
229 assert (ret != -1);
230 ret =
231 write (fd, (char *) start_address,
232 my_endbss - (char *) start_address);
233 assert (ret == (my_endbss - (char *) start_address));
234 if (debug_unexcw)
235 printf (" .bss, mem start %#lx mem length %d\n",
236 start_address, my_endbss - (char *) start_address);
237 if (debug_unexcw)
238 printf (" .bss, file start %d file length %d\n",
239 (int) exe_header->section_header[i].s_scnptr,
240 (int) exe_header->section_header[i].s_paddr);
243 assert (found_bss == 1);
244 assert (found_data == 1);
248 ** Windows likes .exe suffixes on executables.
250 static char *
251 add_exe_suffix_if_necessary (const char *name, char *modified)
253 int i = strlen (name);
254 if (i <= (sizeof (DOTEXE) - 1))
256 sprintf (modified, "%s%s", name, DOTEXE);
258 else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE))
260 strcpy (modified, name);
262 else
264 sprintf (modified, "%s%s", name, DOTEXE);
266 return (modified);
269 void
270 unexec (const char *outfile, const char *infile)
272 char infile_buffer[FILENAME_MAX];
273 char outfile_buffer[FILENAME_MAX];
274 int fd_in;
275 int fd_out;
276 int ret;
277 int ret2;
279 report_sheap_usage (1);
281 infile = add_exe_suffix_if_necessary (infile, infile_buffer);
282 outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
284 fd_in = emacs_open (infile, O_RDONLY | O_BINARY, 0);
285 assert (fd_in >= 0);
286 fd_out = emacs_open (outfile, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0755);
287 assert (fd_out >= 0);
288 for (;;)
290 char buffer[4096];
291 ret = read (fd_in, buffer, sizeof (buffer));
292 if (ret == 0)
294 /* eof */
295 break;
297 assert (ret > 0);
298 /* data */
299 ret2 = write (fd_out, buffer, ret);
300 assert (ret2 == ret);
302 ret = emacs_close (fd_in);
303 assert (ret == 0);
305 bss_sbrk_did_unexec = 1;
306 fixup_executable (fd_out);
307 bss_sbrk_did_unexec = 0;
309 ret = emacs_close (fd_out);
310 assert (ret == 0);