This source file includes following definitions.
- report_error
- report_error_1
- make_hdr
- write_segment
- copy_text_and_data
- copy_sym
- adjust_lnnoptrs
- unexec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 #include <config.h>
54 #include "unexec.h"
55 #include "lisp.h"
56
57 #define PERROR(file) report_error (file, new)
58
59 #ifdef HAVE_UNEXEC
60
61 #ifdef HAVE_COFF_H
62 #include <coff.h>
63 #ifdef MSDOS
64 #include <fcntl.h>
65 #include <crt0.h>
66 #include <sys/exceptn.h>
67 static int save_djgpp_startup_flags;
68 #include <libc/atexit.h>
69 static struct __atexit *save_atexit_ptr;
70 #define filehdr external_filehdr
71 #define scnhdr external_scnhdr
72 #define syment external_syment
73 #define auxent external_auxent
74 #define n_numaux e_numaux
75 #define n_type e_type
76 struct aouthdr
77 {
78 unsigned short magic;
79 unsigned short vstamp;
80 unsigned long tsize;
81 unsigned long dsize;
82 unsigned long bsize;
83 unsigned long entry;
84 unsigned long text_start;
85 unsigned long data_start;
86 };
87 #endif
88 #else
89 #include <a.out.h>
90 #endif
91
92
93
94 #include "getpagesize.h"
95
96 #ifndef makedev
97 #include <sys/types.h>
98 #endif
99 #include <errno.h>
100
101 #include <sys/file.h>
102
103 extern int etext;
104
105 static long block_copy_start;
106 static struct filehdr f_hdr;
107 static struct aouthdr f_ohdr;
108 long bias;
109 long lnnoptr;
110 #define SYMS_START block_copy_start
111
112 static long text_scnptr;
113 static long data_scnptr;
114
115 static long coff_offset;
116
117 static int pagemask;
118
119
120
121
122
123 #define ADDR_CORRECT(x) ((char *) (x) - (char *) 0)
124
125 #include "lisp.h"
126
127 static void
128 report_error (const char *file, int fd)
129 {
130 int err = errno;
131 if (fd)
132 emacs_close (fd);
133 report_file_errno ("Cannot unexec", build_string (file), err);
134 }
135
136 #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
137 #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
138 #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
139
140 static void
141 report_error_1 (int fd, const char *msg, int a1, int a2)
142 {
143 emacs_close (fd);
144 error (msg, a1, a2);
145 }
146
147 static int make_hdr (int, int, const char *, const char *);
148 static int copy_text_and_data (int, int);
149 static int copy_sym (int, int, const char *, const char *);
150 static void mark_x (const char *);
151
152
153
154
155
156
157
158 static int
159 make_hdr (int new, int a_out,
160 const char *a_name, const char *new_name)
161 {
162 auto struct scnhdr f_thdr;
163 auto struct scnhdr f_dhdr;
164 auto struct scnhdr f_bhdr;
165 auto struct scnhdr scntemp;
166 register int scns;
167 unsigned int bss_start;
168 unsigned int data_start;
169
170 pagemask = getpagesize () - 1;
171
172
173 data_start = (int) DATA_START;
174 data_start = ADDR_CORRECT (data_start);
175 data_start = data_start & ~pagemask;
176
177 bss_start = ADDR_CORRECT (sbrk (0)) + pagemask;
178 bss_start &= ~ pagemask;
179
180 if (data_start > bss_start)
181 {
182 ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
183 data_start, bss_start);
184 }
185
186 coff_offset = 0L;
187
188
189 if (a_out >= 0)
190 {
191 #ifdef MSDOS
192
193
194 unsigned short mz_header[3];
195
196 if (read (a_out, &mz_header, sizeof (mz_header)) != sizeof (mz_header))
197 {
198 PERROR (a_name);
199 }
200 if (mz_header[0] == 0x5a4d || mz_header[0] == 0x4d5a)
201 {
202 coff_offset = (long)mz_header[2] * 512L;
203 if (mz_header[1])
204 coff_offset += (long)mz_header[1] - 512L;
205 lseek (a_out, coff_offset, 0);
206 }
207 else
208 lseek (a_out, 0L, 0);
209 #endif
210 if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
211 {
212 PERROR (a_name);
213 }
214 block_copy_start += sizeof (f_hdr);
215 if (f_hdr.f_opthdr > 0)
216 {
217 if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
218 {
219 PERROR (a_name);
220 }
221 block_copy_start += sizeof (f_ohdr);
222 }
223
224 lseek (a_out, coff_offset + sizeof (f_hdr) + f_hdr.f_opthdr, 0);
225 for (scns = f_hdr.f_nscns; scns > 0; scns--) {
226 if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
227 {
228 PERROR (a_name);
229 }
230 if (scntemp.s_scnptr > 0L)
231 {
232 if (block_copy_start < scntemp.s_scnptr + scntemp.s_size)
233 block_copy_start = scntemp.s_scnptr + scntemp.s_size;
234 }
235 if (strcmp (scntemp.s_name, ".text") == 0)
236 {
237 f_thdr = scntemp;
238 }
239 else if (strcmp (scntemp.s_name, ".data") == 0)
240 {
241 f_dhdr = scntemp;
242 }
243 else if (strcmp (scntemp.s_name, ".bss") == 0)
244 {
245 f_bhdr = scntemp;
246 }
247 }
248 }
249 else
250 {
251 ERROR0 ("can't build a COFF file from scratch yet");
252 }
253
254
255
256
257 f_hdr.f_flags |= (F_RELFLG | F_EXEC);
258 f_ohdr.dsize = bss_start - f_ohdr.data_start;
259 f_ohdr.bsize = 0;
260 f_thdr.s_size = f_ohdr.tsize;
261 f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
262 f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
263 lnnoptr = f_thdr.s_lnnoptr;
264 text_scnptr = f_thdr.s_scnptr;
265 f_dhdr.s_paddr = f_ohdr.data_start;
266 f_dhdr.s_vaddr = f_ohdr.data_start;
267 f_dhdr.s_size = f_ohdr.dsize;
268 f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
269 data_scnptr = f_dhdr.s_scnptr;
270 f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
271 f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
272 f_bhdr.s_size = f_ohdr.bsize;
273 f_bhdr.s_scnptr = 0L;
274 bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
275
276 if (f_hdr.f_symptr > 0L)
277 {
278 f_hdr.f_symptr += bias;
279 }
280
281 if (f_thdr.s_lnnoptr > 0L)
282 {
283 f_thdr.s_lnnoptr += bias;
284 }
285
286 if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
287 {
288 PERROR (new_name);
289 }
290
291 if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
292 {
293 PERROR (new_name);
294 }
295
296 if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
297 {
298 PERROR (new_name);
299 }
300
301 if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
302 {
303 PERROR (new_name);
304 }
305
306 if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
307 {
308 PERROR (new_name);
309 }
310
311 return (0);
312
313 }
314
315 void
316 write_segment (int new, const char *ptr, const char *end)
317 {
318 register int i, nwrite, ret;
319
320
321 int writesize = 1 << 13;
322 int pagesize = getpagesize ();
323 char zeros[1 << 13];
324
325 memset (zeros, 0, sizeof (zeros));
326
327 for (i = 0; ptr < end;)
328 {
329
330 nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr;
331
332 if (nwrite > end - ptr) nwrite = end - ptr;
333 ret = write (new, ptr, nwrite);
334
335
336
337
338 if (ret == -1 && errno == EFAULT)
339 {
340
341
342
343 if (nwrite > pagesize)
344 nwrite = pagesize;
345 write (new, zeros, nwrite);
346 }
347 i += nwrite;
348 ptr += nwrite;
349 }
350 }
351
352
353
354
355
356 static int
357 copy_text_and_data (int new, int a_out)
358 {
359 register char *end;
360 register char *ptr;
361
362 #ifdef MSDOS
363
364
365 __djgpp_exception_toggle ();
366
367
368
369 save_djgpp_startup_flags = _crt0_startup_flags;
370 _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR);
371
372
373
374
375 save_atexit_ptr = __atexit_ptr;
376 __atexit_ptr = NULL;
377 #endif
378
379 lseek (new, (long) text_scnptr, 0);
380 ptr = (char *) f_ohdr.text_start;
381 end = ptr + f_ohdr.tsize;
382 write_segment (new, ptr, end);
383
384 lseek (new, (long) data_scnptr, 0);
385 ptr = (char *) f_ohdr.data_start;
386 end = ptr + f_ohdr.dsize;
387 write_segment (new, ptr, end);
388
389 #ifdef MSDOS
390
391 __djgpp_exception_toggle ();
392
393
394 _crt0_startup_flags = save_djgpp_startup_flags;
395
396
397 __atexit_ptr = save_atexit_ptr;
398 #endif
399
400
401 return 0;
402 }
403
404
405
406
407
408
409 static int
410 copy_sym (int new, int a_out, const char *a_name, const char *new_name)
411 {
412 char page[1024];
413 int n;
414
415 if (a_out < 0)
416 return 0;
417
418 if (SYMS_START == 0L)
419 return 0;
420
421 if (lnnoptr)
422 lseek (a_out, coff_offset + lnnoptr, 0);
423 else
424 lseek (a_out, coff_offset + SYMS_START, 0);
425
426 while ((n = read (a_out, page, sizeof page)) > 0)
427 {
428 if (write (new, page, n) != n)
429 {
430 PERROR (new_name);
431 }
432 }
433 if (n < 0)
434 {
435 PERROR (a_name);
436 }
437 return 0;
438 }
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463 int
464 adjust_lnnoptrs (int writedesc, int readdesc, const char *new_name)
465 {
466 register int nsyms;
467 register int new;
468 struct syment symentry;
469 union auxent auxentry;
470
471 if (!lnnoptr || !f_hdr.f_symptr)
472 return 0;
473
474 #ifdef MSDOS
475 if ((new = writedesc) < 0)
476 #else
477 if ((new = emacs_open (new_name, O_RDWR, 0)) < 0)
478 #endif
479 {
480 PERROR (new_name);
481 return -1;
482 }
483
484 lseek (new, f_hdr.f_symptr, 0);
485 for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
486 {
487 read (new, &symentry, SYMESZ);
488 if (symentry.n_numaux)
489 {
490 read (new, &auxentry, AUXESZ);
491 nsyms++;
492 if (ISFCN (symentry.n_type) || symentry.n_type == 0x2400)
493 {
494 auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
495 lseek (new, -AUXESZ, 1);
496 write (new, &auxentry, AUXESZ);
497 }
498 }
499 }
500 #ifndef MSDOS
501 emacs_close (new);
502 #endif
503 return 0;
504 }
505
506
507
508
509
510
511 void
512 unexec (const char *new_name, const char *a_name)
513 {
514 int new = -1, a_out = -1;
515
516 if (a_name && (a_out = emacs_open (a_name, O_RDONLY, 0)) < 0)
517 {
518 PERROR (a_name);
519 }
520 if ((new = emacs_open (new_name, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0)
521 {
522 PERROR (new_name);
523 }
524
525 if (make_hdr (new, a_out, a_name, new_name) < 0
526 || copy_text_and_data (new, a_out) < 0
527 || copy_sym (new, a_out, a_name, new_name) < 0
528 || adjust_lnnoptrs (new, a_out, new_name) < 0
529 )
530 {
531 emacs_close (new);
532 return;
533 }
534
535 emacs_close (new);
536 if (a_out >= 0)
537 emacs_close (a_out);
538 }
539
540 #endif