(Coding Conventions): Node renamed from Style Tips.
[bpt/emacs.git] / src / unexalpha.c
CommitLineData
b061d5f1
RS
1/* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
2
3 Copyright (C) 1994 Free Software Foundation, Inc.
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>
30#include <filehdr.h>
31#include <aouthdr.h>
32#include <scnhdr.h>
33#include <syms.h>
d7b43eaa
RS
34#ifndef __linux__
35# include <reloc.h>
36# include <elf_abi.h>
37#endif
b061d5f1
RS
38
39static void fatal_unexec ();
40static 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
56extern int errno;
57extern char *strerror ();
58
d7b43eaa 59void *sbrk ();
b061d5f1
RS
60
61#define EEOF -1
62
63static struct scnhdr *text_section;
d7b43eaa
RS
64static struct scnhdr *rel_dyn_section;
65static struct scnhdr *dynstr_section;
66static struct scnhdr *dynsym_section;
b061d5f1
RS
67static struct scnhdr *init_section;
68static struct scnhdr *finit_section;
69static struct scnhdr *rdata_section;
866fc66a 70static struct scnhdr *rconst_section;
b061d5f1
RS
71static struct scnhdr *data_section;
72static struct scnhdr *pdata_section;
73static struct scnhdr *xdata_section;
74static struct scnhdr *got_section;
75static struct scnhdr *lit8_section;
76static struct scnhdr *lit4_section;
77static struct scnhdr *sdata_section;
78static struct scnhdr *sbss_section;
79static struct scnhdr *bss_section;
80
d7b43eaa
RS
81static struct scnhdr old_data_scnhdr;
82
866fc66a 83static unsigned long Brk;
b061d5f1
RS
84
85struct 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
99unexec (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++) \
d7b43eaa 169 if (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
b061d5f1
RS
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);
d7b43eaa
RS
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 */
b061d5f1
RS
188#ifdef _FINI
189 CHECK_SCNHDR (finit_section, _FINI, STYP_FINI);
190#endif /* _FINI */
191 CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
866fc66a
RS
192#ifdef _RCONST
193 CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST);
194#endif
b061d5f1
RS
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);
b061d5f1
RS
212
213
214 pagesize = getpagesize ();
215 brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
216
217 /* Remember the current break */
218
219 Brk = brk;
220
d7b43eaa
RS
221 bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
222
b061d5f1
RS
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;
b061d5f1 234
866fc66a
RS
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 }
b061d5f1
RS
244
245 data_section->s_vaddr = data_start;
246 data_section->s_paddr = data_start;
247 data_section->s_size = brk - data_start;
866fc66a
RS
248
249 if (rdata_section != NULL)
250 {
251 data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
252 }
253
b061d5f1
RS
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 {
7d713448
RS
289 bcopy (got_section, buffer, sizeof (struct scnhdr));
290
b061d5f1
RS
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
7d713448
RS
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
b061d5f1
RS
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
d7b43eaa
RS
364#ifndef __linux__
365 update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
b061d5f1
RS
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
b061d5f1 380
b061d5f1 381
d7b43eaa 382#ifndef __linux__
b061d5f1 383
d7b43eaa 384update_dynamic_symbols (old, new_name, new, aout)
866fc66a
RS
385 char *old; /* Pointer to old executable */
386 char *new_name; /* Name of new executable */
387 int new; /* File descriptor for new executable */
d7b43eaa 388 struct aouthdr aout; /* a.out info from the file header */
b061d5f1 389{
d7b43eaa
RS
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);
b061d5f1 402
d7b43eaa
RS
403 for (i = 0; i < nsyms; i++) {
404 register Elf32_Sym x;
b061d5f1 405
d7b43eaa
RS
406 if (rd_base[i].index == 0)
407 continue;
b061d5f1 408
d7b43eaa
RS
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);
b061d5f1
RS
449 }
450
d7b43eaa
RS
451#if 0
452 else
453 fprintf (stderr, "...not relocated\n");
454#endif
455
456 }
457
b061d5f1
RS
458}
459
d7b43eaa 460#endif /* !__linux__ */
b061d5f1
RS
461
462\f
463/*
464 * mark_x
465 *
466 * After successfully building the new a.out, mark it executable
467 */
468
469static void
470mark_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
483static void
a084ed10
RS
484fatal_unexec (s, arg)
485 char *s;
486 char *arg;
b061d5f1 487{
b061d5f1
RS
488 if (errno == EEOF)
489 fputs ("unexec: unexpected end of file, ", stderr);
490 else
491 fprintf (stderr, "unexec: %s, ", strerror (errno));
a084ed10 492 fprintf (stderr, s, arg);
b061d5f1
RS
493 fputs (".\n", stderr);
494 exit (1);
495}