1 /* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
3 Copyright (C) 1994, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
23 #include <sys/types.h>
32 #if !defined (__NetBSD__) && !defined (__OpenBSD__)
41 #else /* __NetBSD__ or __OpenBSD__ */
43 * NetBSD/Alpha does not have 'normal' user-land ECOFF support because
44 * there's no desire to support ECOFF as the executable format in the
47 #include <sys/exec_ecoff.h>
49 /* Structures, constants, etc., that NetBSD defines strangely. */
50 #define filehdr ecoff_filehdr
51 #define aouthdr ecoff_aouthdr
52 #define scnhdr ecoff_scnhdr
53 #define HDRR struct ecoff_symhdr
55 #define cbHDRR sizeof(HDRR)
57 #define ALPHAMAGIC ECOFF_MAGIC_NATIVE_ALPHA
59 #define ALPHAMAGIC ECOFF_MAGIC_NETBSD_ALPHA
61 #define ZMAGIC ECOFF_ZMAGIC
63 /* Misc. constants that NetBSD doesn't define at all. */
64 #define ALPHAUMAGIC 0617
65 #define _MIPS_NSCNS_MAX 35
66 #define STYP_TEXT 0x00000020
67 #define STYP_DATA 0x00000040
68 #define STYP_BSS 0x00000080
69 #define STYP_RDATA 0x00000100
70 #define STYP_SDATA 0x00000200
71 #define STYP_SBSS 0x00000400
72 #define STYP_INIT 0x80000000
77 #define _RDATA ".rdata"
78 #define _SDATA ".sdata"
80 #endif /* __NetBSD__ || __OpenBSD__ */
82 static void fatal_unexec
__P ((char *, char *));
83 static void mark_x
__P ((char *));
85 static void update_dynamic_symbols
__P ((char *, char *, int, struct aouthdr
));
87 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
89 if (read (_fd, _buffer, _size) != _size) \
90 fatal_unexec (_error_message, _error_arg);
92 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
93 if (write (_fd, _buffer, _size) != _size) \
94 fatal_unexec (_error_message, _error_arg);
96 #define SEEK(_fd, _position, _error_message, _error_arg) \
98 if (lseek (_fd, _position, L_SET) != _position) \
99 fatal_unexec (_error_message, _error_arg);
109 static struct scnhdr
*text_section
;
110 static struct scnhdr
*rel_dyn_section
;
111 static struct scnhdr
*dynstr_section
;
112 static struct scnhdr
*dynsym_section
;
113 static struct scnhdr
*init_section
;
114 static struct scnhdr
*finit_section
;
115 static struct scnhdr
*rdata_section
;
116 static struct scnhdr
*rconst_section
;
117 static struct scnhdr
*data_section
;
118 static struct scnhdr
*pdata_section
;
119 static struct scnhdr
*xdata_section
;
120 static struct scnhdr
*got_section
;
121 static struct scnhdr
*lit8_section
;
122 static struct scnhdr
*lit4_section
;
123 static struct scnhdr
*sdata_section
;
124 static struct scnhdr
*sbss_section
;
125 static struct scnhdr
*bss_section
;
127 static struct scnhdr old_data_scnhdr
;
129 static unsigned long Brk
;
134 struct scnhdr section
[_MIPS_NSCNS_MAX
];
139 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
140 char *new_name
, *a_name
;
141 unsigned long data_start
, bss_start
, entry_address
;
145 struct headers ohdr
, nhdr
;
148 long newsyms
, symrel
;
153 char buffer
[BUFSIZE
];
155 if ((old
= open (a_name
, O_RDONLY
)) < 0)
156 fatal_unexec ("opening %s", a_name
);
158 new = creat (new_name
, 0666);
159 if (new < 0) fatal_unexec ("creating %s", new_name
);
161 if ((fstat (old
, &stat
) == -1))
162 fatal_unexec ("fstat %s", a_name
);
164 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
166 if (oldptr
== (char *)-1)
167 fatal_unexec ("mmap %s", a_name
);
171 /* This is a copy of the a.out header of the original executable */
173 ohdr
= (*(struct headers
*)oldptr
);
175 /* This is where we build the new header from the in-memory copy */
177 nhdr
= *((struct headers
*)TEXT_START
);
179 /* First do some consistency checks */
181 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
182 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
184 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
185 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
189 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
191 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
192 nhdr
.fhdr
.f_opthdr
, (int)sizeof (nhdr
.aout
));
195 if (nhdr
.aout
.magic
!= ZMAGIC
)
197 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
198 nhdr
.aout
.magic
, ZMAGIC
);
203 /* Now check the existence of certain header section and grab
206 #define CHECK_SCNHDR(ptr, name, flags) \
208 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
209 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
211 if (nhdr.section[i].s_flags != flags) \
212 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
213 nhdr.section[i].s_flags, flags, name); \
214 ptr = nhdr.section + i; \
217 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
218 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
220 CHECK_SCNHDR (rel_dyn_section
, _REL_DYN
, STYP_REL_DYN
);
221 #endif /* _REL_DYN */
223 CHECK_SCNHDR (dynsym_section
, _DYNSYM
, STYP_DYNSYM
);
224 #endif /* _REL_DYN */
226 CHECK_SCNHDR (dynstr_section
, _DYNSTR
, STYP_DYNSTR
);
227 #endif /* _REL_DYN */
229 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
231 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
233 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
236 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
239 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
241 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
243 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
246 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
247 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
249 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
250 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
251 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
254 pagesize
= getpagesize ();
255 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
257 /* Remember the current break */
261 bcopy (data_section
, &old_data_scnhdr
, sizeof (old_data_scnhdr
));
263 nhdr
.aout
.dsize
= brk
- DATA_START
;
265 if (entry_address
== 0)
268 nhdr
.aout
.entry
= (unsigned long)__start
;
271 nhdr
.aout
.entry
= entry_address
;
273 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
275 if (rdata_section
!= NULL
)
277 rdata_section
->s_size
= data_start
- DATA_START
;
279 /* Adjust start and virtual addresses of rdata_section, too. */
280 rdata_section
->s_vaddr
= DATA_START
;
281 rdata_section
->s_paddr
= DATA_START
;
282 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
285 data_section
->s_vaddr
= data_start
;
286 data_section
->s_paddr
= data_start
;
287 data_section
->s_size
= brk
- data_start
;
289 if (rdata_section
!= NULL
)
291 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
294 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
295 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
296 if (lit8_section
!= NULL
)
298 lit8_section
->s_vaddr
= vaddr
;
299 lit8_section
->s_paddr
= vaddr
;
300 lit8_section
->s_size
= 0;
301 lit8_section
->s_scnptr
= scnptr
;
303 if (lit4_section
!= NULL
)
305 lit4_section
->s_vaddr
= vaddr
;
306 lit4_section
->s_paddr
= vaddr
;
307 lit4_section
->s_size
= 0;
308 lit4_section
->s_scnptr
= scnptr
;
310 if (sdata_section
!= NULL
)
312 sdata_section
->s_vaddr
= vaddr
;
313 sdata_section
->s_paddr
= vaddr
;
314 sdata_section
->s_size
= 0;
315 sdata_section
->s_scnptr
= scnptr
;
318 if (xdata_section
!= NULL
)
320 xdata_section
->s_vaddr
= vaddr
;
321 xdata_section
->s_paddr
= vaddr
;
322 xdata_section
->s_size
= 0;
323 xdata_section
->s_scnptr
= scnptr
;
327 if (got_section
!= NULL
)
329 bcopy (got_section
, buffer
, sizeof (struct scnhdr
));
331 got_section
->s_vaddr
= vaddr
;
332 got_section
->s_paddr
= vaddr
;
333 got_section
->s_size
= 0;
334 got_section
->s_scnptr
= scnptr
;
337 if (sbss_section
!= NULL
)
339 sbss_section
->s_vaddr
= vaddr
;
340 sbss_section
->s_paddr
= vaddr
;
341 sbss_section
->s_size
= 0;
342 sbss_section
->s_scnptr
= scnptr
;
344 if (bss_section
!= NULL
)
346 bss_section
->s_vaddr
= vaddr
;
347 bss_section
->s_paddr
= vaddr
;
348 bss_section
->s_size
= 0;
349 bss_section
->s_scnptr
= scnptr
;
352 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
353 "writing text section to %s", new_name
);
354 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
355 "writing data section to %s", new_name
);
358 #define old_got_section ((struct scnhdr *)buffer)
360 if (got_section
!= NULL
)
362 SEEK (new, old_got_section
->s_scnptr
,
363 "seeking to start of got_section in %s", new_name
);
364 WRITE (new, oldptr
+ old_got_section
->s_scnptr
, old_got_section
->s_size
,
365 "writing new got_section of %s", new_name
);
366 SEEK (new, nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
,
367 "seeking to end of data section of %s", new_name
);
370 #undef old_got_section
374 * Construct new symbol table header
377 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
379 #define symhdr ((pHDRR)buffer)
380 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
381 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
382 nhdr
.fhdr
.f_symptr
= newsyms
;
383 symhdr
->cbLineOffset
+= symrel
;
384 symhdr
->cbDnOffset
+= symrel
;
385 symhdr
->cbPdOffset
+= symrel
;
386 symhdr
->cbSymOffset
+= symrel
;
387 symhdr
->cbOptOffset
+= symrel
;
388 symhdr
->cbAuxOffset
+= symrel
;
389 symhdr
->cbSsOffset
+= symrel
;
390 symhdr
->cbSsExtOffset
+= symrel
;
391 symhdr
->cbFdOffset
+= symrel
;
392 symhdr
->cbRfdOffset
+= symrel
;
393 symhdr
->cbExtOffset
+= symrel
;
395 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
398 * Copy the symbol table and line numbers
400 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
401 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
402 "writing symbol table of %s", new_name
);
406 update_dynamic_symbols (oldptr
, new_name
, new, nhdr
.aout
);
411 SEEK (new, 0, "seeking to start of header in %s", new_name
);
412 WRITE (new, &nhdr
, sizeof (nhdr
),
413 "writing header of %s", new_name
);
422 update_dynamic_symbols (old
, new_name
, new, aout
)
423 char *old
; /* Pointer to old executable */
424 char *new_name
; /* Name of new executable */
425 int new; /* File descriptor for new executable */
426 struct aouthdr aout
; /* a.out info from the file header */
428 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
430 typedef struct dynrel_info
{
438 int nsyms
= rel_dyn_section
->s_size
/ sizeof (struct dynrel_info
);
440 dr_info
* rd_base
= (dr_info
*) (old
+ rel_dyn_section
->s_scnptr
);
441 Elf32_Sym
* ds_base
= (Elf32_Sym
*) (old
+ dynsym_section
->s_scnptr
);
443 for (i
= 0; i
< nsyms
; i
++) {
444 register Elf32_Sym x
;
446 if (rd_base
[i
].index
== 0)
449 x
= ds_base
[rd_base
[i
].index
];
452 fprintf (stderr
, "Object inspected: %s, addr = %lx, shndx = %x",
453 old
+ dynstr_section
->s_scnptr
+ x
.st_name
, rd_base
[i
].addr
, x
.st_shndx
);
457 if ((ELF32_ST_BIND (x
.st_info
) == STB_GLOBAL
)
459 /* && (x.st_value == NULL) */
461 /* OK, this is probably a reference to an object in a shared
462 library, so copy the old value. This is done in several steps:
463 1. reladdr is the address of the location in question relative to
464 the start of the data section,
465 2. oldref is the addr is the mapped in temacs executable,
466 3. newref is the address of the location in question in the
468 4. len is the size of the object reference in bytes --
469 currently only 4 (long) and 8 (quad) are supported.
471 register unsigned long reladdr
= (long)rd_base
[i
].addr
- old_data_scnhdr
.s_vaddr
;
472 char * oldref
= old
+ old_data_scnhdr
.s_scnptr
+ reladdr
;
473 unsigned long newref
= aout
.tsize
+ reladdr
;
477 fprintf (stderr
, "...relocated\n");
480 if (rd_base
[i
].type
== R_REFLONG
)
482 else if (rd_base
[i
].type
== R_REFQUAD
)
485 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i
);
487 SEEK (new, newref
, "seeking to dynamic symbol in %s", new_name
);
488 WRITE (new, oldref
, len
, "writing old dynrel info in %s", new_name
);
493 fprintf (stderr
, "...not relocated\n");
498 #endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
505 * After successfully building the new a.out, mark it executable
513 int um
= umask (777);
515 if (stat (name
, &sbuf
) < 0)
516 fatal_unexec ("getting protection on %s", name
);
517 sbuf
.st_mode
|= 0111 & ~um
;
518 if (chmod (name
, sbuf
.st_mode
) < 0)
519 fatal_unexec ("setting protection on %s", name
);
523 fatal_unexec (s
, arg
)
528 fputs ("unexec: unexpected end of file, ", stderr
);
530 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
531 fprintf (stderr
, s
, arg
);
532 fputs (".\n", stderr
);
536 /* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd
537 (do not change this comment) */