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>
39 #else /* __NetBSD__ */
41 * NetBSD/Alpha does not have 'normal' user-land ECOFF support because
42 * there's no desire to support ECOFF as the executable format in the
45 #include <sys/exec_ecoff.h>
47 /* Structures, constants, etc., that NetBSD defines strangely. */
48 #define filehdr ecoff_filehdr
49 #define aouthdr ecoff_aouthdr
50 #define scnhdr ecoff_scnhdr
51 #define HDRR struct ecoff_symhdr
53 #define cbHDRR sizeof(HDRR)
54 #define ALPHAMAGIC ECOFF_MAGIC_NETBSD_ALPHA
55 #define ZMAGIC ECOFF_ZMAGIC
57 /* Misc. constants that NetBSD doesn't define at all. */
58 #define ALPHAUMAGIC 0617
59 #define _MIPS_NSCNS_MAX 35
60 #define STYP_TEXT 0x00000020
61 #define STYP_DATA 0x00000040
62 #define STYP_BSS 0x00000080
63 #define STYP_RDATA 0x00000100
64 #define STYP_SDATA 0x00000200
65 #define STYP_SBSS 0x00000400
66 #define STYP_INIT 0x80000000
71 #define _RDATA ".rdata"
72 #define _SDATA ".sdata"
74 #endif /* __NetBSD__ */
76 static void fatal_unexec ();
77 static void mark_x ();
79 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
81 if (read (_fd, _buffer, _size) != _size) \
82 fatal_unexec (_error_message, _error_arg);
84 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
85 if (write (_fd, _buffer, _size) != _size) \
86 fatal_unexec (_error_message, _error_arg);
88 #define SEEK(_fd, _position, _error_message, _error_arg) \
90 if (lseek (_fd, _position, L_SET) != _position) \
91 fatal_unexec (_error_message, _error_arg);
94 extern char *strerror ();
100 static struct scnhdr
*text_section
;
101 static struct scnhdr
*rel_dyn_section
;
102 static struct scnhdr
*dynstr_section
;
103 static struct scnhdr
*dynsym_section
;
104 static struct scnhdr
*init_section
;
105 static struct scnhdr
*finit_section
;
106 static struct scnhdr
*rdata_section
;
107 static struct scnhdr
*rconst_section
;
108 static struct scnhdr
*data_section
;
109 static struct scnhdr
*pdata_section
;
110 static struct scnhdr
*xdata_section
;
111 static struct scnhdr
*got_section
;
112 static struct scnhdr
*lit8_section
;
113 static struct scnhdr
*lit4_section
;
114 static struct scnhdr
*sdata_section
;
115 static struct scnhdr
*sbss_section
;
116 static struct scnhdr
*bss_section
;
118 static struct scnhdr old_data_scnhdr
;
120 static unsigned long Brk
;
125 struct scnhdr section
[_MIPS_NSCNS_MAX
];
130 /* Define name of label for entry point for the dumped executable. */
132 #ifndef DEFAULT_ENTRY_ADDRESS
133 #define DEFAULT_ENTRY_ADDRESS __start
136 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
137 char *new_name
, *a_name
;
138 unsigned long data_start
, bss_start
, entry_address
;
142 struct headers ohdr
, nhdr
;
145 long newsyms
, symrel
;
150 char buffer
[BUFSIZE
];
152 if ((old
= open (a_name
, O_RDONLY
)) < 0)
153 fatal_unexec ("opening %s", a_name
);
155 new = creat (new_name
, 0666);
156 if (new < 0) fatal_unexec ("creating %s", new_name
);
158 if ((fstat (old
, &stat
) == -1))
159 fatal_unexec ("fstat %s", a_name
);
161 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
163 if (oldptr
== (char *)-1)
164 fatal_unexec ("mmap %s", a_name
);
168 /* This is a copy of the a.out header of the original executable */
170 ohdr
= (*(struct headers
*)oldptr
);
172 /* This is where we build the new header from the in-memory copy */
174 nhdr
= *((struct headers
*)TEXT_START
);
176 /* First do some consistency checks */
178 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
179 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
181 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
182 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
186 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
188 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
189 nhdr
.fhdr
.f_opthdr
, sizeof (nhdr
.aout
));
192 if (nhdr
.aout
.magic
!= ZMAGIC
)
194 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
195 nhdr
.aout
.magic
, ZMAGIC
);
200 /* Now check the existence of certain header section and grab
203 #define CHECK_SCNHDR(ptr, name, flags) \
205 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
206 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
208 if (nhdr.section[i].s_flags != flags) \
209 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
210 nhdr.section[i].s_flags, flags, name); \
211 ptr = nhdr.section + i; \
214 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
215 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
217 CHECK_SCNHDR (rel_dyn_section
, _REL_DYN
, STYP_REL_DYN
);
218 #endif /* _REL_DYN */
220 CHECK_SCNHDR (dynsym_section
, _DYNSYM
, STYP_DYNSYM
);
221 #endif /* _REL_DYN */
223 CHECK_SCNHDR (dynstr_section
, _DYNSTR
, STYP_DYNSTR
);
224 #endif /* _REL_DYN */
226 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
228 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
230 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
233 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
236 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
238 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
240 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
243 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
244 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
246 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
247 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
248 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
251 pagesize
= getpagesize ();
252 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
254 /* Remember the current break */
258 bcopy (data_section
, &old_data_scnhdr
, sizeof (old_data_scnhdr
));
260 nhdr
.aout
.dsize
= brk
- DATA_START
;
262 if (entry_address
== 0)
264 extern DEFAULT_ENTRY_ADDRESS ();
265 nhdr
.aout
.entry
= (unsigned long)DEFAULT_ENTRY_ADDRESS
;
268 nhdr
.aout
.entry
= entry_address
;
270 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
272 if (rdata_section
!= NULL
)
274 rdata_section
->s_size
= data_start
- DATA_START
;
276 /* Adjust start and virtual addresses of rdata_section, too. */
277 rdata_section
->s_vaddr
= DATA_START
;
278 rdata_section
->s_paddr
= DATA_START
;
279 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
282 data_section
->s_vaddr
= data_start
;
283 data_section
->s_paddr
= data_start
;
284 data_section
->s_size
= brk
- data_start
;
286 if (rdata_section
!= NULL
)
288 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
291 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
292 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
293 if (lit8_section
!= NULL
)
295 lit8_section
->s_vaddr
= vaddr
;
296 lit8_section
->s_paddr
= vaddr
;
297 lit8_section
->s_size
= 0;
298 lit8_section
->s_scnptr
= scnptr
;
300 if (lit4_section
!= NULL
)
302 lit4_section
->s_vaddr
= vaddr
;
303 lit4_section
->s_paddr
= vaddr
;
304 lit4_section
->s_size
= 0;
305 lit4_section
->s_scnptr
= scnptr
;
307 if (sdata_section
!= NULL
)
309 sdata_section
->s_vaddr
= vaddr
;
310 sdata_section
->s_paddr
= vaddr
;
311 sdata_section
->s_size
= 0;
312 sdata_section
->s_scnptr
= scnptr
;
315 if (xdata_section
!= NULL
)
317 xdata_section
->s_vaddr
= vaddr
;
318 xdata_section
->s_paddr
= vaddr
;
319 xdata_section
->s_size
= 0;
320 xdata_section
->s_scnptr
= scnptr
;
324 if (got_section
!= NULL
)
326 bcopy (got_section
, buffer
, sizeof (struct scnhdr
));
328 got_section
->s_vaddr
= vaddr
;
329 got_section
->s_paddr
= vaddr
;
330 got_section
->s_size
= 0;
331 got_section
->s_scnptr
= scnptr
;
334 if (sbss_section
!= NULL
)
336 sbss_section
->s_vaddr
= vaddr
;
337 sbss_section
->s_paddr
= vaddr
;
338 sbss_section
->s_size
= 0;
339 sbss_section
->s_scnptr
= scnptr
;
341 if (bss_section
!= NULL
)
343 bss_section
->s_vaddr
= vaddr
;
344 bss_section
->s_paddr
= vaddr
;
345 bss_section
->s_size
= 0;
346 bss_section
->s_scnptr
= scnptr
;
349 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
350 "writing text section to %s", new_name
);
351 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
352 "writing data section to %s", new_name
);
355 #define old_got_section ((struct scnhdr *)buffer)
357 if (got_section
!= NULL
)
359 SEEK (new, old_got_section
->s_scnptr
,
360 "seeking to start of got_section in %s", new_name
);
361 WRITE (new, oldptr
+ old_got_section
->s_scnptr
, old_got_section
->s_size
,
362 "writing new got_section of %s", new_name
);
363 SEEK (new, nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
,
364 "seeking to end of data section of %s", new_name
);
367 #undef old_got_section
371 * Construct new symbol table header
374 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
376 #define symhdr ((pHDRR)buffer)
377 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
378 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
379 nhdr
.fhdr
.f_symptr
= newsyms
;
380 symhdr
->cbLineOffset
+= symrel
;
381 symhdr
->cbDnOffset
+= symrel
;
382 symhdr
->cbPdOffset
+= symrel
;
383 symhdr
->cbSymOffset
+= symrel
;
384 symhdr
->cbOptOffset
+= symrel
;
385 symhdr
->cbAuxOffset
+= symrel
;
386 symhdr
->cbSsOffset
+= symrel
;
387 symhdr
->cbSsExtOffset
+= symrel
;
388 symhdr
->cbFdOffset
+= symrel
;
389 symhdr
->cbRfdOffset
+= symrel
;
390 symhdr
->cbExtOffset
+= symrel
;
392 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
395 * Copy the symbol table and line numbers
397 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
398 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
399 "writing symbol table of %s", new_name
);
403 update_dynamic_symbols (oldptr
, new_name
, new, nhdr
.aout
);
408 SEEK (new, 0, "seeking to start of header in %s", new_name
);
409 WRITE (new, &nhdr
, sizeof (nhdr
),
410 "writing header of %s", new_name
);
419 update_dynamic_symbols (old
, new_name
, new, aout
)
420 char *old
; /* Pointer to old executable */
421 char *new_name
; /* Name of new executable */
422 int new; /* File descriptor for new executable */
423 struct aouthdr aout
; /* a.out info from the file header */
425 #if !defined (__linux__) && !defined (__NetBSD__)
427 typedef struct dynrel_info
{
435 int nsyms
= rel_dyn_section
->s_size
/ sizeof (struct dynrel_info
);
437 dr_info
* rd_base
= (dr_info
*) (old
+ rel_dyn_section
->s_scnptr
);
438 Elf32_Sym
* ds_base
= (Elf32_Sym
*) (old
+ dynsym_section
->s_scnptr
);
440 for (i
= 0; i
< nsyms
; i
++) {
441 register Elf32_Sym x
;
443 if (rd_base
[i
].index
== 0)
446 x
= ds_base
[rd_base
[i
].index
];
449 fprintf (stderr
, "Object inspected: %s, addr = %lx, shndx = %x",
450 old
+ dynstr_section
->s_scnptr
+ x
.st_name
, rd_base
[i
].addr
, x
.st_shndx
);
454 if ((ELF32_ST_BIND (x
.st_info
) == STB_GLOBAL
)
456 /* && (x.st_value == NULL) */
458 /* OK, this is probably a reference to an object in a shared
459 library, so copy the old value. This is done in several steps:
460 1. reladdr is the address of the location in question relative to
461 the start of the data section,
462 2. oldref is the addr is the mapped in temacs executable,
463 3. newref is the address of the location in question in the
465 4. len is the size of the object reference in bytes --
466 currently only 4 (long) and 8 (quad) are supported.
468 register unsigned long reladdr
= (long)rd_base
[i
].addr
- old_data_scnhdr
.s_vaddr
;
469 char * oldref
= old
+ old_data_scnhdr
.s_scnptr
+ reladdr
;
470 unsigned long newref
= aout
.tsize
+ reladdr
;
474 fprintf (stderr
, "...relocated\n");
477 if (rd_base
[i
].type
== R_REFLONG
)
479 else if (rd_base
[i
].type
== R_REFQUAD
)
482 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", i
);
484 SEEK (new, newref
, "seeking to dynamic symbol in %s", new_name
);
485 WRITE (new, oldref
, len
, "writing old dynrel info in %s", new_name
);
490 fprintf (stderr
, "...not relocated\n");
495 #endif /* not __linux__ and not __NetBSD__ */
502 * After successfully building the new a.out, mark it executable
510 int um
= umask (777);
512 if (stat (name
, &sbuf
) < 0)
513 fatal_unexec ("getting protection on %s", name
);
514 sbuf
.st_mode
|= 0111 & ~um
;
515 if (chmod (name
, sbuf
.st_mode
) < 0)
516 fatal_unexec ("setting protection on %s", name
);
520 fatal_unexec (s
, arg
)
525 fputs ("unexec: unexpected end of file, ", stderr
);
527 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
528 fprintf (stderr
, s
, arg
);
529 fputs (".\n", stderr
);