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>
39 static void fatal_unexec ();
40 static void mark_x ();
42 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
44 if (read (_fd, _buffer, _size) != _size) \
45 fatal_unexec (_error_message, _error_arg);
47 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
48 if (write (_fd, _buffer, _size) != _size) \
49 fatal_unexec (_error_message, _error_arg);
51 #define SEEK(_fd, _position, _error_message, _error_arg) \
53 if (lseek (_fd, _position, L_SET) != _position) \
54 fatal_unexec (_error_message, _error_arg);
57 extern char *strerror ();
63 static struct scnhdr
*text_section
;
64 static struct scnhdr
*rel_dyn_section
;
65 static struct scnhdr
*dynstr_section
;
66 static struct scnhdr
*dynsym_section
;
67 static struct scnhdr
*init_section
;
68 static struct scnhdr
*finit_section
;
69 static struct scnhdr
*rdata_section
;
70 static struct scnhdr
*rconst_section
;
71 static struct scnhdr
*data_section
;
72 static struct scnhdr
*pdata_section
;
73 static struct scnhdr
*xdata_section
;
74 static struct scnhdr
*got_section
;
75 static struct scnhdr
*lit8_section
;
76 static struct scnhdr
*lit4_section
;
77 static struct scnhdr
*sdata_section
;
78 static struct scnhdr
*sbss_section
;
79 static struct scnhdr
*bss_section
;
81 static struct scnhdr old_data_scnhdr
;
83 static unsigned long Brk
;
88 struct scnhdr section
[_MIPS_NSCNS_MAX
];
93 /* Define name of label for entry point for the dumped executable. */
95 #ifndef DEFAULT_ENTRY_ADDRESS
96 #define DEFAULT_ENTRY_ADDRESS __start
99 unexec (new_name
, a_name
, data_start
, bss_start
, entry_address
)
100 char *new_name
, *a_name
;
101 unsigned long data_start
, bss_start
, entry_address
;
105 struct headers ohdr
, nhdr
;
108 long newsyms
, symrel
;
113 char buffer
[BUFSIZE
];
115 if ((old
= open (a_name
, O_RDONLY
)) < 0)
116 fatal_unexec ("opening %s", a_name
);
118 new = creat (new_name
, 0666);
119 if (new < 0) fatal_unexec ("creating %s", new_name
);
121 if ((fstat (old
, &stat
) == -1))
122 fatal_unexec ("fstat %s", a_name
);
124 oldptr
= (char *)mmap (0, stat
.st_size
, PROT_READ
, MAP_FILE
|MAP_SHARED
, old
, 0);
126 if (oldptr
== (char *)-1)
127 fatal_unexec ("mmap %s", a_name
);
131 /* This is a copy of the a.out header of the original executable */
133 ohdr
= (*(struct headers
*)oldptr
);
135 /* This is where we build the new header from the in-memory copy */
137 nhdr
= *((struct headers
*)TEXT_START
);
139 /* First do some consistency checks */
141 if (nhdr
.fhdr
.f_magic
!= ALPHAMAGIC
142 && nhdr
.fhdr
.f_magic
!= ALPHAUMAGIC
)
144 fprintf (stderr
, "unexec: input file magic number is %x, not %x or %x.\n",
145 nhdr
.fhdr
.f_magic
, ALPHAMAGIC
, ALPHAUMAGIC
);
149 if (nhdr
.fhdr
.f_opthdr
!= sizeof (nhdr
.aout
))
151 fprintf (stderr
, "unexec: input a.out header is %d bytes, not %d.\n",
152 nhdr
.fhdr
.f_opthdr
, sizeof (nhdr
.aout
));
155 if (nhdr
.aout
.magic
!= ZMAGIC
)
157 fprintf (stderr
, "unexec: input file a.out magic number is %o, not %o.\n",
158 nhdr
.aout
.magic
, ZMAGIC
);
163 /* Now check the existence of certain header section and grab
166 #define CHECK_SCNHDR(ptr, name, flags) \
168 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
169 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
171 if (nhdr.section[i].s_flags != flags) \
172 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
173 nhdr.section[i].s_flags, flags, name); \
174 ptr = nhdr.section + i; \
177 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
178 CHECK_SCNHDR (init_section
, _INIT
, STYP_INIT
);
180 CHECK_SCNHDR (rel_dyn_section
, _REL_DYN
, STYP_REL_DYN
);
181 #endif /* _REL_DYN */
183 CHECK_SCNHDR (dynsym_section
, _DYNSYM
, STYP_DYNSYM
);
184 #endif /* _REL_DYN */
186 CHECK_SCNHDR (dynstr_section
, _DYNSTR
, STYP_DYNSTR
);
187 #endif /* _REL_DYN */
189 CHECK_SCNHDR (finit_section
, _FINI
, STYP_FINI
);
191 CHECK_SCNHDR (rdata_section
, _RDATA
, STYP_RDATA
);
193 CHECK_SCNHDR (rconst_section
, _RCONST
, STYP_RCONST
);
196 CHECK_SCNHDR (pdata_section
, _PDATA
, STYP_PDATA
);
199 CHECK_SCNHDR (got_section
, _GOT
, STYP_GOT
);
201 CHECK_SCNHDR (data_section
, _DATA
, STYP_DATA
);
203 CHECK_SCNHDR (xdata_section
, _XDATA
, STYP_XDATA
);
206 CHECK_SCNHDR (lit8_section
, _LIT8
, STYP_LIT8
);
207 CHECK_SCNHDR (lit4_section
, _LIT4
, STYP_LIT4
);
209 CHECK_SCNHDR (sdata_section
, _SDATA
, STYP_SDATA
);
210 CHECK_SCNHDR (sbss_section
, _SBSS
, STYP_SBSS
);
211 CHECK_SCNHDR (bss_section
, _BSS
, STYP_BSS
);
214 pagesize
= getpagesize ();
215 brk
= (((long) (sbrk (0))) + pagesize
- 1) & (-pagesize
);
217 /* Remember the current break */
221 bcopy (data_section
, &old_data_scnhdr
, sizeof (old_data_scnhdr
));
223 nhdr
.aout
.dsize
= brk
- DATA_START
;
225 if (entry_address
== 0)
227 extern DEFAULT_ENTRY_ADDRESS ();
228 nhdr
.aout
.entry
= (unsigned long)DEFAULT_ENTRY_ADDRESS
;
231 nhdr
.aout
.entry
= entry_address
;
233 nhdr
.aout
.bss_start
= nhdr
.aout
.data_start
+ nhdr
.aout
.dsize
;
235 if (rdata_section
!= NULL
)
237 rdata_section
->s_size
= data_start
- DATA_START
;
239 /* Adjust start and virtual addresses of rdata_section, too. */
240 rdata_section
->s_vaddr
= DATA_START
;
241 rdata_section
->s_paddr
= DATA_START
;
242 rdata_section
->s_scnptr
= text_section
->s_scnptr
+ nhdr
.aout
.tsize
;
245 data_section
->s_vaddr
= data_start
;
246 data_section
->s_paddr
= data_start
;
247 data_section
->s_size
= brk
- data_start
;
249 if (rdata_section
!= NULL
)
251 data_section
->s_scnptr
= rdata_section
->s_scnptr
+ rdata_section
->s_size
;
254 vaddr
= data_section
->s_vaddr
+ data_section
->s_size
;
255 scnptr
= data_section
->s_scnptr
+ data_section
->s_size
;
256 if (lit8_section
!= NULL
)
258 lit8_section
->s_vaddr
= vaddr
;
259 lit8_section
->s_paddr
= vaddr
;
260 lit8_section
->s_size
= 0;
261 lit8_section
->s_scnptr
= scnptr
;
263 if (lit4_section
!= NULL
)
265 lit4_section
->s_vaddr
= vaddr
;
266 lit4_section
->s_paddr
= vaddr
;
267 lit4_section
->s_size
= 0;
268 lit4_section
->s_scnptr
= scnptr
;
270 if (sdata_section
!= NULL
)
272 sdata_section
->s_vaddr
= vaddr
;
273 sdata_section
->s_paddr
= vaddr
;
274 sdata_section
->s_size
= 0;
275 sdata_section
->s_scnptr
= scnptr
;
278 if (xdata_section
!= NULL
)
280 xdata_section
->s_vaddr
= vaddr
;
281 xdata_section
->s_paddr
= vaddr
;
282 xdata_section
->s_size
= 0;
283 xdata_section
->s_scnptr
= scnptr
;
287 if (got_section
!= NULL
)
289 bcopy (got_section
, buffer
, sizeof (struct scnhdr
));
291 got_section
->s_vaddr
= vaddr
;
292 got_section
->s_paddr
= vaddr
;
293 got_section
->s_size
= 0;
294 got_section
->s_scnptr
= scnptr
;
297 if (sbss_section
!= NULL
)
299 sbss_section
->s_vaddr
= vaddr
;
300 sbss_section
->s_paddr
= vaddr
;
301 sbss_section
->s_size
= 0;
302 sbss_section
->s_scnptr
= scnptr
;
304 if (bss_section
!= NULL
)
306 bss_section
->s_vaddr
= vaddr
;
307 bss_section
->s_paddr
= vaddr
;
308 bss_section
->s_size
= 0;
309 bss_section
->s_scnptr
= scnptr
;
312 WRITE (new, (char *)TEXT_START
, nhdr
.aout
.tsize
,
313 "writing text section to %s", new_name
);
314 WRITE (new, (char *)DATA_START
, nhdr
.aout
.dsize
,
315 "writing data section to %s", new_name
);
318 #define old_got_section ((struct scnhdr *)buffer)
320 if (got_section
!= NULL
)
322 SEEK (new, old_got_section
->s_scnptr
,
323 "seeking to start of got_section in %s", new_name
);
324 WRITE (new, oldptr
+ old_got_section
->s_scnptr
, old_got_section
->s_size
,
325 "writing new got_section of %s", new_name
);
326 SEEK (new, nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
,
327 "seeking to end of data section of %s", new_name
);
330 #undef old_got_section
334 * Construct new symbol table header
337 bcopy (oldptr
+ nhdr
.fhdr
.f_symptr
, buffer
, cbHDRR
);
339 #define symhdr ((pHDRR)buffer)
340 newsyms
= nhdr
.aout
.tsize
+ nhdr
.aout
.dsize
;
341 symrel
= newsyms
- nhdr
.fhdr
.f_symptr
;
342 nhdr
.fhdr
.f_symptr
= newsyms
;
343 symhdr
->cbLineOffset
+= symrel
;
344 symhdr
->cbDnOffset
+= symrel
;
345 symhdr
->cbPdOffset
+= symrel
;
346 symhdr
->cbSymOffset
+= symrel
;
347 symhdr
->cbOptOffset
+= symrel
;
348 symhdr
->cbAuxOffset
+= symrel
;
349 symhdr
->cbSsOffset
+= symrel
;
350 symhdr
->cbSsExtOffset
+= symrel
;
351 symhdr
->cbFdOffset
+= symrel
;
352 symhdr
->cbRfdOffset
+= symrel
;
353 symhdr
->cbExtOffset
+= symrel
;
355 WRITE (new, buffer
, cbHDRR
, "writing symbol table header of %s", new_name
);
358 * Copy the symbol table and line numbers
360 WRITE (new, oldptr
+ ohdr
.fhdr
.f_symptr
+ cbHDRR
,
361 stat
.st_size
- ohdr
.fhdr
.f_symptr
- cbHDRR
,
362 "writing symbol table of %s", new_name
);
365 update_dynamic_symbols (oldptr
, new_name
, new, nhdr
.aout
);
370 SEEK (new, 0, "seeking to start of header in %s", new_name
);
371 WRITE (new, &nhdr
, sizeof (nhdr
),
372 "writing header of %s", new_name
);
384 update_dynamic_symbols (old
, new_name
, new, aout
)
385 char *old
; /* Pointer to old executable */
386 char *new_name
; /* Name of new executable */
387 int new; /* File descriptor for new executable */
388 struct aouthdr aout
; /* a.out info from the file header */
390 typedef struct dynrel_info
{
398 int nsyms
= rel_dyn_section
->s_size
/ sizeof (struct dynrel_info
);
400 dr_info
* rd_base
= (dr_info
*) (old
+ rel_dyn_section
->s_scnptr
);
401 Elf32_Sym
* ds_base
= (Elf32_Sym
*) (old
+ dynsym_section
->s_scnptr
);
403 for (i
= 0; i
< nsyms
; i
++) {
404 register Elf32_Sym x
;
406 if (rd_base
[i
].index
== 0)
409 x
= ds_base
[rd_base
[i
].index
];
412 fprintf (stderr
, "Object inspected: %s, addr = %lx, shndx = %x",
413 old
+ dynstr_section
->s_scnptr
+ x
.st_name
, rd_base
[i
].addr
, x
.st_shndx
);
417 if ((ELF32_ST_BIND (x
.st_info
) == STB_GLOBAL
)
419 /* && (x.st_value == NULL) */
421 /* OK, this is probably a reference to an object in a shared
422 library, so copy the old value. This is done in several steps:
423 1. reladdr is the address of the location in question relative to
424 the start of the data section,
425 2. oldref is the addr is the mapped in temacs executable,
426 3. newref is the address of the location in question in the
428 4. len is the size of the object reference in bytes --
429 currently only 4 (long) and 8 (quad) are supported.
431 register unsigned long reladdr
= rd_base
[i
].addr
- old_data_scnhdr
.s_vaddr
;
432 char * oldref
= old
+ old_data_scnhdr
.s_scnptr
+ reladdr
;
433 unsigned long newref
= aout
.tsize
+ reladdr
;
437 fprintf (stderr
, "...relocated\n");
440 if (rd_base
[i
].type
== R_REFLONG
)
442 else if (rd_base
[i
].type
== R_REFQUAD
)
445 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", i
);
447 SEEK (new, newref
, "seeking to dynamic symbol in %s", new_name
);
448 WRITE (new, oldref
, len
, "writing old dynrel info in %s", new_name
);
453 fprintf (stderr
, "...not relocated\n");
460 #endif /* !__linux__ */
466 * After successfully building the new a.out, mark it executable
474 int um
= umask (777);
476 if (stat (name
, &sbuf
) < 0)
477 fatal_unexec ("getting protection on %s", name
);
478 sbuf
.st_mode
|= 0111 & ~um
;
479 if (chmod (name
, sbuf
.st_mode
) < 0)
480 fatal_unexec ("setting protection on %s", name
);
484 fatal_unexec (s
, arg
)
489 fputs ("unexec: unexpected end of file, ", stderr
);
491 fprintf (stderr
, "unexec: %s, ", strerror (errno
));
492 fprintf (stderr
, s
, arg
);
493 fputs (".\n", stderr
);