1 /* unexec() support for Cygwin;
2 complete rewrite of xemacs Cygwin unexec() code
5 Free Software Foundation, Inc.
7 This file is part of GNU Emacs.
9 GNU Emacs is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
34 extern int bss_sbrk_did_unexec
;
36 /* emacs symbols that indicate where bss and data end for emacs internals */
37 extern char my_endbss
[];
38 extern char my_edata
[];
41 ** header for Windows executable files
46 PEAOUTHDR file_optional_header
;
47 SCNHDR section_header
[32];
53 ** Read the header from the executable into memory so we can more easily access it.
56 read_exe_header (int fd
, exe_header_t
* exe_header_buffer
)
62 assert (exe_header_buffer
!= 0);
64 ret
= lseek (fd
, 0L, SEEK_SET
);
68 read (fd
, &exe_header_buffer
->file_header
,
69 sizeof (exe_header_buffer
->file_header
));
70 assert (ret
== sizeof (exe_header_buffer
->file_header
));
72 assert (exe_header_buffer
->file_header
.e_magic
== 0x5a4d);
73 assert (exe_header_buffer
->file_header
.nt_signature
== 0x4550);
74 assert (exe_header_buffer
->file_header
.f_magic
== 0x014c);
75 assert (exe_header_buffer
->file_header
.f_nscns
> 0);
76 assert (exe_header_buffer
->file_header
.f_nscns
<=
77 sizeof (exe_header_buffer
->section_header
) /
78 sizeof (exe_header_buffer
->section_header
[0]));
79 assert (exe_header_buffer
->file_header
.f_opthdr
> 0);
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 assert (exe_header_buffer
->file_optional_header
.magic
== 0x010b);
88 for (i
= 0; i
< exe_header_buffer
->file_header
.f_nscns
; ++i
)
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
]));
96 return (exe_header_buffer
);
100 ** Fix the dumped emacs executable:
102 ** - copy .data section data of interest from running executable into
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
110 fixup_executable (int fd
)
112 exe_header_t exe_header_buffer
;
113 exe_header_t
*exe_header
;
119 exe_header
= read_exe_header (fd
, &exe_header_buffer
);
120 assert (exe_header
!= 0);
122 assert (exe_header
->file_header
.f_nscns
> 0);
123 for (i
= 0; i
< exe_header
->file_header
.f_nscns
; ++i
)
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
;
133 printf ("%8s start 0x%08x end 0x%08x\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
)
141 lseek (fd
, (long) (exe_header
->section_header
[i
].s_scnptr
),
145 write (fd
, (char *) start_address
,
146 my_edata
- (char *) start_address
);
147 assert (ret
== my_edata
- (char *) start_address
);
150 printf (" .data, mem start 0x%08x mem length %d\n",
151 start_address
, my_edata
- (char *) start_address
);
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
);
157 else if (my_endbss
>= (char *) start_address
158 && my_endbss
< (char *) end_address
)
162 if (exe_header
->section_header
[i
].s_flags
& 0x00000080)
164 /* convert uninitialized data section to initialized data section */
166 ret
= fstat (fd
, &statbuf
);
169 exe_header
->section_header
[i
].s_flags
&= ~0x00000080;
170 exe_header
->section_header
[i
].s_flags
|= 0x00000040;
172 exe_header
->section_header
[i
].s_scnptr
=
174 exe_header
->file_optional_header
.FileAlignment
) /
175 exe_header
->file_optional_header
.FileAlignment
*
176 exe_header
->file_optional_header
.FileAlignment
;
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
;
186 (long) (exe_header
->section_header
[i
].s_scnptr
+
187 exe_header
->section_header
[i
].s_size
- 1),
190 ret
= write (fd
, "", 1);
195 (long) ((char *) &exe_header
->section_header
[i
] -
196 (char *) exe_header
), SEEK_SET
);
199 write (fd
, &exe_header
->section_header
[i
],
200 sizeof (exe_header
->section_header
[i
]));
201 assert (ret
== sizeof (exe_header
->section_header
[i
]));
203 printf (" seek to %ld, write %d\n",
204 (long) ((char *) &exe_header
->section_header
[i
] -
205 (char *) exe_header
),
206 sizeof (exe_header
->section_header
[i
]));
208 /* write initialized data section */
210 lseek (fd
, (long) (exe_header
->section_header
[i
].s_scnptr
),
214 write (fd
, (char *) start_address
,
215 my_endbss
- (char *) start_address
);
216 assert (ret
== (my_endbss
- (char *) start_address
));
218 printf (" .bss, mem start 0x%08x mem length %d\n",
219 start_address
, my_endbss
- (char *) start_address
);
221 printf (" .bss, file start %d file length %d\n",
222 (int) exe_header
->section_header
[i
].s_scnptr
,
223 (int) exe_header
->section_header
[i
].s_paddr
);
226 assert (found_bss
== 1);
227 assert (found_data
== 1);
231 ** Windows likes .exe suffixes on executables.
234 add_exe_suffix_if_necessary (const char *name
, char *modified
)
236 int i
= strlen (name
);
237 if (i
<= (sizeof (DOTEXE
) - 1))
239 sprintf (modified
, "%s%s", name
, DOTEXE
);
241 else if (!strcasecmp (name
+ i
- (sizeof (DOTEXE
) - 1), DOTEXE
))
243 strcpy (modified
, name
);
247 sprintf (modified
, "%s%s", name
, DOTEXE
);
253 unexec (char *outfile
, char *infile
, unsigned start_data
, unsigned d1
,
256 char infile_buffer
[FILENAME_MAX
];
257 char outfile_buffer
[FILENAME_MAX
];
263 if (bss_sbrk_did_unexec
)
265 /* can only dump once */
266 printf ("You can only dump emacs once on this platform.\n");
270 report_sheap_usage (1);
272 infile
= add_exe_suffix_if_necessary (infile
, infile_buffer
);
273 outfile
= add_exe_suffix_if_necessary (outfile
, outfile_buffer
);
275 fd_in
= open (infile
, O_RDONLY
| O_BINARY
);
277 fd_out
= open (outfile
, O_RDWR
| O_TRUNC
| O_CREAT
| O_BINARY
, 0755);
278 assert (fd_out
>= 0);
282 ret
= read (fd_in
, buffer
, sizeof (buffer
));
290 ret2
= write (fd_out
, buffer
, ret
);
291 assert (ret2
== ret
);
296 bss_sbrk_did_unexec
= 1;
297 fixup_executable (fd_out
);
298 bss_sbrk_did_unexec
= 0;
300 ret
= close (fd_out
);
306 /* arch-tag: fc44f6c3-ca0a-45e0-a5a2-58b6101b1e65
307 (do not change this comment) */