Add arch taglines
[bpt/emacs.git] / src / unexalpha.c
CommitLineData
b061d5f1
RS
1/* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
2
20fd0b4f 3 Copyright (C) 1994, 2000 Free Software Foundation, Inc.
b061d5f1
RS
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
b061d5f1
RS
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>
20fd0b4f
DL
30#include <errno.h>
31#ifdef HAVE_STRING_H
32#include <string.h>
33#endif
61e63089 34#if !defined (__NetBSD__) && !defined (__OpenBSD__)
b061d5f1
RS
35#include <filehdr.h>
36#include <aouthdr.h>
37#include <scnhdr.h>
38#include <syms.h>
d7b43eaa
RS
39#ifndef __linux__
40# include <reloc.h>
41# include <elf_abi.h>
42#endif
61e63089 43#else /* __NetBSD__ or __OpenBSD__ */
6538ee2e
RS
44/*
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
47 * long term.
48 */
49#include <sys/exec_ecoff.h>
50
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
56#define pHDRR HDRR *
57#define cbHDRR sizeof(HDRR)
61e63089
RS
58#ifdef __OpenBSD__
59#define ALPHAMAGIC ECOFF_MAGIC_NATIVE_ALPHA
60#else
6538ee2e 61#define ALPHAMAGIC ECOFF_MAGIC_NETBSD_ALPHA
61e63089 62#endif
6538ee2e
RS
63#define ZMAGIC ECOFF_ZMAGIC
64
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
75#define _TEXT ".text"
76#define _DATA ".data"
77#define _BSS ".bss"
78#define _INIT ".init"
79#define _RDATA ".rdata"
80#define _SDATA ".sdata"
81#define _SBSS ".sbss"
61e63089 82#endif /* __NetBSD__ || __OpenBSD__ */
b061d5f1 83
3fb21e7a
DL
84static void fatal_unexec __P ((char *, char *));
85static void mark_x __P ((char *));
86
87static void update_dynamic_symbols __P ((char *, char *, int, struct aouthdr));
b061d5f1
RS
88
89#define READ(_fd, _buffer, _size, _error_message, _error_arg) \
90 errno = EEOF; \
91 if (read (_fd, _buffer, _size) != _size) \
92 fatal_unexec (_error_message, _error_arg);
93
94#define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
95 if (write (_fd, _buffer, _size) != _size) \
96 fatal_unexec (_error_message, _error_arg);
97
98#define SEEK(_fd, _position, _error_message, _error_arg) \
99 errno = EEOF; \
100 if (lseek (_fd, _position, L_SET) != _position) \
101 fatal_unexec (_error_message, _error_arg);
102
20fd0b4f
DL
103#ifdef HAVE_UNISTD_H
104#include <unistd.h>
105#else
d7b43eaa 106void *sbrk ();
20fd0b4f 107#endif
b061d5f1
RS
108
109#define EEOF -1
110
111static struct scnhdr *text_section;
d7b43eaa
RS
112static struct scnhdr *rel_dyn_section;
113static struct scnhdr *dynstr_section;
114static struct scnhdr *dynsym_section;
b061d5f1
RS
115static struct scnhdr *init_section;
116static struct scnhdr *finit_section;
117static struct scnhdr *rdata_section;
866fc66a 118static struct scnhdr *rconst_section;
b061d5f1
RS
119static struct scnhdr *data_section;
120static struct scnhdr *pdata_section;
121static struct scnhdr *xdata_section;
122static struct scnhdr *got_section;
123static struct scnhdr *lit8_section;
124static struct scnhdr *lit4_section;
125static struct scnhdr *sdata_section;
126static struct scnhdr *sbss_section;
127static struct scnhdr *bss_section;
128
d7b43eaa
RS
129static struct scnhdr old_data_scnhdr;
130
866fc66a 131static unsigned long Brk;
b061d5f1
RS
132
133struct headers {
134 struct filehdr fhdr;
135 struct aouthdr aout;
136 struct scnhdr section[_MIPS_NSCNS_MAX];
137};
138
139
140
141/* Define name of label for entry point for the dumped executable. */
142
143#ifndef DEFAULT_ENTRY_ADDRESS
144#define DEFAULT_ENTRY_ADDRESS __start
145#endif
146\f
3fb21e7a 147void
b061d5f1
RS
148unexec (new_name, a_name, data_start, bss_start, entry_address)
149 char *new_name, *a_name;
150 unsigned long data_start, bss_start, entry_address;
151{
152 int new, old;
153 char * oldptr;
154 struct headers ohdr, nhdr;
155 struct stat stat;
156 long pagesize, brk;
157 long newsyms, symrel;
158 int nread;
159 int i;
160 long vaddr, scnptr;
161#define BUFSIZE 8192
162 char buffer[BUFSIZE];
163
164 if ((old = open (a_name, O_RDONLY)) < 0)
165 fatal_unexec ("opening %s", a_name);
166
167 new = creat (new_name, 0666);
168 if (new < 0) fatal_unexec ("creating %s", new_name);
169
170 if ((fstat (old, &stat) == -1))
171 fatal_unexec ("fstat %s", a_name);
172
173 oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0);
174
175 if (oldptr == (char *)-1)
176 fatal_unexec ("mmap %s", a_name);
177
178 close (old);
179
180 /* This is a copy of the a.out header of the original executable */
181
182 ohdr = (*(struct headers *)oldptr);
183
184 /* This is where we build the new header from the in-memory copy */
185
186 nhdr = *((struct headers *)TEXT_START);
187
188 /* First do some consistency checks */
189
190 if (nhdr.fhdr.f_magic != ALPHAMAGIC
191 && nhdr.fhdr.f_magic != ALPHAUMAGIC)
192 {
193 fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
194 nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC);
195 exit (1);
196 }
197
198 if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
199 {
200 fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
0c08e6df 201 nhdr.fhdr.f_opthdr, (int)sizeof (nhdr.aout));
b061d5f1
RS
202 exit (1);
203 }
204 if (nhdr.aout.magic != ZMAGIC)
205 {
206 fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
207 nhdr.aout.magic, ZMAGIC);
208 exit (1);
209 }
210
211
212 /* Now check the existence of certain header section and grab
213 their addresses. */
214
215#define CHECK_SCNHDR(ptr, name, flags) \
216 ptr = NULL; \
217 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
d7b43eaa 218 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
b061d5f1
RS
219 { \
220 if (nhdr.section[i].s_flags != flags) \
221 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
222 nhdr.section[i].s_flags, flags, name); \
223 ptr = nhdr.section + i; \
224 } \
225
226 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
227 CHECK_SCNHDR (init_section, _INIT, STYP_INIT);
d7b43eaa
RS
228#ifdef _REL_DYN
229 CHECK_SCNHDR (rel_dyn_section, _REL_DYN, STYP_REL_DYN);
230#endif /* _REL_DYN */
231#ifdef _DYNSYM
232 CHECK_SCNHDR (dynsym_section, _DYNSYM, STYP_DYNSYM);
233#endif /* _REL_DYN */
234#ifdef _DYNSTR
235 CHECK_SCNHDR (dynstr_section, _DYNSTR, STYP_DYNSTR);
236#endif /* _REL_DYN */
b061d5f1
RS
237#ifdef _FINI
238 CHECK_SCNHDR (finit_section, _FINI, STYP_FINI);
239#endif /* _FINI */
240 CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
866fc66a
RS
241#ifdef _RCONST
242 CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST);
243#endif
b061d5f1
RS
244#ifdef _PDATA
245 CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
20fd0b4f 246#endif /* _PDATA */
b061d5f1
RS
247#ifdef _GOT
248 CHECK_SCNHDR (got_section, _GOT, STYP_GOT);
20fd0b4f 249#endif /* _GOT */
b061d5f1
RS
250 CHECK_SCNHDR (data_section, _DATA, STYP_DATA);
251#ifdef _XDATA
252 CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
253#endif /* _XDATA */
254#ifdef _LIT8
255 CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8);
256 CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4);
257#endif /* _LIT8 */
258 CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
259 CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS);
260 CHECK_SCNHDR (bss_section, _BSS, STYP_BSS);
b061d5f1
RS
261
262
263 pagesize = getpagesize ();
264 brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
265
266 /* Remember the current break */
267
268 Brk = brk;
269
d7b43eaa
RS
270 bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
271
b061d5f1
RS
272 nhdr.aout.dsize = brk - DATA_START;
273 nhdr.aout.bsize = 0;
274 if (entry_address == 0)
275 {
276 extern DEFAULT_ENTRY_ADDRESS ();
277 nhdr.aout.entry = (unsigned long)DEFAULT_ENTRY_ADDRESS;
278 }
279 else
280 nhdr.aout.entry = entry_address;
281
282 nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize;
b061d5f1 283
866fc66a
RS
284 if (rdata_section != NULL)
285 {
286 rdata_section->s_size = data_start - DATA_START;
287
288 /* Adjust start and virtual addresses of rdata_section, too. */
289 rdata_section->s_vaddr = DATA_START;
290 rdata_section->s_paddr = DATA_START;
291 rdata_section->s_scnptr = text_section->s_scnptr + nhdr.aout.tsize;
292 }
b061d5f1
RS
293
294 data_section->s_vaddr = data_start;
295 data_section->s_paddr = data_start;
296 data_section->s_size = brk - data_start;
866fc66a
RS
297
298 if (rdata_section != NULL)
299 {
300 data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
301 }
302
b061d5f1
RS
303 vaddr = data_section->s_vaddr + data_section->s_size;
304 scnptr = data_section->s_scnptr + data_section->s_size;
305 if (lit8_section != NULL)
306 {
307 lit8_section->s_vaddr = vaddr;
308 lit8_section->s_paddr = vaddr;
309 lit8_section->s_size = 0;
310 lit8_section->s_scnptr = scnptr;
311 }
312 if (lit4_section != NULL)
313 {
314 lit4_section->s_vaddr = vaddr;
315 lit4_section->s_paddr = vaddr;
316 lit4_section->s_size = 0;
317 lit4_section->s_scnptr = scnptr;
318 }
319 if (sdata_section != NULL)
320 {
321 sdata_section->s_vaddr = vaddr;
322 sdata_section->s_paddr = vaddr;
323 sdata_section->s_size = 0;
324 sdata_section->s_scnptr = scnptr;
325 }
326#ifdef _XDATA
327 if (xdata_section != NULL)
328 {
329 xdata_section->s_vaddr = vaddr;
330 xdata_section->s_paddr = vaddr;
331 xdata_section->s_size = 0;
332 xdata_section->s_scnptr = scnptr;
333 }
334#endif
335#ifdef _GOT
336 if (got_section != NULL)
337 {
7d713448
RS
338 bcopy (got_section, buffer, sizeof (struct scnhdr));
339
b061d5f1
RS
340 got_section->s_vaddr = vaddr;
341 got_section->s_paddr = vaddr;
342 got_section->s_size = 0;
343 got_section->s_scnptr = scnptr;
344 }
345#endif /*_GOT */
346 if (sbss_section != NULL)
347 {
348 sbss_section->s_vaddr = vaddr;
349 sbss_section->s_paddr = vaddr;
350 sbss_section->s_size = 0;
351 sbss_section->s_scnptr = scnptr;
352 }
353 if (bss_section != NULL)
354 {
355 bss_section->s_vaddr = vaddr;
356 bss_section->s_paddr = vaddr;
357 bss_section->s_size = 0;
358 bss_section->s_scnptr = scnptr;
359 }
360
361 WRITE (new, (char *)TEXT_START, nhdr.aout.tsize,
362 "writing text section to %s", new_name);
363 WRITE (new, (char *)DATA_START, nhdr.aout.dsize,
364 "writing data section to %s", new_name);
365
7d713448
RS
366#ifdef _GOT
367#define old_got_section ((struct scnhdr *)buffer)
368
369 if (got_section != NULL)
370 {
371 SEEK (new, old_got_section->s_scnptr,
372 "seeking to start of got_section in %s", new_name);
373 WRITE (new, oldptr + old_got_section->s_scnptr, old_got_section->s_size,
374 "writing new got_section of %s", new_name);
375 SEEK (new, nhdr.aout.tsize + nhdr.aout.dsize,
376 "seeking to end of data section of %s", new_name);
377 }
378
379#undef old_got_section
380#endif
b061d5f1
RS
381
382 /*
383 * Construct new symbol table header
384 */
385
386 bcopy (oldptr + nhdr.fhdr.f_symptr, buffer, cbHDRR);
387
388#define symhdr ((pHDRR)buffer)
389 newsyms = nhdr.aout.tsize + nhdr.aout.dsize;
390 symrel = newsyms - nhdr.fhdr.f_symptr;
391 nhdr.fhdr.f_symptr = newsyms;
392 symhdr->cbLineOffset += symrel;
393 symhdr->cbDnOffset += symrel;
394 symhdr->cbPdOffset += symrel;
395 symhdr->cbSymOffset += symrel;
396 symhdr->cbOptOffset += symrel;
397 symhdr->cbAuxOffset += symrel;
398 symhdr->cbSsOffset += symrel;
399 symhdr->cbSsExtOffset += symrel;
400 symhdr->cbFdOffset += symrel;
401 symhdr->cbRfdOffset += symrel;
402 symhdr->cbExtOffset += symrel;
403
404 WRITE (new, buffer, cbHDRR, "writing symbol table header of %s", new_name);
405
406 /*
407 * Copy the symbol table and line numbers
408 */
409 WRITE (new, oldptr + ohdr.fhdr.f_symptr + cbHDRR,
410 stat.st_size - ohdr.fhdr.f_symptr - cbHDRR,
411 "writing symbol table of %s", new_name);
412
6ca5cfd1
RS
413#ifdef _REL_DYN
414 if (rel_dyn_section)
415 update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
416#endif
b061d5f1
RS
417
418#undef symhdr
419
420 SEEK (new, 0, "seeking to start of header in %s", new_name);
421 WRITE (new, &nhdr, sizeof (nhdr),
422 "writing header of %s", new_name);
423
424 close (old);
425 close (new);
426 mark_x (new_name);
427}
428
429
3fb21e7a 430static void
d7b43eaa 431update_dynamic_symbols (old, new_name, new, aout)
866fc66a
RS
432 char *old; /* Pointer to old executable */
433 char *new_name; /* Name of new executable */
434 int new; /* File descriptor for new executable */
d7b43eaa 435 struct aouthdr aout; /* a.out info from the file header */
b061d5f1 436{
61e63089 437#if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
54dfb86c 438
d7b43eaa
RS
439 typedef struct dynrel_info {
440 char * addr;
441 unsigned type:8;
442 unsigned index:24;
443 unsigned info:8;
444 unsigned pad:8;
445 } dr_info;
446
447 int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info);
448 int i;
449 dr_info * rd_base = (dr_info *) (old + rel_dyn_section->s_scnptr);
450 Elf32_Sym * ds_base = (Elf32_Sym *) (old + dynsym_section->s_scnptr);
b061d5f1 451
d7b43eaa
RS
452 for (i = 0; i < nsyms; i++) {
453 register Elf32_Sym x;
b061d5f1 454
d7b43eaa
RS
455 if (rd_base[i].index == 0)
456 continue;
b061d5f1 457
d7b43eaa
RS
458 x = ds_base[rd_base[i].index];
459
460#if 0
461 fprintf (stderr, "Object inspected: %s, addr = %lx, shndx = %x",
462 old + dynstr_section->s_scnptr + x.st_name, rd_base[i].addr, x.st_shndx);
463#endif
464
465
466 if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL)
467 && (x.st_shndx == 0)
468 /* && (x.st_value == NULL) */
469 ) {
470 /* OK, this is probably a reference to an object in a shared
471 library, so copy the old value. This is done in several steps:
472 1. reladdr is the address of the location in question relative to
473 the start of the data section,
474 2. oldref is the addr is the mapped in temacs executable,
475 3. newref is the address of the location in question in the
476 undumped executable,
477 4. len is the size of the object reference in bytes --
478 currently only 4 (long) and 8 (quad) are supported.
479 */
2881ec96 480 register unsigned long reladdr = (long)rd_base[i].addr - old_data_scnhdr.s_vaddr;
d7b43eaa
RS
481 char * oldref = old + old_data_scnhdr.s_scnptr + reladdr;
482 unsigned long newref = aout.tsize + reladdr;
483 int len;
484
485#if 0
486 fprintf (stderr, "...relocated\n");
487#endif
488
177c0ea7 489 if (rd_base[i].type == R_REFLONG)
d7b43eaa 490 len = 4;
177c0ea7 491 else if (rd_base[i].type == R_REFQUAD)
d7b43eaa
RS
492 len = 8;
493 else
4042a81a 494 fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i);
d7b43eaa
RS
495
496 SEEK (new, newref, "seeking to dynamic symbol in %s", new_name);
497 WRITE (new, oldref, len, "writing old dynrel info in %s", new_name);
b061d5f1
RS
498 }
499
d7b43eaa
RS
500#if 0
501 else
502 fprintf (stderr, "...not relocated\n");
503#endif
504
505 }
506
61e63089 507#endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
b061d5f1
RS
508}
509
b061d5f1
RS
510\f
511/*
512 * mark_x
513 *
514 * After successfully building the new a.out, mark it executable
515 */
516
517static void
518mark_x (name)
519 char *name;
520{
521 struct stat sbuf;
522 int um = umask (777);
523 umask (um);
524 if (stat (name, &sbuf) < 0)
525 fatal_unexec ("getting protection on %s", name);
526 sbuf.st_mode |= 0111 & ~um;
527 if (chmod (name, sbuf.st_mode) < 0)
528 fatal_unexec ("setting protection on %s", name);
529}
530
531static void
a084ed10
RS
532fatal_unexec (s, arg)
533 char *s;
534 char *arg;
b061d5f1 535{
b061d5f1
RS
536 if (errno == EEOF)
537 fputs ("unexec: unexpected end of file, ", stderr);
538 else
539 fprintf (stderr, "unexec: %s, ", strerror (errno));
a084ed10 540 fprintf (stderr, s, arg);
b061d5f1
RS
541 fputs (".\n", stderr);
542 exit (1);
543}
ab5796a9
MB
544
545/* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd
546 (do not change this comment) */