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>
30 #if !defined (__NetBSD__) && !defined (__OpenBSD__)
39 #else /* __NetBSD__ or __OpenBSD__ */
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)
55 #define ALPHAMAGIC ECOFF_MAGIC_NATIVE_ALPHA
57 #define ALPHAMAGIC ECOFF_MAGIC_NETBSD_ALPHA
59 #define ZMAGIC ECOFF_ZMAGIC
61 /* Misc. constants that NetBSD doesn't define at all. */
62 #define ALPHAUMAGIC 0617
63 #define _MIPS_NSCNS_MAX 35
64 #define STYP_TEXT 0x00000020
65 #define STYP_DATA 0x00000040
66 #define STYP_BSS 0x00000080
67 #define STYP_RDATA 0x00000100
68 #define STYP_SDATA 0x00000200
69 #define STYP_SBSS 0x00000400
70 #define STYP_INIT 0x80000000
75 #define _RDATA ".rdata"
76 #define _SDATA ".sdata"
78 #endif /* __NetBSD__ || __OpenBSD__ */
80 static void fatal_unexec ();
81 static void mark_x ();
83 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
85 if (read (_fd, _buffer, _size) != _size) \
86 fatal_unexec (_error_message, _error_arg);
88 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
89 if (write (_fd, _buffer, _size) != _size) \
90 fatal_unexec (_error_message, _error_arg);
92 #define SEEK(_fd, _position, _error_message, _error_arg) \
94 if (lseek (_fd, _position, L_SET) != _position) \
95 fatal_unexec (_error_message, _error_arg);
98 extern char *strerror ();
104 static struct scnhdr
*text_section
;
105 static struct scnhdr
*rel_dyn_section
;
106 static struct scnhdr
*dynstr_section
;
107 static struct scnhdr
*dynsym_section
;
108 static struct scnhdr
*init_section
;
109 static struct scnhdr
*finit_section
;
110 static struct scnhdr
*rdata_section
;
111 static struct scnhdr
*rconst_section
;
112 static struct scnhdr
*data_section
;
113 static struct scnhdr
*pdata_section
;
114 static struct scnhdr
*xdata_section
;
115 static struct scnhdr
*got_section
;
116 static struct scnhdr
*lit8_section
;
117 static struct scnhdr
*lit4_section
;
118 static struct scnhdr
*sdata_section
;
119 static struct scnhdr
*sbss_section
;
120 static struct scnhdr
*bss_section
;
122 static struct scnhdr old_data_scnhdr
;
124 static unsigned long Brk
;
129 struct scnhdr section
[_MIPS_NSCNS_MAX
];
134 /* Define name of label for entry point for the dumped executable. */
136 #ifndef DEFAULT_ENTRY_ADDRESS
137 #define DEFAULT_ENTRY_ADDRESS __start
140 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
141 char *new_name
, *a_name
;
142 unsigned long data_start
, bss_start
, entry_address
;
146 struct headers ohdr
, nhdr
;
149 long newsyms
, symrel
;
154 char buffer
[BUFSIZE
];
156 if ((old
= open (a_name
, O_RDONLY
)) < 0)
157 fatal_unexec ("opening %s", a_name
);
159 new = creat (new_name
, 0666);
160 if (new < 0) fatal_unexec ("creating %s", new_name
);
162 if ((fstat (old
, &stat
) == -1))
163 fatal_unexec ("fstat %s", a_name
);
165 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
167 if (oldptr
== (char *)-1)
168 fatal_unexec ("mmap %s", a_name
);
172 /* This is a copy of the a.out header of the original executable */
174 ohdr
= (*(struct headers
*)oldptr
);
176 /* This is where we build the new header from the in-memory copy */
178 nhdr
= *((struct headers
*)TEXT_START
);
180 /* First do some consistency checks */
182 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
183 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
185 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
186 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
190 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
192 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
193 nhdr
.fhdr
.f_opthdr
, (int)sizeof (nhdr
.aout
));
196 if (nhdr
.aout
.magic
!= ZMAGIC
)
198 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
199 nhdr
.aout
.magic
, ZMAGIC
);
204 /* Now check the existence of certain header section and grab
207 #define CHECK_SCNHDR(ptr, name, flags) \
209 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
210 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
212 if (nhdr.section[i].s_flags != flags) \
213 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
214 nhdr.section[i].s_flags, flags, name); \
215 ptr = nhdr.section + i; \
218 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
219 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
221 CHECK_SCNHDR (rel_dyn_section
, _REL_DYN
, STYP_REL_DYN
);
222 #endif /* _REL_DYN */
224 CHECK_SCNHDR (dynsym_section
, _DYNSYM
, STYP_DYNSYM
);
225 #endif /* _REL_DYN */
227 CHECK_SCNHDR (dynstr_section
, _DYNSTR
, STYP_DYNSTR
);
228 #endif /* _REL_DYN */
230 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
232 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
234 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
237 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
240 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
242 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
244 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
247 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
248 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
250 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
251 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
252 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
255 pagesize
= getpagesize ();
256 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
258 /* Remember the current break */
262 bcopy (data_section
, &old_data_scnhdr
, sizeof (old_data_scnhdr
));
264 nhdr
.aout
.dsize
= brk
- DATA_START
;
266 if (entry_address
== 0)
268 extern DEFAULT_ENTRY_ADDRESS ();
269 nhdr
.aout
.entry
= (unsigned long)DEFAULT_ENTRY_ADDRESS
;
272 nhdr
.aout
.entry
= entry_address
;
274 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
276 if (rdata_section
!= NULL
)
278 rdata_section
->s_size
= data_start
- DATA_START
;
280 /* Adjust start and virtual addresses of rdata_section, too. */
281 rdata_section
->s_vaddr
= DATA_START
;
282 rdata_section
->s_paddr
= DATA_START
;
283 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
286 data_section
->s_vaddr
= data_start
;
287 data_section
->s_paddr
= data_start
;
288 data_section
->s_size
= brk
- data_start
;
290 if (rdata_section
!= NULL
)
292 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
295 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
296 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
297 if (lit8_section
!= NULL
)
299 lit8_section
->s_vaddr
= vaddr
;
300 lit8_section
->s_paddr
= vaddr
;
301 lit8_section
->s_size
= 0;
302 lit8_section
->s_scnptr
= scnptr
;
304 if (lit4_section
!= NULL
)
306 lit4_section
->s_vaddr
= vaddr
;
307 lit4_section
->s_paddr
= vaddr
;
308 lit4_section
->s_size
= 0;
309 lit4_section
->s_scnptr
= scnptr
;
311 if (sdata_section
!= NULL
)
313 sdata_section
->s_vaddr
= vaddr
;
314 sdata_section
->s_paddr
= vaddr
;
315 sdata_section
->s_size
= 0;
316 sdata_section
->s_scnptr
= scnptr
;
319 if (xdata_section
!= NULL
)
321 xdata_section
->s_vaddr
= vaddr
;
322 xdata_section
->s_paddr
= vaddr
;
323 xdata_section
->s_size
= 0;
324 xdata_section
->s_scnptr
= scnptr
;
328 if (got_section
!= NULL
)
330 bcopy (got_section
, buffer
, sizeof (struct scnhdr
));
332 got_section
->s_vaddr
= vaddr
;
333 got_section
->s_paddr
= vaddr
;
334 got_section
->s_size
= 0;
335 got_section
->s_scnptr
= scnptr
;
338 if (sbss_section
!= NULL
)
340 sbss_section
->s_vaddr
= vaddr
;
341 sbss_section
->s_paddr
= vaddr
;
342 sbss_section
->s_size
= 0;
343 sbss_section
->s_scnptr
= scnptr
;
345 if (bss_section
!= NULL
)
347 bss_section
->s_vaddr
= vaddr
;
348 bss_section
->s_paddr
= vaddr
;
349 bss_section
->s_size
= 0;
350 bss_section
->s_scnptr
= scnptr
;
353 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
354 "writing text section to %s", new_name
);
355 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
356 "writing data section to %s", new_name
);
359 #define old_got_section ((struct scnhdr *)buffer)
361 if (got_section
!= NULL
)
363 SEEK (new, old_got_section
->s_scnptr
,
364 "seeking to start of got_section in %s", new_name
);
365 WRITE (new, oldptr
+ old_got_section
->s_scnptr
, old_got_section
->s_size
,
366 "writing new got_section of %s", new_name
);
367 SEEK (new, nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
,
368 "seeking to end of data section of %s", new_name
);
371 #undef old_got_section
375 * Construct new symbol table header
378 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
380 #define symhdr ((pHDRR)buffer)
381 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
382 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
383 nhdr
.fhdr
.f_symptr
= newsyms
;
384 symhdr
->cbLineOffset
+= symrel
;
385 symhdr
->cbDnOffset
+= symrel
;
386 symhdr
->cbPdOffset
+= symrel
;
387 symhdr
->cbSymOffset
+= symrel
;
388 symhdr
->cbOptOffset
+= symrel
;
389 symhdr
->cbAuxOffset
+= symrel
;
390 symhdr
->cbSsOffset
+= symrel
;
391 symhdr
->cbSsExtOffset
+= symrel
;
392 symhdr
->cbFdOffset
+= symrel
;
393 symhdr
->cbRfdOffset
+= symrel
;
394 symhdr
->cbExtOffset
+= symrel
;
396 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
399 * Copy the symbol table and line numbers
401 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
402 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
403 "writing symbol table of %s", new_name
);
407 update_dynamic_symbols (oldptr
, new_name
, new, nhdr
.aout
);
412 SEEK (new, 0, "seeking to start of header in %s", new_name
);
413 WRITE (new, &nhdr
, sizeof (nhdr
),
414 "writing header of %s", new_name
);
423 update_dynamic_symbols (old
, new_name
, new, aout
)
424 char *old
; /* Pointer to old executable */
425 char *new_name
; /* Name of new executable */
426 int new; /* File descriptor for new executable */
427 struct aouthdr aout
; /* a.out info from the file header */
429 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
431 typedef struct dynrel_info
{
439 int nsyms
= rel_dyn_section
->s_size
/ sizeof (struct dynrel_info
);
441 dr_info
* rd_base
= (dr_info
*) (old
+ rel_dyn_section
->s_scnptr
);
442 Elf32_Sym
* ds_base
= (Elf32_Sym
*) (old
+ dynsym_section
->s_scnptr
);
444 for (i
= 0; i
< nsyms
; i
++) {
445 register Elf32_Sym x
;
447 if (rd_base
[i
].index
== 0)
450 x
= ds_base
[rd_base
[i
].index
];
453 fprintf (stderr
, "Object inspected: %s, addr = %lx, shndx = %x",
454 old
+ dynstr_section
->s_scnptr
+ x
.st_name
, rd_base
[i
].addr
, x
.st_shndx
);
458 if ((ELF32_ST_BIND (x
.st_info
) == STB_GLOBAL
)
460 /* && (x.st_value == NULL) */
462 /* OK, this is probably a reference to an object in a shared
463 library, so copy the old value. This is done in several steps:
464 1. reladdr is the address of the location in question relative to
465 the start of the data section,
466 2. oldref is the addr is the mapped in temacs executable,
467 3. newref is the address of the location in question in the
469 4. len is the size of the object reference in bytes --
470 currently only 4 (long) and 8 (quad) are supported.
472 register unsigned long reladdr
= (long)rd_base
[i
].addr
- old_data_scnhdr
.s_vaddr
;
473 char * oldref
= old
+ old_data_scnhdr
.s_scnptr
+ reladdr
;
474 unsigned long newref
= aout
.tsize
+ reladdr
;
478 fprintf (stderr
, "...relocated\n");
481 if (rd_base
[i
].type
== R_REFLONG
)
483 else if (rd_base
[i
].type
== R_REFQUAD
)
486 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", i
);
488 SEEK (new, newref
, "seeking to dynamic symbol in %s", new_name
);
489 WRITE (new, oldref
, len
, "writing old dynrel info in %s", new_name
);
494 fprintf (stderr
, "...not relocated\n");
499 #endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
506 * After successfully building the new a.out, mark it executable
514 int um
= umask (777);
516 if (stat (name
, &sbuf
) < 0)
517 fatal_unexec ("getting protection on %s", name
);
518 sbuf
.st_mode
|= 0111 & ~um
;
519 if (chmod (name
, sbuf
.st_mode
) < 0)
520 fatal_unexec ("setting protection on %s", name
);
524 fatal_unexec (s
, arg
)
529 fputs ("unexec: unexpected end of file, ", stderr
);
531 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
532 fprintf (stderr
, s
, arg
);
533 fputs (".\n", stderr
);