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>
33 #if !defined (__NetBSD__) && !defined (__OpenBSD__)
42 #else /* __NetBSD__ or __OpenBSD__ */
44 * NetBSD/Alpha does not have 'normal' user-land ECOFF support because
45 * there's no desire to support ECOFF as the executable format in the
48 #include <sys/exec_ecoff.h>
50 /* Structures, constants, etc., that NetBSD defines strangely. */
51 #define filehdr ecoff_filehdr
52 #define aouthdr ecoff_aouthdr
53 #define scnhdr ecoff_scnhdr
54 #define HDRR struct ecoff_symhdr
56 #define cbHDRR sizeof(HDRR)
58 #define ALPHAMAGIC ECOFF_MAGIC_NATIVE_ALPHA
60 #define ALPHAMAGIC ECOFF_MAGIC_NETBSD_ALPHA
62 #define ZMAGIC ECOFF_ZMAGIC
64 /* Misc. constants that NetBSD doesn't define at all. */
65 #define ALPHAUMAGIC 0617
66 #define _MIPS_NSCNS_MAX 35
67 #define STYP_TEXT 0x00000020
68 #define STYP_DATA 0x00000040
69 #define STYP_BSS 0x00000080
70 #define STYP_RDATA 0x00000100
71 #define STYP_SDATA 0x00000200
72 #define STYP_SBSS 0x00000400
73 #define STYP_INIT 0x80000000
78 #define _RDATA ".rdata"
79 #define _SDATA ".sdata"
81 #endif /* __NetBSD__ || __OpenBSD__ */
83 static void fatal_unexec
__P ((char *, char *));
84 static void mark_x
__P ((char *));
86 static void update_dynamic_symbols
__P ((char *, char *, int, struct aouthdr
));
88 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
90 if (read (_fd, _buffer, _size) != _size) \
91 fatal_unexec (_error_message, _error_arg);
93 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
94 if (write (_fd, _buffer, _size) != _size) \
95 fatal_unexec (_error_message, _error_arg);
97 #define SEEK(_fd, _position, _error_message, _error_arg) \
99 if (lseek (_fd, _position, L_SET) != _position) \
100 fatal_unexec (_error_message, _error_arg);
110 static struct scnhdr
*text_section
;
111 static struct scnhdr
*rel_dyn_section
;
112 static struct scnhdr
*dynstr_section
;
113 static struct scnhdr
*dynsym_section
;
114 static struct scnhdr
*init_section
;
115 static struct scnhdr
*finit_section
;
116 static struct scnhdr
*rdata_section
;
117 static struct scnhdr
*rconst_section
;
118 static struct scnhdr
*data_section
;
119 static struct scnhdr
*pdata_section
;
120 static struct scnhdr
*xdata_section
;
121 static struct scnhdr
*got_section
;
122 static struct scnhdr
*lit8_section
;
123 static struct scnhdr
*lit4_section
;
124 static struct scnhdr
*sdata_section
;
125 static struct scnhdr
*sbss_section
;
126 static struct scnhdr
*bss_section
;
128 static struct scnhdr old_data_scnhdr
;
130 static unsigned long Brk
;
135 struct scnhdr section
[_MIPS_NSCNS_MAX
];
140 /* Define name of label for entry point for the dumped executable. */
142 #ifndef DEFAULT_ENTRY_ADDRESS
143 #define DEFAULT_ENTRY_ADDRESS __start
147 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
148 char *new_name
, *a_name
;
149 unsigned long data_start
, bss_start
, entry_address
;
153 struct headers ohdr
, nhdr
;
156 long newsyms
, symrel
;
161 char buffer
[BUFSIZE
];
163 if ((old
= open (a_name
, O_RDONLY
)) < 0)
164 fatal_unexec ("opening %s", a_name
);
166 new = creat (new_name
, 0666);
167 if (new < 0) fatal_unexec ("creating %s", new_name
);
169 if ((fstat (old
, &stat
) == -1))
170 fatal_unexec ("fstat %s", a_name
);
172 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
174 if (oldptr
== (char *)-1)
175 fatal_unexec ("mmap %s", a_name
);
179 /* This is a copy of the a.out header of the original executable */
181 ohdr
= (*(struct headers
*)oldptr
);
183 /* This is where we build the new header from the in-memory copy */
185 nhdr
= *((struct headers
*)TEXT_START
);
187 /* First do some consistency checks */
189 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
190 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
192 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
193 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
197 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
199 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
200 nhdr
.fhdr
.f_opthdr
, (int)sizeof (nhdr
.aout
));
203 if (nhdr
.aout
.magic
!= ZMAGIC
)
205 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
206 nhdr
.aout
.magic
, ZMAGIC
);
211 /* Now check the existence of certain header section and grab
214 #define CHECK_SCNHDR(ptr, name, flags) \
216 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
217 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
219 if (nhdr.section[i].s_flags != flags) \
220 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
221 nhdr.section[i].s_flags, flags, name); \
222 ptr = nhdr.section + i; \
225 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
226 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
228 CHECK_SCNHDR (rel_dyn_section
, _REL_DYN
, STYP_REL_DYN
);
229 #endif /* _REL_DYN */
231 CHECK_SCNHDR (dynsym_section
, _DYNSYM
, STYP_DYNSYM
);
232 #endif /* _REL_DYN */
234 CHECK_SCNHDR (dynstr_section
, _DYNSTR
, STYP_DYNSTR
);
235 #endif /* _REL_DYN */
237 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
239 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
241 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
244 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
247 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
249 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
251 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
254 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
255 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
257 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
258 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
259 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
262 pagesize
= getpagesize ();
263 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
265 /* Remember the current break */
269 bcopy (data_section
, &old_data_scnhdr
, sizeof (old_data_scnhdr
));
271 nhdr
.aout
.dsize
= brk
- DATA_START
;
273 if (entry_address
== 0)
275 extern DEFAULT_ENTRY_ADDRESS ();
276 nhdr
.aout
.entry
= (unsigned long)DEFAULT_ENTRY_ADDRESS
;
279 nhdr
.aout
.entry
= entry_address
;
281 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
283 if (rdata_section
!= NULL
)
285 rdata_section
->s_size
= data_start
- DATA_START
;
287 /* Adjust start and virtual addresses of rdata_section, too. */
288 rdata_section
->s_vaddr
= DATA_START
;
289 rdata_section
->s_paddr
= DATA_START
;
290 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
293 data_section
->s_vaddr
= data_start
;
294 data_section
->s_paddr
= data_start
;
295 data_section
->s_size
= brk
- data_start
;
297 if (rdata_section
!= NULL
)
299 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
302 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
303 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
304 if (lit8_section
!= NULL
)
306 lit8_section
->s_vaddr
= vaddr
;
307 lit8_section
->s_paddr
= vaddr
;
308 lit8_section
->s_size
= 0;
309 lit8_section
->s_scnptr
= scnptr
;
311 if (lit4_section
!= NULL
)
313 lit4_section
->s_vaddr
= vaddr
;
314 lit4_section
->s_paddr
= vaddr
;
315 lit4_section
->s_size
= 0;
316 lit4_section
->s_scnptr
= scnptr
;
318 if (sdata_section
!= NULL
)
320 sdata_section
->s_vaddr
= vaddr
;
321 sdata_section
->s_paddr
= vaddr
;
322 sdata_section
->s_size
= 0;
323 sdata_section
->s_scnptr
= scnptr
;
326 if (xdata_section
!= NULL
)
328 xdata_section
->s_vaddr
= vaddr
;
329 xdata_section
->s_paddr
= vaddr
;
330 xdata_section
->s_size
= 0;
331 xdata_section
->s_scnptr
= scnptr
;
335 if (got_section
!= NULL
)
337 bcopy (got_section
, buffer
, sizeof (struct scnhdr
));
339 got_section
->s_vaddr
= vaddr
;
340 got_section
->s_paddr
= vaddr
;
341 got_section
->s_size
= 0;
342 got_section
->s_scnptr
= scnptr
;
345 if (sbss_section
!= NULL
)
347 sbss_section
->s_vaddr
= vaddr
;
348 sbss_section
->s_paddr
= vaddr
;
349 sbss_section
->s_size
= 0;
350 sbss_section
->s_scnptr
= scnptr
;
352 if (bss_section
!= NULL
)
354 bss_section
->s_vaddr
= vaddr
;
355 bss_section
->s_paddr
= vaddr
;
356 bss_section
->s_size
= 0;
357 bss_section
->s_scnptr
= scnptr
;
360 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
361 "writing text section to %s", new_name
);
362 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
363 "writing data section to %s", new_name
);
366 #define old_got_section ((struct scnhdr *)buffer)
368 if (got_section
!= NULL
)
370 SEEK (new, old_got_section
->s_scnptr
,
371 "seeking to start of got_section in %s", new_name
);
372 WRITE (new, oldptr
+ old_got_section
->s_scnptr
, old_got_section
->s_size
,
373 "writing new got_section of %s", new_name
);
374 SEEK (new, nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
,
375 "seeking to end of data section of %s", new_name
);
378 #undef old_got_section
382 * Construct new symbol table header
385 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
387 #define symhdr ((pHDRR)buffer)
388 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
389 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
390 nhdr
.fhdr
.f_symptr
= newsyms
;
391 symhdr
->cbLineOffset
+= symrel
;
392 symhdr
->cbDnOffset
+= symrel
;
393 symhdr
->cbPdOffset
+= symrel
;
394 symhdr
->cbSymOffset
+= symrel
;
395 symhdr
->cbOptOffset
+= symrel
;
396 symhdr
->cbAuxOffset
+= symrel
;
397 symhdr
->cbSsOffset
+= symrel
;
398 symhdr
->cbSsExtOffset
+= symrel
;
399 symhdr
->cbFdOffset
+= symrel
;
400 symhdr
->cbRfdOffset
+= symrel
;
401 symhdr
->cbExtOffset
+= symrel
;
403 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
406 * Copy the symbol table and line numbers
408 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
409 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
410 "writing symbol table of %s", new_name
);
414 update_dynamic_symbols (oldptr
, new_name
, new, nhdr
.aout
);
419 SEEK (new, 0, "seeking to start of header in %s", new_name
);
420 WRITE (new, &nhdr
, sizeof (nhdr
),
421 "writing header of %s", new_name
);
430 update_dynamic_symbols (old
, new_name
, new, aout
)
431 char *old
; /* Pointer to old executable */
432 char *new_name
; /* Name of new executable */
433 int new; /* File descriptor for new executable */
434 struct aouthdr aout
; /* a.out info from the file header */
436 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
438 typedef struct dynrel_info
{
446 int nsyms
= rel_dyn_section
->s_size
/ sizeof (struct dynrel_info
);
448 dr_info
* rd_base
= (dr_info
*) (old
+ rel_dyn_section
->s_scnptr
);
449 Elf32_Sym
* ds_base
= (Elf32_Sym
*) (old
+ dynsym_section
->s_scnptr
);
451 for (i
= 0; i
< nsyms
; i
++) {
452 register Elf32_Sym x
;
454 if (rd_base
[i
].index
== 0)
457 x
= ds_base
[rd_base
[i
].index
];
460 fprintf (stderr
, "Object inspected: %s, addr = %lx, shndx = %x",
461 old
+ dynstr_section
->s_scnptr
+ x
.st_name
, rd_base
[i
].addr
, x
.st_shndx
);
465 if ((ELF32_ST_BIND (x
.st_info
) == STB_GLOBAL
)
467 /* && (x.st_value == NULL) */
469 /* OK, this is probably a reference to an object in a shared
470 library, so copy the old value. This is done in several steps:
471 1. reladdr is the address of the location in question relative to
472 the start of the data section,
473 2. oldref is the addr is the mapped in temacs executable,
474 3. newref is the address of the location in question in the
476 4. len is the size of the object reference in bytes --
477 currently only 4 (long) and 8 (quad) are supported.
479 register unsigned long reladdr
= (long)rd_base
[i
].addr
- old_data_scnhdr
.s_vaddr
;
480 char * oldref
= old
+ old_data_scnhdr
.s_scnptr
+ reladdr
;
481 unsigned long newref
= aout
.tsize
+ reladdr
;
485 fprintf (stderr
, "...relocated\n");
488 if (rd_base
[i
].type
== R_REFLONG
)
490 else if (rd_base
[i
].type
== R_REFQUAD
)
493 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i
);
495 SEEK (new, newref
, "seeking to dynamic symbol in %s", new_name
);
496 WRITE (new, oldref
, len
, "writing old dynrel info in %s", new_name
);
501 fprintf (stderr
, "...not relocated\n");
506 #endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
513 * After successfully building the new a.out, mark it executable
521 int um
= umask (777);
523 if (stat (name
, &sbuf
) < 0)
524 fatal_unexec ("getting protection on %s", name
);
525 sbuf
.st_mode
|= 0111 & ~um
;
526 if (chmod (name
, sbuf
.st_mode
) < 0)
527 fatal_unexec ("setting protection on %s", name
);
531 fatal_unexec (s
, arg
)
536 fputs ("unexec: unexpected end of file, ", stderr
);
538 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
539 fprintf (stderr
, s
, arg
);
540 fputs (".\n", stderr
);
544 /* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd
545 (do not change this comment) */