]> code.delx.au - gnu-emacs/blob - src/unexalpha.c
(map_char_table): New arg SUBTABLE. Callers changed.
[gnu-emacs] / src / unexalpha.c
1 /* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
2
3 Copyright (C) 1994 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
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)
10 any later version.
11
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.
16
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. */
21
22 \f
23 #include <config.h>
24 #include <sys/types.h>
25 #include <sys/file.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <stdio.h>
29 #include <varargs.h>
30 #include <filehdr.h>
31 #include <aouthdr.h>
32 #include <scnhdr.h>
33 #include <syms.h>
34 #ifndef __linux__
35 # include <reloc.h>
36 # include <elf_abi.h>
37 #endif
38
39 static void fatal_unexec ();
40 static void mark_x ();
41
42 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
43 errno = EEOF; \
44 if (read (_fd, _buffer, _size) != _size) \
45 fatal_unexec (_error_message, _error_arg);
46
47 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
48 if (write (_fd, _buffer, _size) != _size) \
49 fatal_unexec (_error_message, _error_arg);
50
51 #define SEEK(_fd, _position, _error_message, _error_arg) \
52 errno = EEOF; \
53 if (lseek (_fd, _position, L_SET) != _position) \
54 fatal_unexec (_error_message, _error_arg);
55
56 extern int errno;
57 extern char *strerror ();
58
59 void *sbrk ();
60
61 #define EEOF -1
62
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;
80
81 static struct scnhdr old_data_scnhdr;
82
83 static unsigned long Brk;
84
85 struct headers {
86 struct filehdr fhdr;
87 struct aouthdr aout;
88 struct scnhdr section[_MIPS_NSCNS_MAX];
89 };
90
91
92
93 /* Define name of label for entry point for the dumped executable. */
94
95 #ifndef DEFAULT_ENTRY_ADDRESS
96 #define DEFAULT_ENTRY_ADDRESS __start
97 #endif
98 \f
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;
102 {
103 int new, old;
104 char * oldptr;
105 struct headers ohdr, nhdr;
106 struct stat stat;
107 long pagesize, brk;
108 long newsyms, symrel;
109 int nread;
110 int i;
111 long vaddr, scnptr;
112 #define BUFSIZE 8192
113 char buffer[BUFSIZE];
114
115 if ((old = open (a_name, O_RDONLY)) < 0)
116 fatal_unexec ("opening %s", a_name);
117
118 new = creat (new_name, 0666);
119 if (new < 0) fatal_unexec ("creating %s", new_name);
120
121 if ((fstat (old, &stat) == -1))
122 fatal_unexec ("fstat %s", a_name);
123
124 oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0);
125
126 if (oldptr == (char *)-1)
127 fatal_unexec ("mmap %s", a_name);
128
129 close (old);
130
131 /* This is a copy of the a.out header of the original executable */
132
133 ohdr = (*(struct headers *)oldptr);
134
135 /* This is where we build the new header from the in-memory copy */
136
137 nhdr = *((struct headers *)TEXT_START);
138
139 /* First do some consistency checks */
140
141 if (nhdr.fhdr.f_magic != ALPHAMAGIC
142 && nhdr.fhdr.f_magic != ALPHAUMAGIC)
143 {
144 fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
145 nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC);
146 exit (1);
147 }
148
149 if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
150 {
151 fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
152 nhdr.fhdr.f_opthdr, sizeof (nhdr.aout));
153 exit (1);
154 }
155 if (nhdr.aout.magic != ZMAGIC)
156 {
157 fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
158 nhdr.aout.magic, ZMAGIC);
159 exit (1);
160 }
161
162
163 /* Now check the existence of certain header section and grab
164 their addresses. */
165
166 #define CHECK_SCNHDR(ptr, name, flags) \
167 ptr = NULL; \
168 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
169 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
170 { \
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; \
175 } \
176
177 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
178 CHECK_SCNHDR (init_section, _INIT, STYP_INIT);
179 #ifdef _REL_DYN
180 CHECK_SCNHDR (rel_dyn_section, _REL_DYN, STYP_REL_DYN);
181 #endif /* _REL_DYN */
182 #ifdef _DYNSYM
183 CHECK_SCNHDR (dynsym_section, _DYNSYM, STYP_DYNSYM);
184 #endif /* _REL_DYN */
185 #ifdef _DYNSTR
186 CHECK_SCNHDR (dynstr_section, _DYNSTR, STYP_DYNSTR);
187 #endif /* _REL_DYN */
188 #ifdef _FINI
189 CHECK_SCNHDR (finit_section, _FINI, STYP_FINI);
190 #endif /* _FINI */
191 CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
192 #ifdef _RCONST
193 CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST);
194 #endif
195 #ifdef _PDATA
196 CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
197 #endif _PDATA
198 #ifdef _GOT
199 CHECK_SCNHDR (got_section, _GOT, STYP_GOT);
200 #endif _GOT
201 CHECK_SCNHDR (data_section, _DATA, STYP_DATA);
202 #ifdef _XDATA
203 CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
204 #endif /* _XDATA */
205 #ifdef _LIT8
206 CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8);
207 CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4);
208 #endif /* _LIT8 */
209 CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
210 CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS);
211 CHECK_SCNHDR (bss_section, _BSS, STYP_BSS);
212
213
214 pagesize = getpagesize ();
215 brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
216
217 /* Remember the current break */
218
219 Brk = brk;
220
221 bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
222
223 nhdr.aout.dsize = brk - DATA_START;
224 nhdr.aout.bsize = 0;
225 if (entry_address == 0)
226 {
227 extern DEFAULT_ENTRY_ADDRESS ();
228 nhdr.aout.entry = (unsigned long)DEFAULT_ENTRY_ADDRESS;
229 }
230 else
231 nhdr.aout.entry = entry_address;
232
233 nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize;
234
235 if (rdata_section != NULL)
236 {
237 rdata_section->s_size = data_start - DATA_START;
238
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;
243 }
244
245 data_section->s_vaddr = data_start;
246 data_section->s_paddr = data_start;
247 data_section->s_size = brk - data_start;
248
249 if (rdata_section != NULL)
250 {
251 data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
252 }
253
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)
257 {
258 lit8_section->s_vaddr = vaddr;
259 lit8_section->s_paddr = vaddr;
260 lit8_section->s_size = 0;
261 lit8_section->s_scnptr = scnptr;
262 }
263 if (lit4_section != NULL)
264 {
265 lit4_section->s_vaddr = vaddr;
266 lit4_section->s_paddr = vaddr;
267 lit4_section->s_size = 0;
268 lit4_section->s_scnptr = scnptr;
269 }
270 if (sdata_section != NULL)
271 {
272 sdata_section->s_vaddr = vaddr;
273 sdata_section->s_paddr = vaddr;
274 sdata_section->s_size = 0;
275 sdata_section->s_scnptr = scnptr;
276 }
277 #ifdef _XDATA
278 if (xdata_section != NULL)
279 {
280 xdata_section->s_vaddr = vaddr;
281 xdata_section->s_paddr = vaddr;
282 xdata_section->s_size = 0;
283 xdata_section->s_scnptr = scnptr;
284 }
285 #endif
286 #ifdef _GOT
287 if (got_section != NULL)
288 {
289 bcopy (got_section, buffer, sizeof (struct scnhdr));
290
291 got_section->s_vaddr = vaddr;
292 got_section->s_paddr = vaddr;
293 got_section->s_size = 0;
294 got_section->s_scnptr = scnptr;
295 }
296 #endif /*_GOT */
297 if (sbss_section != NULL)
298 {
299 sbss_section->s_vaddr = vaddr;
300 sbss_section->s_paddr = vaddr;
301 sbss_section->s_size = 0;
302 sbss_section->s_scnptr = scnptr;
303 }
304 if (bss_section != NULL)
305 {
306 bss_section->s_vaddr = vaddr;
307 bss_section->s_paddr = vaddr;
308 bss_section->s_size = 0;
309 bss_section->s_scnptr = scnptr;
310 }
311
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);
316
317 #ifdef _GOT
318 #define old_got_section ((struct scnhdr *)buffer)
319
320 if (got_section != NULL)
321 {
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);
328 }
329
330 #undef old_got_section
331 #endif
332
333 /*
334 * Construct new symbol table header
335 */
336
337 bcopy (oldptr + nhdr.fhdr.f_symptr, buffer, cbHDRR);
338
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;
354
355 WRITE (new, buffer, cbHDRR, "writing symbol table header of %s", new_name);
356
357 /*
358 * Copy the symbol table and line numbers
359 */
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);
363
364 #ifndef __linux__
365 update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
366 #endif
367
368 #undef symhdr
369
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);
373
374 close (old);
375 close (new);
376 mark_x (new_name);
377 }
378
379
380
381
382 #ifndef __linux__
383
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 */
389 {
390 typedef struct dynrel_info {
391 char * addr;
392 unsigned type:8;
393 unsigned index:24;
394 unsigned info:8;
395 unsigned pad:8;
396 } dr_info;
397
398 int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info);
399 int i;
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);
402
403 for (i = 0; i < nsyms; i++) {
404 register Elf32_Sym x;
405
406 if (rd_base[i].index == 0)
407 continue;
408
409 x = ds_base[rd_base[i].index];
410
411 #if 0
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);
414 #endif
415
416
417 if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL)
418 && (x.st_shndx == 0)
419 /* && (x.st_value == NULL) */
420 ) {
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
427 undumped executable,
428 4. len is the size of the object reference in bytes --
429 currently only 4 (long) and 8 (quad) are supported.
430 */
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;
434 int len;
435
436 #if 0
437 fprintf (stderr, "...relocated\n");
438 #endif
439
440 if (rd_base[i].type == R_REFLONG)
441 len = 4;
442 else if (rd_base[i].type == R_REFQUAD)
443 len = 8;
444 else
445 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", i);
446
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);
449 }
450
451 #if 0
452 else
453 fprintf (stderr, "...not relocated\n");
454 #endif
455
456 }
457
458 }
459
460 #endif /* !__linux__ */
461
462 \f
463 /*
464 * mark_x
465 *
466 * After successfully building the new a.out, mark it executable
467 */
468
469 static void
470 mark_x (name)
471 char *name;
472 {
473 struct stat sbuf;
474 int um = umask (777);
475 umask (um);
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);
481 }
482
483 static void
484 fatal_unexec (s, arg)
485 char *s;
486 char *arg;
487 {
488 if (errno == EEOF)
489 fputs ("unexec: unexpected end of file, ", stderr);
490 else
491 fprintf (stderr, "unexec: %s, ", strerror (errno));
492 fprintf (stderr, s, arg);
493 fputs (".\n", stderr);
494 exit (1);
495 }