1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
4 Copyright (C) 2004-2012 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/>. */
34 extern int bss_sbrk_did_unexec
;
36 extern int __malloc_initialized
;
38 /* emacs symbols that indicate where bss and data end for emacs internals */
39 extern char my_endbss
[];
40 extern char my_edata
[];
43 ** header for Windows executable files
48 PEAOUTHDR file_optional_header
;
49 SCNHDR section_header
[32];
55 ** Read the header from the executable into memory so we can more easily access it.
58 read_exe_header (int fd
, exe_header_t
* exe_header_buffer
)
64 assert (exe_header_buffer
!= 0);
66 ret
= lseek (fd
, 0L, SEEK_SET
);
70 read (fd
, &exe_header_buffer
->file_header
,
71 sizeof (exe_header_buffer
->file_header
));
72 assert (ret
== sizeof (exe_header_buffer
->file_header
));
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);
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
));
88 assert (exe_header_buffer
->file_optional_header
.magic
== 0x010b);
90 for (i
= 0; i
< exe_header_buffer
->file_header
.f_nscns
; ++i
)
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
]));
98 return (exe_header_buffer
);
102 ** Fix the dumped emacs executable:
104 ** - copy .data section data of interest from running executable into
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
112 fixup_executable (int fd
)
114 exe_header_t exe_header_buffer
;
115 exe_header_t
*exe_header
;
121 exe_header
= read_exe_header (fd
, &exe_header_buffer
);
122 assert (exe_header
!= 0);
124 assert (exe_header
->file_header
.f_nscns
> 0);
125 for (i
= 0; i
< exe_header
->file_header
.f_nscns
; ++i
)
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
;
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
)
143 lseek (fd
, (long) (exe_header
->section_header
[i
].s_scnptr
),
147 write (fd
, (char *) start_address
,
148 my_edata
- (char *) start_address
);
149 assert (ret
== my_edata
- (char *) start_address
);
152 printf (" .data, mem start 0x%08x mem length %d\n",
153 start_address
, my_edata
- (char *) start_address
);
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
);
159 else if (my_endbss
>= (char *) start_address
160 && my_endbss
< (char *) end_address
)
164 if (exe_header
->section_header
[i
].s_flags
& 0x00000080)
166 /* convert uninitialized data section to initialized data section */
168 ret
= fstat (fd
, &statbuf
);
171 exe_header
->section_header
[i
].s_flags
&= ~0x00000080;
172 exe_header
->section_header
[i
].s_flags
|= 0x00000040;
174 exe_header
->section_header
[i
].s_scnptr
=
176 exe_header
->file_optional_header
.FileAlignment
) /
177 exe_header
->file_optional_header
.FileAlignment
*
178 exe_header
->file_optional_header
.FileAlignment
;
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
;
188 (long) (exe_header
->section_header
[i
].s_scnptr
+
189 exe_header
->section_header
[i
].s_size
- 1),
192 ret
= write (fd
, "", 1);
197 (long) ((char *) &exe_header
->section_header
[i
] -
198 (char *) exe_header
), SEEK_SET
);
201 write (fd
, &exe_header
->section_header
[i
],
202 sizeof (exe_header
->section_header
[i
]));
203 assert (ret
== sizeof (exe_header
->section_header
[i
]));
205 printf (" seek to %ld, write %d\n",
206 (long) ((char *) &exe_header
->section_header
[i
] -
207 (char *) exe_header
),
208 sizeof (exe_header
->section_header
[i
]));
210 /* write initialized data section */
212 lseek (fd
, (long) (exe_header
->section_header
[i
].s_scnptr
),
215 /* force the dumped emacs to reinitialize malloc */
216 __malloc_initialized
= 0;
218 write (fd
, (char *) start_address
,
219 my_endbss
- (char *) start_address
);
220 __malloc_initialized
= 1;
221 assert (ret
== (my_endbss
- (char *) start_address
));
223 printf (" .bss, mem start 0x%08x mem length %d\n",
224 start_address
, my_endbss
- (char *) start_address
);
226 printf (" .bss, file start %d file length %d\n",
227 (int) exe_header
->section_header
[i
].s_scnptr
,
228 (int) exe_header
->section_header
[i
].s_paddr
);
231 assert (found_bss
== 1);
232 assert (found_data
== 1);
236 ** Windows likes .exe suffixes on executables.
239 add_exe_suffix_if_necessary (const char *name
, char *modified
)
241 int i
= strlen (name
);
242 if (i
<= (sizeof (DOTEXE
) - 1))
244 sprintf (modified
, "%s%s", name
, DOTEXE
);
246 else if (!strcasecmp (name
+ i
- (sizeof (DOTEXE
) - 1), DOTEXE
))
248 strcpy (modified
, name
);
252 sprintf (modified
, "%s%s", name
, DOTEXE
);
258 unexec (const char *outfile
, const char *infile
)
260 char infile_buffer
[FILENAME_MAX
];
261 char outfile_buffer
[FILENAME_MAX
];
267 if (bss_sbrk_did_unexec
)
269 /* can only dump once */
270 printf ("You can only dump Emacs once on this platform.\n");
274 report_sheap_usage (1);
276 infile
= add_exe_suffix_if_necessary (infile
, infile_buffer
);
277 outfile
= add_exe_suffix_if_necessary (outfile
, outfile_buffer
);
279 fd_in
= open (infile
, O_RDONLY
| O_BINARY
);
281 fd_out
= open (outfile
, O_RDWR
| O_TRUNC
| O_CREAT
| O_BINARY
, 0755);
282 assert (fd_out
>= 0);
286 ret
= read (fd_in
, buffer
, sizeof (buffer
));
294 ret2
= write (fd_out
, buffer
, ret
);
295 assert (ret2
== ret
);
300 bss_sbrk_did_unexec
= 1;
301 fixup_executable (fd_out
);
302 bss_sbrk_did_unexec
= 0;
304 ret
= close (fd_out
);