1 /* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
3 Copyright (C) 1994 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
24 #include <sys/types.h>
35 static void fatal_unexec ();
36 static void mark_x ();
38 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
40 if (read (_fd, _buffer, _size) != _size) \
41 fatal_unexec (_error_message, _error_arg);
43 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
44 if (write (_fd, _buffer, _size) != _size) \
45 fatal_unexec (_error_message, _error_arg);
47 #define SEEK(_fd, _position, _error_message, _error_arg) \
49 if (lseek (_fd, _position, L_SET) != _position) \
50 fatal_unexec (_error_message, _error_arg);
53 extern char *strerror ();
59 static struct scnhdr
*text_section
;
60 static struct scnhdr
*init_section
;
61 static struct scnhdr
*finit_section
;
62 static struct scnhdr
*rdata_section
;
63 static struct scnhdr
*rconst_section
;
64 static struct scnhdr
*data_section
;
65 static struct scnhdr
*pdata_section
;
66 static struct scnhdr
*xdata_section
;
67 static struct scnhdr
*got_section
;
68 static struct scnhdr
*lit8_section
;
69 static struct scnhdr
*lit4_section
;
70 static struct scnhdr
*sdata_section
;
71 static struct scnhdr
*sbss_section
;
72 static struct scnhdr
*bss_section
;
74 static unsigned long Brk
;
79 struct scnhdr section
[_MIPS_NSCNS_MAX
];
84 /* Define name of label for entry point for the dumped executable. */
86 #ifndef DEFAULT_ENTRY_ADDRESS
87 #define DEFAULT_ENTRY_ADDRESS __start
90 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
91 char *new_name
, *a_name
;
92 unsigned long data_start
, bss_start
, entry_address
;
96 struct headers ohdr
, nhdr
;
104 char buffer
[BUFSIZE
];
106 if ((old
= open (a_name
, O_RDONLY
)) < 0)
107 fatal_unexec ("opening %s", a_name
);
109 new = creat (new_name
, 0666);
110 if (new < 0) fatal_unexec ("creating %s", new_name
);
112 if ((fstat (old
, &stat
) == -1))
113 fatal_unexec ("fstat %s", a_name
);
115 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
117 if (oldptr
== (char *)-1)
118 fatal_unexec ("mmap %s", a_name
);
122 /* This is a copy of the a.out header of the original executable */
124 ohdr
= (*(struct headers
*)oldptr
);
126 /* This is where we build the new header from the in-memory copy */
128 nhdr
= *((struct headers
*)TEXT_START
);
130 /* First do some consistency checks */
132 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
133 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
135 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
136 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
140 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
142 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
143 nhdr
.fhdr
.f_opthdr
, sizeof (nhdr
.aout
));
146 if (nhdr
.aout
.magic
!= ZMAGIC
)
148 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
149 nhdr
.aout
.magic
, ZMAGIC
);
154 /* Now check the existence of certain header section and grab
157 #define CHECK_SCNHDR(ptr, name, flags) \
159 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
160 if (strcmp (nhdr.section[i].s_name, name) == 0) \
162 if (nhdr.section[i].s_flags != flags) \
163 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
164 nhdr.section[i].s_flags, flags, name); \
165 ptr = nhdr.section + i; \
168 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
169 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
171 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
173 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
175 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
178 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
181 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
183 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
185 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
188 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
189 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
191 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
192 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
193 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
196 pagesize
= getpagesize ();
197 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
199 /* Remember the current break */
203 nhdr
.aout
.dsize
= brk
- DATA_START
;
205 if (entry_address
== 0)
207 extern DEFAULT_ENTRY_ADDRESS ();
208 nhdr
.aout
.entry
= (unsigned long)DEFAULT_ENTRY_ADDRESS
;
211 nhdr
.aout
.entry
= entry_address
;
213 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
215 if (rdata_section
!= NULL
)
217 rdata_section
->s_size
= data_start
- DATA_START
;
219 /* Adjust start and virtual addresses of rdata_section, too. */
220 rdata_section
->s_vaddr
= DATA_START
;
221 rdata_section
->s_paddr
= DATA_START
;
222 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
225 data_section
->s_vaddr
= data_start
;
226 data_section
->s_paddr
= data_start
;
227 data_section
->s_size
= brk
- data_start
;
229 if (rdata_section
!= NULL
)
231 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
234 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
235 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
236 if (lit8_section
!= NULL
)
238 lit8_section
->s_vaddr
= vaddr
;
239 lit8_section
->s_paddr
= vaddr
;
240 lit8_section
->s_size
= 0;
241 lit8_section
->s_scnptr
= scnptr
;
243 if (lit4_section
!= NULL
)
245 lit4_section
->s_vaddr
= vaddr
;
246 lit4_section
->s_paddr
= vaddr
;
247 lit4_section
->s_size
= 0;
248 lit4_section
->s_scnptr
= scnptr
;
250 if (sdata_section
!= NULL
)
252 sdata_section
->s_vaddr
= vaddr
;
253 sdata_section
->s_paddr
= vaddr
;
254 sdata_section
->s_size
= 0;
255 sdata_section
->s_scnptr
= scnptr
;
258 if (xdata_section
!= NULL
)
260 xdata_section
->s_vaddr
= vaddr
;
261 xdata_section
->s_paddr
= vaddr
;
262 xdata_section
->s_size
= 0;
263 xdata_section
->s_scnptr
= scnptr
;
267 if (got_section
!= NULL
)
269 got_section
->s_vaddr
= vaddr
;
270 got_section
->s_paddr
= vaddr
;
271 got_section
->s_size
= 0;
272 got_section
->s_scnptr
= scnptr
;
275 if (sbss_section
!= NULL
)
277 sbss_section
->s_vaddr
= vaddr
;
278 sbss_section
->s_paddr
= vaddr
;
279 sbss_section
->s_size
= 0;
280 sbss_section
->s_scnptr
= scnptr
;
282 if (bss_section
!= NULL
)
284 bss_section
->s_vaddr
= vaddr
;
285 bss_section
->s_paddr
= vaddr
;
286 bss_section
->s_size
= 0;
287 bss_section
->s_scnptr
= scnptr
;
290 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
291 "writing text section to %s", new_name
);
292 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
293 "writing data section to %s", new_name
);
297 * Construct new symbol table header
300 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
302 #define symhdr ((pHDRR)buffer)
303 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
304 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
305 nhdr
.fhdr
.f_symptr
= newsyms
;
306 symhdr
->cbLineOffset
+= symrel
;
307 symhdr
->cbDnOffset
+= symrel
;
308 symhdr
->cbPdOffset
+= symrel
;
309 symhdr
->cbSymOffset
+= symrel
;
310 symhdr
->cbOptOffset
+= symrel
;
311 symhdr
->cbAuxOffset
+= symrel
;
312 symhdr
->cbSsOffset
+= symrel
;
313 symhdr
->cbSsExtOffset
+= symrel
;
314 symhdr
->cbFdOffset
+= symrel
;
315 symhdr
->cbRfdOffset
+= symrel
;
316 symhdr
->cbExtOffset
+= symrel
;
318 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
321 * Copy the symbol table and line numbers
323 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
324 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
325 "writing symbol table of %s", new_name
);
329 /* Not needed for now */
331 update_dynamic_symbols (oldptr
, new_name
, new, newsyms
,
332 ((pHDRR
) (oldptr
+ ohdr
.fhdr
.f_symptr
))->issExtMax
,
333 ((pHDRR
) (oldptr
+ ohdr
.fhdr
.f_symptr
))->cbExtOffset
,
334 ((pHDRR
) (oldptr
+ ohdr
.fhdr
.f_symptr
))->cbSsExtOffset
);
340 SEEK (new, 0, "seeking to start of header in %s", new_name
);
341 WRITE (new, &nhdr
, sizeof (nhdr
),
342 "writing header of %s", new_name
);
352 /* Not needed for now */
354 /* The following function updates the values of some symbols
355 that are used by the dynamic loader:
363 update_dynamic_symbols (old
, new_name
, new, newsyms
, nsyms
, symoff
, stroff
)
364 char *old
; /* Pointer to old executable */
365 char *new_name
; /* Name of new executable */
366 int new; /* File descriptor for new executable */
367 long newsyms
; /* Offset of Symbol table in new executable */
368 int nsyms
; /* Number of symbol table entries */
369 long symoff
; /* Offset of External Symbols in old file */
370 long stroff
; /* Offset of string table in old file */
376 /* We go through the symbol table entries until we have found the two
379 /* cbEXTR is the size of an external symbol table entry */
381 for (i
= 0; i
< nsyms
&& found
< 2; i
+= cbEXTR
)
383 register pEXTR x
= (pEXTR
) (old
+ symoff
+ i
);
386 s
= old
+ stroff
+ x
->asym
.iss
; /* name of the symbol */
388 if (!strcmp(s
,"_edata"))
391 bcopy (x
, &n_edata
, cbEXTR
);
392 n_edata
.asym
.value
= Brk
;
393 SEEK (new, newsyms
+ cbHDRR
+ i
,
394 "seeking to symbol _edata in %s", new_name
);
395 WRITE (new, &n_edata
, cbEXTR
,
396 "writing symbol table entry for _edata into %s", new_name
);
398 else if (!strcmp(s
,"_end"))
401 bcopy (x
, &n_end
, cbEXTR
);
402 n_end
.asym
.value
= Brk
;
403 SEEK (new, newsyms
+ cbHDRR
+ i
,
404 "seeking to symbol _end in %s", new_name
);
405 WRITE (new, &n_end
, cbEXTR
,
406 "writing symbol table entry for _end into %s", new_name
);
418 * After successfully building the new a.out, mark it executable
426 int um
= umask (777);
428 if (stat (name
, &sbuf
) < 0)
429 fatal_unexec ("getting protection on %s", name
);
430 sbuf
.st_mode
|= 0111 & ~um
;
431 if (chmod (name
, sbuf
.st_mode
) < 0)
432 fatal_unexec ("setting protection on %s", name
);
436 fatal_unexec (s
, arg
)
441 fputs ("unexec: unexpected end of file, ", stderr
);
443 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
444 fprintf (stderr
, s
, arg
);
445 fputs (".\n", stderr
);