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