]>
code.delx.au - gnu-emacs/blob - src/unexalpha.c
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 ();
85 static void mark_x ();
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 /* Define name of label for entry point for the dumped executable. */
141 #ifndef DEFAULT_ENTRY_ADDRESS
142 #define DEFAULT_ENTRY_ADDRESS __start
145 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
146 char *new_name
, *a_name
;
147 unsigned long data_start
, bss_start
, entry_address
;
151 struct headers ohdr
, nhdr
;
154 long newsyms
, symrel
;
159 char buffer
[BUFSIZE
];
161 if ((old
= open (a_name
, O_RDONLY
)) < 0)
162 fatal_unexec ("opening %s", a_name
);
164 new = creat (new_name
, 0666);
165 if (new < 0) fatal_unexec ("creating %s", new_name
);
167 if ((fstat (old
, &stat
) == -1))
168 fatal_unexec ("fstat %s", a_name
);
170 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
172 if (oldptr
== (char *)-1)
173 fatal_unexec ("mmap %s", a_name
);
177 /* This is a copy of the a.out header of the original executable */
179 ohdr
= (*(struct headers
*)oldptr
);
181 /* This is where we build the new header from the in-memory copy */
183 nhdr
= *((struct headers
*)TEXT_START
);
185 /* First do some consistency checks */
187 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
188 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
190 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
191 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
195 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
197 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
198 nhdr
.fhdr
.f_opthdr
, (int)sizeof (nhdr
.aout
));
201 if (nhdr
.aout
.magic
!= ZMAGIC
)
203 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
204 nhdr
.aout
.magic
, ZMAGIC
);
209 /* Now check the existence of certain header section and grab
212 #define CHECK_SCNHDR(ptr, name, flags) \
214 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
215 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
217 if (nhdr.section[i].s_flags != flags) \
218 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
219 nhdr.section[i].s_flags, flags, name); \
220 ptr = nhdr.section + i; \
223 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
224 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
226 CHECK_SCNHDR (rel_dyn_section
, _REL_DYN
, STYP_REL_DYN
);
227 #endif /* _REL_DYN */
229 CHECK_SCNHDR (dynsym_section
, _DYNSYM
, STYP_DYNSYM
);
230 #endif /* _REL_DYN */
232 CHECK_SCNHDR (dynstr_section
, _DYNSTR
, STYP_DYNSTR
);
233 #endif /* _REL_DYN */
235 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
237 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
239 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
242 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
245 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
247 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
249 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
252 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
253 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
255 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
256 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
257 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
260 pagesize
= getpagesize ();
261 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
263 /* Remember the current break */
267 bcopy (data_section
, &old_data_scnhdr
, sizeof (old_data_scnhdr
));
269 nhdr
.aout
.dsize
= brk
- DATA_START
;
271 if (entry_address
== 0)
273 extern DEFAULT_ENTRY_ADDRESS ();
274 nhdr
.aout
.entry
= (unsigned long)DEFAULT_ENTRY_ADDRESS
;
277 nhdr
.aout
.entry
= entry_address
;
279 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
281 if (rdata_section
!= NULL
)
283 rdata_section
->s_size
= data_start
- DATA_START
;
285 /* Adjust start and virtual addresses of rdata_section, too. */
286 rdata_section
->s_vaddr
= DATA_START
;
287 rdata_section
->s_paddr
= DATA_START
;
288 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
291 data_section
->s_vaddr
= data_start
;
292 data_section
->s_paddr
= data_start
;
293 data_section
->s_size
= brk
- data_start
;
295 if (rdata_section
!= NULL
)
297 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
300 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
301 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
302 if (lit8_section
!= NULL
)
304 lit8_section
->s_vaddr
= vaddr
;
305 lit8_section
->s_paddr
= vaddr
;
306 lit8_section
->s_size
= 0;
307 lit8_section
->s_scnptr
= scnptr
;
309 if (lit4_section
!= NULL
)
311 lit4_section
->s_vaddr
= vaddr
;
312 lit4_section
->s_paddr
= vaddr
;
313 lit4_section
->s_size
= 0;
314 lit4_section
->s_scnptr
= scnptr
;
316 if (sdata_section
!= NULL
)
318 sdata_section
->s_vaddr
= vaddr
;
319 sdata_section
->s_paddr
= vaddr
;
320 sdata_section
->s_size
= 0;
321 sdata_section
->s_scnptr
= scnptr
;
324 if (xdata_section
!= NULL
)
326 xdata_section
->s_vaddr
= vaddr
;
327 xdata_section
->s_paddr
= vaddr
;
328 xdata_section
->s_size
= 0;
329 xdata_section
->s_scnptr
= scnptr
;
333 if (got_section
!= NULL
)
335 bcopy (got_section
, buffer
, sizeof (struct scnhdr
));
337 got_section
->s_vaddr
= vaddr
;
338 got_section
->s_paddr
= vaddr
;
339 got_section
->s_size
= 0;
340 got_section
->s_scnptr
= scnptr
;
343 if (sbss_section
!= NULL
)
345 sbss_section
->s_vaddr
= vaddr
;
346 sbss_section
->s_paddr
= vaddr
;
347 sbss_section
->s_size
= 0;
348 sbss_section
->s_scnptr
= scnptr
;
350 if (bss_section
!= NULL
)
352 bss_section
->s_vaddr
= vaddr
;
353 bss_section
->s_paddr
= vaddr
;
354 bss_section
->s_size
= 0;
355 bss_section
->s_scnptr
= scnptr
;
358 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
359 "writing text section to %s", new_name
);
360 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
361 "writing data section to %s", new_name
);
364 #define old_got_section ((struct scnhdr *)buffer)
366 if (got_section
!= NULL
)
368 SEEK (new, old_got_section
->s_scnptr
,
369 "seeking to start of got_section in %s", new_name
);
370 WRITE (new, oldptr
+ old_got_section
->s_scnptr
, old_got_section
->s_size
,
371 "writing new got_section of %s", new_name
);
372 SEEK (new, nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
,
373 "seeking to end of data section of %s", new_name
);
376 #undef old_got_section
380 * Construct new symbol table header
383 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
385 #define symhdr ((pHDRR)buffer)
386 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
387 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
388 nhdr
.fhdr
.f_symptr
= newsyms
;
389 symhdr
->cbLineOffset
+= symrel
;
390 symhdr
->cbDnOffset
+= symrel
;
391 symhdr
->cbPdOffset
+= symrel
;
392 symhdr
->cbSymOffset
+= symrel
;
393 symhdr
->cbOptOffset
+= symrel
;
394 symhdr
->cbAuxOffset
+= symrel
;
395 symhdr
->cbSsOffset
+= symrel
;
396 symhdr
->cbSsExtOffset
+= symrel
;
397 symhdr
->cbFdOffset
+= symrel
;
398 symhdr
->cbRfdOffset
+= symrel
;
399 symhdr
->cbExtOffset
+= symrel
;
401 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
404 * Copy the symbol table and line numbers
406 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
407 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
408 "writing symbol table of %s", new_name
);
412 update_dynamic_symbols (oldptr
, new_name
, new, nhdr
.aout
);
417 SEEK (new, 0, "seeking to start of header in %s", new_name
);
418 WRITE (new, &nhdr
, sizeof (nhdr
),
419 "writing header of %s", new_name
);
428 update_dynamic_symbols (old
, new_name
, new, aout
)
429 char *old
; /* Pointer to old executable */
430 char *new_name
; /* Name of new executable */
431 int new; /* File descriptor for new executable */
432 struct aouthdr aout
; /* a.out info from the file header */
434 #if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
436 typedef struct dynrel_info
{
444 int nsyms
= rel_dyn_section
->s_size
/ sizeof (struct dynrel_info
);
446 dr_info
* rd_base
= (dr_info
*) (old
+ rel_dyn_section
->s_scnptr
);
447 Elf32_Sym
* ds_base
= (Elf32_Sym
*) (old
+ dynsym_section
->s_scnptr
);
449 for (i
= 0; i
< nsyms
; i
++) {
450 register Elf32_Sym x
;
452 if (rd_base
[i
].index
== 0)
455 x
= ds_base
[rd_base
[i
].index
];
458 fprintf (stderr
, "Object inspected: %s, addr = %lx, shndx = %x",
459 old
+ dynstr_section
->s_scnptr
+ x
.st_name
, rd_base
[i
].addr
, x
.st_shndx
);
463 if ((ELF32_ST_BIND (x
.st_info
) == STB_GLOBAL
)
465 /* && (x.st_value == NULL) */
467 /* OK, this is probably a reference to an object in a shared
468 library, so copy the old value. This is done in several steps:
469 1. reladdr is the address of the location in question relative to
470 the start of the data section,
471 2. oldref is the addr is the mapped in temacs executable,
472 3. newref is the address of the location in question in the
474 4. len is the size of the object reference in bytes --
475 currently only 4 (long) and 8 (quad) are supported.
477 register unsigned long reladdr
= (long)rd_base
[i
].addr
- old_data_scnhdr
.s_vaddr
;
478 char * oldref
= old
+ old_data_scnhdr
.s_scnptr
+ reladdr
;
479 unsigned long newref
= aout
.tsize
+ reladdr
;
483 fprintf (stderr
, "...relocated\n");
486 if (rd_base
[i
].type
== R_REFLONG
)
488 else if (rd_base
[i
].type
== R_REFQUAD
)
491 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", i
);
493 SEEK (new, newref
, "seeking to dynamic symbol in %s", new_name
);
494 WRITE (new, oldref
, len
, "writing old dynrel info in %s", new_name
);
499 fprintf (stderr
, "...not relocated\n");
504 #endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
511 * After successfully building the new a.out, mark it executable
519 int um
= umask (777);
521 if (stat (name
, &sbuf
) < 0)
522 fatal_unexec ("getting protection on %s", name
);
523 sbuf
.st_mode
|= 0111 & ~um
;
524 if (chmod (name
, sbuf
.st_mode
) < 0)
525 fatal_unexec ("setting protection on %s", name
);
529 fatal_unexec (s
, arg
)
534 fputs ("unexec: unexpected end of file, ", stderr
);
536 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
537 fprintf (stderr
, s
, arg
);
538 fputs (".\n", stderr
);