1 /* Unexec for DEC alpha.
3 Copyright (C) 1994, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
6 Author: Rainer Schoepf <schoepf@sc.ZIB-Berlin.DE>
8 This file is part of GNU Emacs.
10 GNU Emacs is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 GNU Emacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
25 #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 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
142 char *new_name
, *a_name
;
143 unsigned long data_start
, bss_start
, entry_address
;
147 struct headers ohdr
, nhdr
;
150 long newsyms
, symrel
;
155 char buffer
[BUFSIZE
];
157 if ((old
= open (a_name
, O_RDONLY
)) < 0)
158 fatal_unexec ("opening %s", a_name
);
160 new = creat (new_name
, 0666);
161 if (new < 0) fatal_unexec ("creating %s", new_name
);
163 if ((fstat (old
, &stat
) == -1))
164 fatal_unexec ("fstat %s", a_name
);
166 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
168 if (oldptr
== (char *)-1)
169 fatal_unexec ("mmap %s", a_name
);
173 /* This is a copy of the a.out header of the original executable */
175 ohdr
= (*(struct headers
*)oldptr
);
177 /* This is where we build the new header from the in-memory copy */
179 nhdr
= *((struct headers
*)TEXT_START
);
181 /* First do some consistency checks */
183 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
184 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
186 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
187 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
191 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
193 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
194 nhdr
.fhdr
.f_opthdr
, (int)sizeof (nhdr
.aout
));
197 if (nhdr
.aout
.magic
!= ZMAGIC
)
199 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
200 nhdr
.aout
.magic
, ZMAGIC
);
205 /* Now check the existence of certain header section and grab
208 #define CHECK_SCNHDR(ptr, name, flags) \
210 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
211 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
213 if (nhdr.section[i].s_flags != flags) \
214 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
215 nhdr.section[i].s_flags, flags, name); \
216 ptr = nhdr.section + i; \
219 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
220 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
222 CHECK_SCNHDR (rel_dyn_section
, _REL_DYN
, STYP_REL_DYN
);
223 #endif /* _REL_DYN */
225 CHECK_SCNHDR (dynsym_section
, _DYNSYM
, STYP_DYNSYM
);
226 #endif /* _REL_DYN */
228 CHECK_SCNHDR (dynstr_section
, _DYNSTR
, STYP_DYNSTR
);
229 #endif /* _REL_DYN */
231 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
233 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
235 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
238 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
241 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
243 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
245 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
248 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
249 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
251 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
252 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
253 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
256 pagesize
= getpagesize ();
257 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
259 /* Remember the current break */
263 bcopy (data_section
, &old_data_scnhdr
, sizeof (old_data_scnhdr
));
265 nhdr
.aout
.dsize
= brk
- DATA_START
;
267 if (entry_address
== 0)
270 nhdr
.aout
.entry
= (unsigned long)__start
;
273 nhdr
.aout
.entry
= entry_address
;
275 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
277 if (rdata_section
!= NULL
)
279 rdata_section
->s_size
= data_start
- DATA_START
;
281 /* Adjust start and virtual addresses of rdata_section, too. */
282 rdata_section
->s_vaddr
= DATA_START
;
283 rdata_section
->s_paddr
= DATA_START
;
284 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
287 data_section
->s_vaddr
= data_start
;
288 data_section
->s_paddr
= data_start
;
289 data_section
->s_size
= brk
- data_start
;
291 if (rdata_section
!= NULL
)
293 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
296 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
297 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
298 if (lit8_section
!= NULL
)
300 lit8_section
->s_vaddr
= vaddr
;
301 lit8_section
->s_paddr
= vaddr
;
302 lit8_section
->s_size
= 0;
303 lit8_section
->s_scnptr
= scnptr
;
305 if (lit4_section
!= NULL
)
307 lit4_section
->s_vaddr
= vaddr
;
308 lit4_section
->s_paddr
= vaddr
;
309 lit4_section
->s_size
= 0;
310 lit4_section
->s_scnptr
= scnptr
;
312 if (sdata_section
!= NULL
)
314 sdata_section
->s_vaddr
= vaddr
;
315 sdata_section
->s_paddr
= vaddr
;
316 sdata_section
->s_size
= 0;
317 sdata_section
->s_scnptr
= scnptr
;
320 if (xdata_section
!= NULL
)
322 xdata_section
->s_vaddr
= vaddr
;
323 xdata_section
->s_paddr
= vaddr
;
324 xdata_section
->s_size
= 0;
325 xdata_section
->s_scnptr
= scnptr
;
329 if (got_section
!= NULL
)
331 bcopy (got_section
, buffer
, sizeof (struct scnhdr
));
333 got_section
->s_vaddr
= vaddr
;
334 got_section
->s_paddr
= vaddr
;
335 got_section
->s_size
= 0;
336 got_section
->s_scnptr
= scnptr
;
339 if (sbss_section
!= NULL
)
341 sbss_section
->s_vaddr
= vaddr
;
342 sbss_section
->s_paddr
= vaddr
;
343 sbss_section
->s_size
= 0;
344 sbss_section
->s_scnptr
= scnptr
;
346 if (bss_section
!= NULL
)
348 bss_section
->s_vaddr
= vaddr
;
349 bss_section
->s_paddr
= vaddr
;
350 bss_section
->s_size
= 0;
351 bss_section
->s_scnptr
= scnptr
;
354 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
355 "writing text section to %s", new_name
);
356 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
357 "writing data section to %s", new_name
);
360 #define old_got_section ((struct scnhdr *)buffer)
362 if (got_section
!= NULL
)
364 SEEK (new, old_got_section
->s_scnptr
,
365 "seeking to start of got_section in %s", new_name
);
366 WRITE (new, oldptr
+ old_got_section
->s_scnptr
, old_got_section
->s_size
,
367 "writing new got_section of %s", new_name
);
368 SEEK (new, nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
,
369 "seeking to end of data section of %s", new_name
);
372 #undef old_got_section
376 * Construct new symbol table header
379 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
381 #define symhdr ((pHDRR)buffer)
382 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
383 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
384 nhdr
.fhdr
.f_symptr
= newsyms
;
385 symhdr
->cbLineOffset
+= symrel
;
386 symhdr
->cbDnOffset
+= symrel
;
387 symhdr
->cbPdOffset
+= symrel
;
388 symhdr
->cbSymOffset
+= symrel
;
389 symhdr
->cbOptOffset
+= symrel
;
390 symhdr
->cbAuxOffset
+= symrel
;
391 symhdr
->cbSsOffset
+= symrel
;
392 symhdr
->cbSsExtOffset
+= symrel
;
393 symhdr
->cbFdOffset
+= symrel
;
394 symhdr
->cbRfdOffset
+= symrel
;
395 symhdr
->cbExtOffset
+= symrel
;
397 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
400 * Copy the symbol table and line numbers
402 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
403 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
404 "writing symbol table of %s", new_name
);
408 update_dynamic_symbols (oldptr
, new_name
, new, nhdr
.aout
);
413 SEEK (new, 0, "seeking to start of header in %s", new_name
);
414 WRITE (new, &nhdr
, sizeof (nhdr
),
415 "writing header of %s", new_name
);
424 update_dynamic_symbols (old
, new_name
, new, aout
)
425 char *old
; /* Pointer to old executable */
426 char *new_name
; /* Name of new executable */
427 int new; /* File descriptor for new executable */
428 struct aouthdr aout
; /* a.out info from the file header */
430 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
432 typedef struct dynrel_info
{
440 int nsyms
= rel_dyn_section
->s_size
/ sizeof (struct dynrel_info
);
442 dr_info
* rd_base
= (dr_info
*) (old
+ rel_dyn_section
->s_scnptr
);
443 Elf32_Sym
* ds_base
= (Elf32_Sym
*) (old
+ dynsym_section
->s_scnptr
);
445 for (i
= 0; i
< nsyms
; i
++) {
446 register Elf32_Sym x
;
448 if (rd_base
[i
].index
== 0)
451 x
= ds_base
[rd_base
[i
].index
];
454 fprintf (stderr
, "Object inspected: %s, addr = %lx, shndx = %x",
455 old
+ dynstr_section
->s_scnptr
+ x
.st_name
, rd_base
[i
].addr
, x
.st_shndx
);
459 if ((ELF32_ST_BIND (x
.st_info
) == STB_GLOBAL
)
461 /* && (x.st_value == NULL) */
463 /* OK, this is probably a reference to an object in a shared
464 library, so copy the old value. This is done in several steps:
465 1. reladdr is the address of the location in question relative to
466 the start of the data section,
467 2. oldref is the addr is the mapped in temacs executable,
468 3. newref is the address of the location in question in the
470 4. len is the size of the object reference in bytes --
471 currently only 4 (long) and 8 (quad) are supported.
473 register unsigned long reladdr
= (long)rd_base
[i
].addr
- old_data_scnhdr
.s_vaddr
;
474 char * oldref
= old
+ old_data_scnhdr
.s_scnptr
+ reladdr
;
475 unsigned long newref
= aout
.tsize
+ reladdr
;
479 fprintf (stderr
, "...relocated\n");
482 if (rd_base
[i
].type
== R_REFLONG
)
484 else if (rd_base
[i
].type
== R_REFQUAD
)
487 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i
);
489 SEEK (new, newref
, "seeking to dynamic symbol in %s", new_name
);
490 WRITE (new, oldref
, len
, "writing old dynrel info in %s", new_name
);
495 fprintf (stderr
, "...not relocated\n");
500 #endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
507 * After successfully building the new a.out, mark it executable
515 int um
= umask (777);
517 if (stat (name
, &sbuf
) < 0)
518 fatal_unexec ("getting protection on %s", name
);
519 sbuf
.st_mode
|= 0111 & ~um
;
520 if (chmod (name
, sbuf
.st_mode
) < 0)
521 fatal_unexec ("setting protection on %s", name
);
525 fatal_unexec (s
, arg
)
530 fputs ("unexec: unexpected end of file, ", stderr
);
532 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
533 fprintf (stderr
, s
, arg
);
534 fputs (".\n", stderr
);
538 /* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd
539 (do not change this comment) */