1 /* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
3 Copyright (C) 1994, 2000 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>
34 #if !defined (__NetBSD__) && !defined (__OpenBSD__)
43 #else /* __NetBSD__ or __OpenBSD__ */
45 * NetBSD/Alpha does not have 'normal' user-land ECOFF support because
46 * there's no desire to support ECOFF as the executable format in the
49 #include <sys/exec_ecoff.h>
51 /* Structures, constants, etc., that NetBSD defines strangely. */
52 #define filehdr ecoff_filehdr
53 #define aouthdr ecoff_aouthdr
54 #define scnhdr ecoff_scnhdr
55 #define HDRR struct ecoff_symhdr
57 #define cbHDRR sizeof(HDRR)
59 #define ALPHAMAGIC ECOFF_MAGIC_NATIVE_ALPHA
61 #define ALPHAMAGIC ECOFF_MAGIC_NETBSD_ALPHA
63 #define ZMAGIC ECOFF_ZMAGIC
65 /* Misc. constants that NetBSD doesn't define at all. */
66 #define ALPHAUMAGIC 0617
67 #define _MIPS_NSCNS_MAX 35
68 #define STYP_TEXT 0x00000020
69 #define STYP_DATA 0x00000040
70 #define STYP_BSS 0x00000080
71 #define STYP_RDATA 0x00000100
72 #define STYP_SDATA 0x00000200
73 #define STYP_SBSS 0x00000400
74 #define STYP_INIT 0x80000000
79 #define _RDATA ".rdata"
80 #define _SDATA ".sdata"
82 #endif /* __NetBSD__ || __OpenBSD__ */
84 static void fatal_unexec
__P ((char *, char *));
85 static void mark_x
__P ((char *));
87 static void update_dynamic_symbols
__P ((char *, char *, int, struct aouthdr
));
89 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
91 if (read (_fd, _buffer, _size) != _size) \
92 fatal_unexec (_error_message, _error_arg);
94 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
95 if (write (_fd, _buffer, _size) != _size) \
96 fatal_unexec (_error_message, _error_arg);
98 #define SEEK(_fd, _position, _error_message, _error_arg) \
100 if (lseek (_fd, _position, L_SET) != _position) \
101 fatal_unexec (_error_message, _error_arg);
111 static struct scnhdr
*text_section
;
112 static struct scnhdr
*rel_dyn_section
;
113 static struct scnhdr
*dynstr_section
;
114 static struct scnhdr
*dynsym_section
;
115 static struct scnhdr
*init_section
;
116 static struct scnhdr
*finit_section
;
117 static struct scnhdr
*rdata_section
;
118 static struct scnhdr
*rconst_section
;
119 static struct scnhdr
*data_section
;
120 static struct scnhdr
*pdata_section
;
121 static struct scnhdr
*xdata_section
;
122 static struct scnhdr
*got_section
;
123 static struct scnhdr
*lit8_section
;
124 static struct scnhdr
*lit4_section
;
125 static struct scnhdr
*sdata_section
;
126 static struct scnhdr
*sbss_section
;
127 static struct scnhdr
*bss_section
;
129 static struct scnhdr old_data_scnhdr
;
131 static unsigned long Brk
;
136 struct scnhdr section
[_MIPS_NSCNS_MAX
];
141 /* Define name of label for entry point for the dumped executable. */
143 #ifndef DEFAULT_ENTRY_ADDRESS
144 #define DEFAULT_ENTRY_ADDRESS __start
148 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
149 char *new_name
, *a_name
;
150 unsigned long data_start
, bss_start
, entry_address
;
154 struct headers ohdr
, nhdr
;
157 long newsyms
, symrel
;
162 char buffer
[BUFSIZE
];
164 if ((old
= open (a_name
, O_RDONLY
)) < 0)
165 fatal_unexec ("opening %s", a_name
);
167 new = creat (new_name
, 0666);
168 if (new < 0) fatal_unexec ("creating %s", new_name
);
170 if ((fstat (old
, &stat
) == -1))
171 fatal_unexec ("fstat %s", a_name
);
173 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
175 if (oldptr
== (char *)-1)
176 fatal_unexec ("mmap %s", a_name
);
180 /* This is a copy of the a.out header of the original executable */
182 ohdr
= (*(struct headers
*)oldptr
);
184 /* This is where we build the new header from the in-memory copy */
186 nhdr
= *((struct headers
*)TEXT_START
);
188 /* First do some consistency checks */
190 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
191 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
193 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
194 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
198 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
200 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
201 nhdr
.fhdr
.f_opthdr
, (int)sizeof (nhdr
.aout
));
204 if (nhdr
.aout
.magic
!= ZMAGIC
)
206 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
207 nhdr
.aout
.magic
, ZMAGIC
);
212 /* Now check the existence of certain header section and grab
215 #define CHECK_SCNHDR(ptr, name, flags) \
217 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
218 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
220 if (nhdr.section[i].s_flags != flags) \
221 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
222 nhdr.section[i].s_flags, flags, name); \
223 ptr = nhdr.section + i; \
226 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
227 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
229 CHECK_SCNHDR (rel_dyn_section
, _REL_DYN
, STYP_REL_DYN
);
230 #endif /* _REL_DYN */
232 CHECK_SCNHDR (dynsym_section
, _DYNSYM
, STYP_DYNSYM
);
233 #endif /* _REL_DYN */
235 CHECK_SCNHDR (dynstr_section
, _DYNSTR
, STYP_DYNSTR
);
236 #endif /* _REL_DYN */
238 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
240 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
242 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
245 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
248 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
250 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
252 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
255 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
256 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
258 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
259 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
260 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
263 pagesize
= getpagesize ();
264 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
266 /* Remember the current break */
270 bcopy (data_section
, &old_data_scnhdr
, sizeof (old_data_scnhdr
));
272 nhdr
.aout
.dsize
= brk
- DATA_START
;
274 if (entry_address
== 0)
276 extern DEFAULT_ENTRY_ADDRESS ();
277 nhdr
.aout
.entry
= (unsigned long)DEFAULT_ENTRY_ADDRESS
;
280 nhdr
.aout
.entry
= entry_address
;
282 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
284 if (rdata_section
!= NULL
)
286 rdata_section
->s_size
= data_start
- DATA_START
;
288 /* Adjust start and virtual addresses of rdata_section, too. */
289 rdata_section
->s_vaddr
= DATA_START
;
290 rdata_section
->s_paddr
= DATA_START
;
291 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
294 data_section
->s_vaddr
= data_start
;
295 data_section
->s_paddr
= data_start
;
296 data_section
->s_size
= brk
- data_start
;
298 if (rdata_section
!= NULL
)
300 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
303 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
304 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
305 if (lit8_section
!= NULL
)
307 lit8_section
->s_vaddr
= vaddr
;
308 lit8_section
->s_paddr
= vaddr
;
309 lit8_section
->s_size
= 0;
310 lit8_section
->s_scnptr
= scnptr
;
312 if (lit4_section
!= NULL
)
314 lit4_section
->s_vaddr
= vaddr
;
315 lit4_section
->s_paddr
= vaddr
;
316 lit4_section
->s_size
= 0;
317 lit4_section
->s_scnptr
= scnptr
;
319 if (sdata_section
!= NULL
)
321 sdata_section
->s_vaddr
= vaddr
;
322 sdata_section
->s_paddr
= vaddr
;
323 sdata_section
->s_size
= 0;
324 sdata_section
->s_scnptr
= scnptr
;
327 if (xdata_section
!= NULL
)
329 xdata_section
->s_vaddr
= vaddr
;
330 xdata_section
->s_paddr
= vaddr
;
331 xdata_section
->s_size
= 0;
332 xdata_section
->s_scnptr
= scnptr
;
336 if (got_section
!= NULL
)
338 bcopy (got_section
, buffer
, sizeof (struct scnhdr
));
340 got_section
->s_vaddr
= vaddr
;
341 got_section
->s_paddr
= vaddr
;
342 got_section
->s_size
= 0;
343 got_section
->s_scnptr
= scnptr
;
346 if (sbss_section
!= NULL
)
348 sbss_section
->s_vaddr
= vaddr
;
349 sbss_section
->s_paddr
= vaddr
;
350 sbss_section
->s_size
= 0;
351 sbss_section
->s_scnptr
= scnptr
;
353 if (bss_section
!= NULL
)
355 bss_section
->s_vaddr
= vaddr
;
356 bss_section
->s_paddr
= vaddr
;
357 bss_section
->s_size
= 0;
358 bss_section
->s_scnptr
= scnptr
;
361 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
362 "writing text section to %s", new_name
);
363 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
364 "writing data section to %s", new_name
);
367 #define old_got_section ((struct scnhdr *)buffer)
369 if (got_section
!= NULL
)
371 SEEK (new, old_got_section
->s_scnptr
,
372 "seeking to start of got_section in %s", new_name
);
373 WRITE (new, oldptr
+ old_got_section
->s_scnptr
, old_got_section
->s_size
,
374 "writing new got_section of %s", new_name
);
375 SEEK (new, nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
,
376 "seeking to end of data section of %s", new_name
);
379 #undef old_got_section
383 * Construct new symbol table header
386 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
388 #define symhdr ((pHDRR)buffer)
389 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
390 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
391 nhdr
.fhdr
.f_symptr
= newsyms
;
392 symhdr
->cbLineOffset
+= symrel
;
393 symhdr
->cbDnOffset
+= symrel
;
394 symhdr
->cbPdOffset
+= symrel
;
395 symhdr
->cbSymOffset
+= symrel
;
396 symhdr
->cbOptOffset
+= symrel
;
397 symhdr
->cbAuxOffset
+= symrel
;
398 symhdr
->cbSsOffset
+= symrel
;
399 symhdr
->cbSsExtOffset
+= symrel
;
400 symhdr
->cbFdOffset
+= symrel
;
401 symhdr
->cbRfdOffset
+= symrel
;
402 symhdr
->cbExtOffset
+= symrel
;
404 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
407 * Copy the symbol table and line numbers
409 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
410 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
411 "writing symbol table of %s", new_name
);
415 update_dynamic_symbols (oldptr
, new_name
, new, nhdr
.aout
);
420 SEEK (new, 0, "seeking to start of header in %s", new_name
);
421 WRITE (new, &nhdr
, sizeof (nhdr
),
422 "writing header of %s", new_name
);
431 update_dynamic_symbols (old
, new_name
, new, aout
)
432 char *old
; /* Pointer to old executable */
433 char *new_name
; /* Name of new executable */
434 int new; /* File descriptor for new executable */
435 struct aouthdr aout
; /* a.out info from the file header */
437 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
439 typedef struct dynrel_info
{
447 int nsyms
= rel_dyn_section
->s_size
/ sizeof (struct dynrel_info
);
449 dr_info
* rd_base
= (dr_info
*) (old
+ rel_dyn_section
->s_scnptr
);
450 Elf32_Sym
* ds_base
= (Elf32_Sym
*) (old
+ dynsym_section
->s_scnptr
);
452 for (i
= 0; i
< nsyms
; i
++) {
453 register Elf32_Sym x
;
455 if (rd_base
[i
].index
== 0)
458 x
= ds_base
[rd_base
[i
].index
];
461 fprintf (stderr
, "Object inspected: %s, addr = %lx, shndx = %x",
462 old
+ dynstr_section
->s_scnptr
+ x
.st_name
, rd_base
[i
].addr
, x
.st_shndx
);
466 if ((ELF32_ST_BIND (x
.st_info
) == STB_GLOBAL
)
468 /* && (x.st_value == NULL) */
470 /* OK, this is probably a reference to an object in a shared
471 library, so copy the old value. This is done in several steps:
472 1. reladdr is the address of the location in question relative to
473 the start of the data section,
474 2. oldref is the addr is the mapped in temacs executable,
475 3. newref is the address of the location in question in the
477 4. len is the size of the object reference in bytes --
478 currently only 4 (long) and 8 (quad) are supported.
480 register unsigned long reladdr
= (long)rd_base
[i
].addr
- old_data_scnhdr
.s_vaddr
;
481 char * oldref
= old
+ old_data_scnhdr
.s_scnptr
+ reladdr
;
482 unsigned long newref
= aout
.tsize
+ reladdr
;
486 fprintf (stderr
, "...relocated\n");
489 if (rd_base
[i
].type
== R_REFLONG
)
491 else if (rd_base
[i
].type
== R_REFQUAD
)
494 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i
);
496 SEEK (new, newref
, "seeking to dynamic symbol in %s", new_name
);
497 WRITE (new, oldref
, len
, "writing old dynrel info in %s", new_name
);
502 fprintf (stderr
, "...not relocated\n");
507 #endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
514 * After successfully building the new a.out, mark it executable
522 int um
= umask (777);
524 if (stat (name
, &sbuf
) < 0)
525 fatal_unexec ("getting protection on %s", name
);
526 sbuf
.st_mode
|= 0111 & ~um
;
527 if (chmod (name
, sbuf
.st_mode
) < 0)
528 fatal_unexec ("setting protection on %s", name
);
532 fatal_unexec (s
, arg
)
537 fputs ("unexec: unexpected end of file, ", stderr
);
539 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
540 fprintf (stderr
, s
, arg
);
541 fputs (".\n", stderr
);