1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
4 Copyright (C) 2004-2018 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 (at
11 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 <https://www.gnu.org/licenses/>. */
33 ** header for Windows executable files
38 PEAOUTHDR file_optional_header
;
39 SCNHDR section_header
[32];
45 ** Read the header from the executable into memory so we can more easily access it.
48 read_exe_header (int fd
, exe_header_t
* exe_header_buffer
)
54 assert (exe_header_buffer
!= 0);
56 ret
= lseek (fd
, 0L, SEEK_SET
);
60 read (fd
, &exe_header_buffer
->file_header
,
61 sizeof (exe_header_buffer
->file_header
));
62 assert (ret
== sizeof (exe_header_buffer
->file_header
));
64 assert (exe_header_buffer
->file_header
.e_magic
== 0x5a4d);
65 assert (exe_header_buffer
->file_header
.nt_signature
== 0x4550);
67 assert (exe_header_buffer
->file_header
.f_magic
== 0x8664);
69 assert (exe_header_buffer
->file_header
.f_magic
== 0x014c);
71 assert (exe_header_buffer
->file_header
.f_nscns
> 0);
72 assert (exe_header_buffer
->file_header
.f_nscns
<=
73 ARRAYELTS (exe_header_buffer
->section_header
));
74 assert (exe_header_buffer
->file_header
.f_opthdr
> 0);
77 read (fd
, &exe_header_buffer
->file_optional_header
,
78 sizeof (exe_header_buffer
->file_optional_header
));
79 assert (ret
== sizeof (exe_header_buffer
->file_optional_header
));
82 assert (exe_header_buffer
->file_optional_header
.magic
== 0x020b);
84 assert (exe_header_buffer
->file_optional_header
.magic
== 0x010b);
87 for (i
= 0; i
< exe_header_buffer
->file_header
.f_nscns
; ++i
)
90 read (fd
, &exe_header_buffer
->section_header
[i
],
91 sizeof (exe_header_buffer
->section_header
[i
]));
92 assert (ret
== sizeof (exe_header_buffer
->section_header
[i
]));
95 return (exe_header_buffer
);
99 ** Fix the dumped emacs executable:
101 ** - copy .data section data of interest from running executable into
104 ** - convert .bss section into an initialized data section (like
105 ** .data) and copy .bss section data of interest from running
106 ** executable into output .exe file
109 fixup_executable (int fd
)
111 exe_header_t exe_header_buffer
;
112 exe_header_t
*exe_header
;
118 exe_header
= read_exe_header (fd
, &exe_header_buffer
);
119 assert (exe_header
!= 0);
121 assert (exe_header
->file_header
.f_nscns
> 0);
122 for (i
= 0; i
< exe_header
->file_header
.f_nscns
; ++i
)
124 unsigned long start_address
=
125 exe_header
->section_header
[i
].s_vaddr
+
126 exe_header
->file_optional_header
.ImageBase
;
127 unsigned long end_address
=
128 exe_header
->section_header
[i
].s_vaddr
+
129 exe_header
->file_optional_header
.ImageBase
+
130 exe_header
->section_header
[i
].s_paddr
;
132 printf ("%8s start %#lx end %#lx\n",
133 exe_header
->section_header
[i
].s_name
,
134 start_address
, end_address
);
135 if (my_edata
>= (char *) start_address
136 && my_edata
< (char *) end_address
)
140 lseek (fd
, (long) (exe_header
->section_header
[i
].s_scnptr
),
144 write (fd
, (char *) start_address
,
145 my_edata
- (char *) start_address
);
146 assert (ret
== my_edata
- (char *) start_address
);
149 printf (" .data, mem start %#lx mem length %td\n",
150 start_address
, my_edata
- (char *) start_address
);
152 printf (" .data, file start %d file length %d\n",
153 (int) exe_header
->section_header
[i
].s_scnptr
,
154 (int) exe_header
->section_header
[i
].s_paddr
);
156 else if (my_endbss
>= (char *) start_address
157 && my_endbss
< (char *) end_address
)
161 if (exe_header
->section_header
[i
].s_flags
& 0x00000080)
163 /* convert uninitialized data section to initialized data section */
165 ret
= fstat (fd
, &statbuf
);
168 exe_header
->section_header
[i
].s_flags
&= ~0x00000080;
169 exe_header
->section_header
[i
].s_flags
|= 0x00000040;
171 exe_header
->section_header
[i
].s_scnptr
=
173 exe_header
->file_optional_header
.FileAlignment
) /
174 exe_header
->file_optional_header
.FileAlignment
*
175 exe_header
->file_optional_header
.FileAlignment
;
177 exe_header
->section_header
[i
].s_size
=
178 (exe_header
->section_header
[i
].s_paddr
+
179 exe_header
->file_optional_header
.FileAlignment
) /
180 exe_header
->file_optional_header
.FileAlignment
*
181 exe_header
->file_optional_header
.FileAlignment
;
183 /* Make sure the generated bootstrap binary isn't
184 * sparse. NT doesn't use a file cache for sparse
185 * executables, so if we bootstrap Emacs using a sparse
186 * bootstrap-emacs.exe, bootstrap takes about twenty
187 * times longer than it would otherwise. */
189 ret
= posix_fallocate (fd
,
190 ( exe_header
->section_header
[i
].s_scnptr
+
191 exe_header
->section_header
[i
].s_size
),
198 (long) (exe_header
->section_header
[i
].s_scnptr
+
199 exe_header
->section_header
[i
].s_size
- 1),
202 ret
= write (fd
, "", 1);
207 (long) ((char *) &exe_header
->section_header
[i
] -
208 (char *) exe_header
), SEEK_SET
);
211 write (fd
, &exe_header
->section_header
[i
],
212 sizeof (exe_header
->section_header
[i
]));
213 assert (ret
== sizeof (exe_header
->section_header
[i
]));
215 printf (" seek to %ld, write %zu\n",
216 (long) ((char *) &exe_header
->section_header
[i
] -
217 (char *) exe_header
),
218 sizeof (exe_header
->section_header
[i
]));
220 /* write initialized data section */
222 lseek (fd
, (long) (exe_header
->section_header
[i
].s_scnptr
),
226 write (fd
, (char *) start_address
,
227 my_endbss
- (char *) start_address
);
228 assert (ret
== (my_endbss
- (char *) start_address
));
230 printf (" .bss, mem start %#lx mem length %td\n",
231 start_address
, my_endbss
- (char *) start_address
);
233 printf (" .bss, file start %d file length %d\n",
234 (int) exe_header
->section_header
[i
].s_scnptr
,
235 (int) exe_header
->section_header
[i
].s_paddr
);
238 assert (found_bss
== 1);
239 assert (found_data
== 1);
243 ** Windows likes .exe suffixes on executables.
246 add_exe_suffix_if_necessary (const char *name
, char *modified
)
248 int i
= strlen (name
);
249 if (i
<= (sizeof (DOTEXE
) - 1))
251 sprintf (modified
, "%s%s", name
, DOTEXE
);
253 else if (!strcasecmp (name
+ i
- (sizeof (DOTEXE
) - 1), DOTEXE
))
255 strcpy (modified
, name
);
259 sprintf (modified
, "%s%s", name
, DOTEXE
);
265 unexec (const char *outfile
, const char *infile
)
267 char infile_buffer
[FILENAME_MAX
];
268 char outfile_buffer
[FILENAME_MAX
];
274 infile
= add_exe_suffix_if_necessary (infile
, infile_buffer
);
275 outfile
= add_exe_suffix_if_necessary (outfile
, outfile_buffer
);
277 fd_in
= emacs_open (infile
, O_RDONLY
, 0);
279 fd_out
= emacs_open (outfile
, O_RDWR
| O_TRUNC
| O_CREAT
, 0755);
280 assert (fd_out
>= 0);
284 ret
= read (fd_in
, buffer
, sizeof (buffer
));
292 ret2
= write (fd_out
, buffer
, ret
);
293 assert (ret2
== ret
);
295 ret
= emacs_close (fd_in
);
298 fixup_executable (fd_out
);
300 ret
= emacs_close (fd_out
);