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, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #include <sys/types.h>
34 static void fatal_unexec ();
35 static void mark_x ();
37 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
39 if (read (_fd, _buffer, _size) != _size) \
40 fatal_unexec (_error_message, _error_arg);
42 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
43 if (write (_fd, _buffer, _size) != _size) \
44 fatal_unexec (_error_message, _error_arg);
46 #define SEEK(_fd, _position, _error_message, _error_arg) \
48 if (lseek (_fd, _position, L_SET) != _position) \
49 fatal_unexec (_error_message, _error_arg);
52 extern char *strerror ();
58 static struct scnhdr
*text_section
;
59 static struct scnhdr
*init_section
;
60 static struct scnhdr
*finit_section
;
61 static struct scnhdr
*rdata_section
;
62 static struct scnhdr
*rconst_section
;
63 static struct scnhdr
*data_section
;
64 static struct scnhdr
*pdata_section
;
65 static struct scnhdr
*xdata_section
;
66 static struct scnhdr
*got_section
;
67 static struct scnhdr
*lit8_section
;
68 static struct scnhdr
*lit4_section
;
69 static struct scnhdr
*sdata_section
;
70 static struct scnhdr
*sbss_section
;
71 static struct scnhdr
*bss_section
;
73 static unsigned long Brk
;
78 struct scnhdr section
[_MIPS_NSCNS_MAX
];
83 /* Define name of label for entry point for the dumped executable. */
85 #ifndef DEFAULT_ENTRY_ADDRESS
86 #define DEFAULT_ENTRY_ADDRESS __start
89 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
90 char *new_name
, *a_name
;
91 unsigned long data_start
, bss_start
, entry_address
;
95 struct headers ohdr
, nhdr
;
103 char buffer
[BUFSIZE
];
105 if ((old
= open (a_name
, O_RDONLY
)) < 0)
106 fatal_unexec ("opening %s", a_name
);
108 new = creat (new_name
, 0666);
109 if (new < 0) fatal_unexec ("creating %s", new_name
);
111 if ((fstat (old
, &stat
) == -1))
112 fatal_unexec ("fstat %s", a_name
);
114 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
116 if (oldptr
== (char *)-1)
117 fatal_unexec ("mmap %s", a_name
);
121 /* This is a copy of the a.out header of the original executable */
123 ohdr
= (*(struct headers
*)oldptr
);
125 /* This is where we build the new header from the in-memory copy */
127 nhdr
= *((struct headers
*)TEXT_START
);
129 /* First do some consistency checks */
131 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
132 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
134 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
135 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
139 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
141 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
142 nhdr
.fhdr
.f_opthdr
, sizeof (nhdr
.aout
));
145 if (nhdr
.aout
.magic
!= ZMAGIC
)
147 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
148 nhdr
.aout
.magic
, ZMAGIC
);
153 /* Now check the existence of certain header section and grab
156 #define CHECK_SCNHDR(ptr, name, flags) \
158 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
159 if (strcmp (nhdr.section[i].s_name, name) == 0) \
161 if (nhdr.section[i].s_flags != flags) \
162 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
163 nhdr.section[i].s_flags, flags, name); \
164 ptr = nhdr.section + i; \
167 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
168 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
170 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
172 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
174 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
177 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
180 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
182 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
184 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
187 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
188 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
190 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
191 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
192 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
195 pagesize
= getpagesize ();
196 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
198 /* Remember the current break */
202 nhdr
.aout
.dsize
= brk
- DATA_START
;
204 if (entry_address
== 0)
206 extern DEFAULT_ENTRY_ADDRESS ();
207 nhdr
.aout
.entry
= (unsigned long)DEFAULT_ENTRY_ADDRESS
;
210 nhdr
.aout
.entry
= entry_address
;
212 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
214 if (rdata_section
!= NULL
)
216 rdata_section
->s_size
= data_start
- DATA_START
;
218 /* Adjust start and virtual addresses of rdata_section, too. */
219 rdata_section
->s_vaddr
= DATA_START
;
220 rdata_section
->s_paddr
= DATA_START
;
221 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
224 data_section
->s_vaddr
= data_start
;
225 data_section
->s_paddr
= data_start
;
226 data_section
->s_size
= brk
- data_start
;
228 if (rdata_section
!= NULL
)
230 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
233 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
234 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
235 if (lit8_section
!= NULL
)
237 lit8_section
->s_vaddr
= vaddr
;
238 lit8_section
->s_paddr
= vaddr
;
239 lit8_section
->s_size
= 0;
240 lit8_section
->s_scnptr
= scnptr
;
242 if (lit4_section
!= NULL
)
244 lit4_section
->s_vaddr
= vaddr
;
245 lit4_section
->s_paddr
= vaddr
;
246 lit4_section
->s_size
= 0;
247 lit4_section
->s_scnptr
= scnptr
;
249 if (sdata_section
!= NULL
)
251 sdata_section
->s_vaddr
= vaddr
;
252 sdata_section
->s_paddr
= vaddr
;
253 sdata_section
->s_size
= 0;
254 sdata_section
->s_scnptr
= scnptr
;
257 if (xdata_section
!= NULL
)
259 xdata_section
->s_vaddr
= vaddr
;
260 xdata_section
->s_paddr
= vaddr
;
261 xdata_section
->s_size
= 0;
262 xdata_section
->s_scnptr
= scnptr
;
266 if (got_section
!= NULL
)
268 got_section
->s_vaddr
= vaddr
;
269 got_section
->s_paddr
= vaddr
;
270 got_section
->s_size
= 0;
271 got_section
->s_scnptr
= scnptr
;
274 if (sbss_section
!= NULL
)
276 sbss_section
->s_vaddr
= vaddr
;
277 sbss_section
->s_paddr
= vaddr
;
278 sbss_section
->s_size
= 0;
279 sbss_section
->s_scnptr
= scnptr
;
281 if (bss_section
!= NULL
)
283 bss_section
->s_vaddr
= vaddr
;
284 bss_section
->s_paddr
= vaddr
;
285 bss_section
->s_size
= 0;
286 bss_section
->s_scnptr
= scnptr
;
289 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
290 "writing text section to %s", new_name
);
291 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
292 "writing data section to %s", new_name
);
296 * Construct new symbol table header
299 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
301 #define symhdr ((pHDRR)buffer)
302 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
303 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
304 nhdr
.fhdr
.f_symptr
= newsyms
;
305 symhdr
->cbLineOffset
+= symrel
;
306 symhdr
->cbDnOffset
+= symrel
;
307 symhdr
->cbPdOffset
+= symrel
;
308 symhdr
->cbSymOffset
+= symrel
;
309 symhdr
->cbOptOffset
+= symrel
;
310 symhdr
->cbAuxOffset
+= symrel
;
311 symhdr
->cbSsOffset
+= symrel
;
312 symhdr
->cbSsExtOffset
+= symrel
;
313 symhdr
->cbFdOffset
+= symrel
;
314 symhdr
->cbRfdOffset
+= symrel
;
315 symhdr
->cbExtOffset
+= symrel
;
317 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
320 * Copy the symbol table and line numbers
322 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
323 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
324 "writing symbol table of %s", new_name
);
328 /* Not needed for now */
330 update_dynamic_symbols (oldptr
, new_name
, new, newsyms
,
331 ((pHDRR
) (oldptr
+ ohdr
.fhdr
.f_symptr
))->issExtMax
,
332 ((pHDRR
) (oldptr
+ ohdr
.fhdr
.f_symptr
))->cbExtOffset
,
333 ((pHDRR
) (oldptr
+ ohdr
.fhdr
.f_symptr
))->cbSsExtOffset
);
339 SEEK (new, 0, "seeking to start of header in %s", new_name
);
340 WRITE (new, &nhdr
, sizeof (nhdr
),
341 "writing header of %s", new_name
);
351 /* Not needed for now */
353 /* The following function updates the values of some symbols
354 that are used by the dynamic loader:
362 update_dynamic_symbols (old
, new_name
, new, newsyms
, nsyms
, symoff
, stroff
)
363 char *old
; /* Pointer to old executable */
364 char *new_name
; /* Name of new executable */
365 int new; /* File descriptor for new executable */
366 long newsyms
; /* Offset of Symbol table in new executable */
367 int nsyms
; /* Number of symbol table entries */
368 long symoff
; /* Offset of External Symbols in old file */
369 long stroff
; /* Offset of string table in old file */
375 /* We go through the symbol table entries until we have found the two
378 /* cbEXTR is the size of an external symbol table entry */
380 for (i
= 0; i
< nsyms
&& found
< 2; i
+= cbEXTR
)
382 register pEXTR x
= (pEXTR
) (old
+ symoff
+ i
);
385 s
= old
+ stroff
+ x
->asym
.iss
; /* name of the symbol */
387 if (!strcmp(s
,"_edata"))
390 bcopy (x
, &n_edata
, cbEXTR
);
391 n_edata
.asym
.value
= Brk
;
392 SEEK (new, newsyms
+ cbHDRR
+ i
,
393 "seeking to symbol _edata in %s", new_name
);
394 WRITE (new, &n_edata
, cbEXTR
,
395 "writing symbol table entry for _edata into %s", new_name
);
397 else if (!strcmp(s
,"_end"))
400 bcopy (x
, &n_end
, cbEXTR
);
401 n_end
.asym
.value
= Brk
;
402 SEEK (new, newsyms
+ cbHDRR
+ i
,
403 "seeking to symbol _end in %s", new_name
);
404 WRITE (new, &n_end
, cbEXTR
,
405 "writing symbol table entry for _end into %s", new_name
);
417 * After successfully building the new a.out, mark it executable
425 int um
= umask (777);
427 if (stat (name
, &sbuf
) < 0)
428 fatal_unexec ("getting protection on %s", name
);
429 sbuf
.st_mode
|= 0111 & ~um
;
430 if (chmod (name
, sbuf
.st_mode
) < 0)
431 fatal_unexec ("setting protection on %s", name
);
435 fatal_unexec (s
, va_alist
)
441 fputs ("unexec: unexpected end of file, ", stderr
);
443 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
445 _doprnt (s
, ap
, stderr
);
446 fputs (".\n", stderr
);