428
+ − 1 /* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
+ − 2
+ − 3 Copyright (C) 1994 Free Software Foundation, Inc.
+ − 4
613
+ − 5 This file is part of XEmacs.
428
+ − 6
613
+ − 7 XEmacs is free software; you can redistribute it and/or modify
428
+ − 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
613
+ − 12 XEmacs is distributed in the hope that it will be useful,
428
+ − 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
613
+ − 18 along with XEmacs; see the file COPYING. If not, write to
428
+ − 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ − 20 Boston, MA 02111-1307, USA. */
+ − 21
+ − 22 /* Synched up with: FSF 19.31. */
+ − 23
+ − 24
+ − 25 #include <config.h>
+ − 26 #include <stdlib.h>
+ − 27 #include <string.h>
+ − 28 #include <unistd.h>
+ − 29 #include <sys/types.h>
+ − 30 #include <sys/file.h>
+ − 31 #include <sys/stat.h>
+ − 32 #include <sys/mman.h>
+ − 33 #include <stdio.h>
438
+ − 34 #include <errno.h>
428
+ − 35 #include <varargs.h>
+ − 36 #include <filehdr.h>
+ − 37 #include <aouthdr.h>
+ − 38 #include <scnhdr.h>
+ − 39 #include <syms.h>
2286
+ − 40 #include "compiler.h"
428
+ − 41
+ − 42 static void fatal_unexec (char *, char *);
+ − 43 static void mark_x (char *);
+ − 44
+ − 45 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
+ − 46 errno = EEOF; \
+ − 47 if (read (_fd, _buffer, _size) != _size) \
+ − 48 fatal_unexec (_error_message, _error_arg);
+ − 49
+ − 50 #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
+ − 51 if (write (_fd, _buffer, _size) != _size) \
+ − 52 fatal_unexec (_error_message, _error_arg);
+ − 53
+ − 54 #define SEEK(_fd, _position, _error_message, _error_arg) \
+ − 55 errno = EEOF; \
+ − 56 if (lseek (_fd, _position, L_SET) != _position) \
+ − 57 fatal_unexec (_error_message, _error_arg);
+ − 58
+ − 59 #define EEOF -1
+ − 60
+ − 61 static struct scnhdr *text_section;
+ − 62 static struct scnhdr *init_section;
+ − 63 static struct scnhdr *finit_section;
+ − 64 static struct scnhdr *rdata_section;
+ − 65 static struct scnhdr *rconst_section;
+ − 66 static struct scnhdr *data_section;
+ − 67 static struct scnhdr *pdata_section;
+ − 68 static struct scnhdr *xdata_section;
+ − 69 static struct scnhdr *got_section;
+ − 70 static struct scnhdr *lit8_section;
+ − 71 static struct scnhdr *lit4_section;
+ − 72 static struct scnhdr *sdata_section;
+ − 73 static struct scnhdr *sbss_section;
+ − 74 static struct scnhdr *bss_section;
+ − 75
+ − 76 static unsigned long Brk;
+ − 77
+ − 78 struct headers {
+ − 79 struct filehdr fhdr;
+ − 80 struct aouthdr aout;
+ − 81 struct scnhdr section[_MIPS_NSCNS_MAX];
+ − 82 };
+ − 83
+ − 84
+ − 85 /* Define name of label for entry point for the dumped executable. */
+ − 86
+ − 87 #ifndef DEFAULT_ENTRY_ADDRESS
+ − 88 #define DEFAULT_ENTRY_ADDRESS __start
+ − 89 #endif
442
+ − 90 EXTERN_C int DEFAULT_ENTRY_ADDRESS (void);
+ − 91
428
+ − 92
+ − 93 int
+ − 94 unexec (char *new_name, char *a_name,
+ − 95 unsigned long data_start,
2286
+ − 96 unsigned long UNUSED (bss_start),
428
+ − 97 unsigned long entry_address)
+ − 98 {
3025
+ − 99 int new_, old;
428
+ − 100 char * oldptr;
+ − 101 struct headers ohdr, nhdr;
+ − 102 struct stat stat;
+ − 103 long pagesize, brk;
+ − 104 long newsyms, symrel;
+ − 105 int i;
+ − 106 long vaddr, scnptr;
+ − 107 #define BUFSIZE 8192
+ − 108 char buffer[BUFSIZE];
+ − 109
+ − 110 if ((old = open (a_name, O_RDONLY)) < 0)
+ − 111 fatal_unexec ("opening %s", a_name);
+ − 112
3025
+ − 113 new_ = creat (new_name, 0666);
+ − 114 if (new_ < 0) fatal_unexec ("creating %s", new_name);
428
+ − 115
+ − 116 if ((fstat (old, &stat) == -1))
+ − 117 fatal_unexec ("fstat %s", a_name);
+ − 118
+ − 119 oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0);
+ − 120
+ − 121 if (oldptr == (char *)-1)
+ − 122 fatal_unexec ("mmap %s", a_name);
+ − 123
+ − 124 close (old);
+ − 125
+ − 126 /* This is a copy of the a.out header of the original executable */
+ − 127
+ − 128 ohdr = (*(struct headers *)oldptr);
+ − 129
+ − 130 /* This is where we build the new header from the in-memory copy */
+ − 131
+ − 132 nhdr = *((struct headers *)TEXT_START);
+ − 133
+ − 134 /* First do some consistency checks */
+ − 135
+ − 136 if (nhdr.fhdr.f_magic != ALPHAMAGIC
+ − 137 && nhdr.fhdr.f_magic != ALPHAUMAGIC)
+ − 138 {
+ − 139 fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
+ − 140 nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC);
+ − 141 exit (1);
+ − 142 }
+ − 143
+ − 144 if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
+ − 145 {
+ − 146 fprintf (stderr, "unexec: input a.out header is %d bytes, not %ld.\n",
+ − 147 nhdr.fhdr.f_opthdr, (long) (sizeof (nhdr.aout)));
+ − 148 exit (1);
+ − 149 }
+ − 150 if (nhdr.aout.magic != ZMAGIC)
+ − 151 {
+ − 152 fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
+ − 153 nhdr.aout.magic, ZMAGIC);
+ − 154 exit (1);
+ − 155 }
+ − 156
+ − 157
+ − 158 /* Now check the existence of certain header section and grab
+ − 159 their addresses. */
+ − 160
+ − 161 #define CHECK_SCNHDR(ptr, name, flags) \
+ − 162 ptr = NULL; \
+ − 163 for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
+ − 164 if (strcmp (nhdr.section[i].s_name, name) == 0) \
+ − 165 { \
+ − 166 if (nhdr.section[i].s_flags != flags) \
+ − 167 fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
+ − 168 nhdr.section[i].s_flags, flags, name); \
+ − 169 ptr = nhdr.section + i; \
+ − 170 } \
+ − 171
+ − 172 CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
+ − 173 CHECK_SCNHDR (init_section, _INIT, STYP_INIT);
+ − 174 #ifdef _FINI
+ − 175 CHECK_SCNHDR (finit_section, _FINI, STYP_FINI);
+ − 176 #endif /* _FINI */
+ − 177 CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
+ − 178 #ifdef _RCONST
+ − 179 CHECK_SCNHDR (rconst_section, _RCONST, STYP_RCONST);
+ − 180 #endif
+ − 181 #ifdef _PDATA
+ − 182 CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
+ − 183 #endif /* _PDATA */
+ − 184 #ifdef _GOT
+ − 185 CHECK_SCNHDR (got_section, _GOT, STYP_GOT);
+ − 186 #endif /* _GOT */
+ − 187 CHECK_SCNHDR (data_section, _DATA, STYP_DATA);
+ − 188 #ifdef _XDATA
+ − 189 CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
+ − 190 #endif /* _XDATA */
+ − 191 #ifdef _LIT8
+ − 192 CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8);
+ − 193 CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4);
+ − 194 #endif /* _LIT8 */
+ − 195 CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
+ − 196 CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS);
+ − 197 CHECK_SCNHDR (bss_section, _BSS, STYP_BSS);
+ − 198
+ − 199
+ − 200 pagesize = getpagesize ();
+ − 201 brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
+ − 202
+ − 203 /* Remember the current break */
+ − 204
+ − 205 Brk = brk;
+ − 206
+ − 207 nhdr.aout.dsize = brk - DATA_START;
+ − 208 nhdr.aout.bsize = 0;
+ − 209 if (entry_address == 0)
+ − 210 {
+ − 211 nhdr.aout.entry = (unsigned long)DEFAULT_ENTRY_ADDRESS;
+ − 212 }
+ − 213 else
+ − 214 nhdr.aout.entry = entry_address;
+ − 215
+ − 216 nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize;
+ − 217
+ − 218 if (rdata_section != NULL)
+ − 219 {
+ − 220 rdata_section->s_size = data_start - DATA_START;
+ − 221
+ − 222 /* Adjust start and virtual addresses of rdata_section, too. */
+ − 223 rdata_section->s_vaddr = DATA_START;
+ − 224 rdata_section->s_paddr = DATA_START;
+ − 225 rdata_section->s_scnptr = text_section->s_scnptr + nhdr.aout.tsize;
+ − 226 }
+ − 227
+ − 228 data_section->s_vaddr = data_start;
+ − 229 data_section->s_paddr = data_start;
+ − 230 data_section->s_size = brk - data_start;
+ − 231
+ − 232 if (rdata_section != NULL)
+ − 233 {
+ − 234 data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
+ − 235 }
+ − 236
+ − 237 vaddr = data_section->s_vaddr + data_section->s_size;
+ − 238 scnptr = data_section->s_scnptr + data_section->s_size;
+ − 239 if (lit8_section != NULL)
+ − 240 {
+ − 241 lit8_section->s_vaddr = vaddr;
+ − 242 lit8_section->s_paddr = vaddr;
+ − 243 lit8_section->s_size = 0;
+ − 244 lit8_section->s_scnptr = scnptr;
+ − 245 }
+ − 246 if (lit4_section != NULL)
+ − 247 {
+ − 248 lit4_section->s_vaddr = vaddr;
+ − 249 lit4_section->s_paddr = vaddr;
+ − 250 lit4_section->s_size = 0;
+ − 251 lit4_section->s_scnptr = scnptr;
+ − 252 }
+ − 253 if (sdata_section != NULL)
+ − 254 {
+ − 255 sdata_section->s_vaddr = vaddr;
+ − 256 sdata_section->s_paddr = vaddr;
+ − 257 sdata_section->s_size = 0;
+ − 258 sdata_section->s_scnptr = scnptr;
+ − 259 }
+ − 260 #ifdef _XDATA
+ − 261 if (xdata_section != NULL)
+ − 262 {
+ − 263 xdata_section->s_vaddr = vaddr;
+ − 264 xdata_section->s_paddr = vaddr;
+ − 265 xdata_section->s_size = 0;
+ − 266 xdata_section->s_scnptr = scnptr;
+ − 267 }
+ − 268 #endif
+ − 269 #ifdef _GOT
+ − 270 if (got_section != NULL)
+ − 271 {
+ − 272 got_section->s_vaddr = vaddr;
+ − 273 got_section->s_paddr = vaddr;
+ − 274 got_section->s_size = 0;
+ − 275 got_section->s_scnptr = scnptr;
+ − 276 }
+ − 277 #endif /*_GOT */
+ − 278 if (sbss_section != NULL)
+ − 279 {
+ − 280 sbss_section->s_vaddr = vaddr;
+ − 281 sbss_section->s_paddr = vaddr;
+ − 282 sbss_section->s_size = 0;
+ − 283 sbss_section->s_scnptr = scnptr;
+ − 284 }
+ − 285 if (bss_section != NULL)
+ − 286 {
+ − 287 bss_section->s_vaddr = vaddr;
+ − 288 bss_section->s_paddr = vaddr;
+ − 289 bss_section->s_size = 0;
+ − 290 bss_section->s_scnptr = scnptr;
+ − 291 }
+ − 292
3025
+ − 293 WRITE (new_, (char *)TEXT_START, nhdr.aout.tsize,
428
+ − 294 "writing text section to %s", new_name);
3025
+ − 295 WRITE (new_, (char *)DATA_START, nhdr.aout.dsize,
428
+ − 296 "writing data section to %s", new_name);
+ − 297
+ − 298
+ − 299 /*
+ − 300 * Construct new symbol table header
+ − 301 */
+ − 302
+ − 303 memcpy (buffer, oldptr + nhdr.fhdr.f_symptr, cbHDRR);
+ − 304
+ − 305 #define symhdr ((pHDRR)buffer)
+ − 306 newsyms = nhdr.aout.tsize + nhdr.aout.dsize;
+ − 307 symrel = newsyms - nhdr.fhdr.f_symptr;
+ − 308 nhdr.fhdr.f_symptr = newsyms;
+ − 309 symhdr->cbLineOffset += symrel;
+ − 310 symhdr->cbDnOffset += symrel;
+ − 311 symhdr->cbPdOffset += symrel;
+ − 312 symhdr->cbSymOffset += symrel;
+ − 313 symhdr->cbOptOffset += symrel;
+ − 314 symhdr->cbAuxOffset += symrel;
+ − 315 symhdr->cbSsOffset += symrel;
+ − 316 symhdr->cbSsExtOffset += symrel;
+ − 317 symhdr->cbFdOffset += symrel;
+ − 318 symhdr->cbRfdOffset += symrel;
+ − 319 symhdr->cbExtOffset += symrel;
+ − 320
3025
+ − 321 WRITE (new_, buffer, cbHDRR, "writing symbol table header of %s", new_name);
428
+ − 322
+ − 323 /*
+ − 324 * Copy the symbol table and line numbers
+ − 325 */
3025
+ − 326 WRITE (new_, oldptr + ohdr.fhdr.f_symptr + cbHDRR,
428
+ − 327 stat.st_size - ohdr.fhdr.f_symptr - cbHDRR,
+ − 328 "writing symbol table of %s", new_name);
+ − 329
+ − 330 #if 0
+ − 331
+ − 332 /* Not needed for now */
+ − 333
3025
+ − 334 update_dynamic_symbols (oldptr, new_name, new_, newsyms,
428
+ − 335 ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->issExtMax,
+ − 336 ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->cbExtOffset,
+ − 337 ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->cbSsExtOffset);
+ − 338
+ − 339 #endif
+ − 340
+ − 341 #undef symhdr
+ − 342
3025
+ − 343 SEEK (new_, 0, "seeking to start of header in %s", new_name);
+ − 344 WRITE (new_, &nhdr, sizeof (nhdr),
428
+ − 345 "writing header of %s", new_name);
+ − 346
+ − 347 close (old);
3025
+ − 348 close (new_);
428
+ − 349 mark_x (new_name);
+ − 350 return 0;
+ − 351 }
+ − 352
+ − 353
+ − 354 #if 0
+ − 355
+ − 356 /* Not needed for now */
+ − 357
+ − 358 /* The following function updates the values of some symbols
+ − 359 that are used by the dynamic loader:
+ − 360
+ − 361 _edata
+ − 362 _end
+ − 363
+ − 364 */
+ − 365
+ − 366 int
+ − 367 update_dynamic_symbols (
+ − 368 char *old, /* Pointer to old executable */
+ − 369 char *new_name, /* Name of new executable */
3025
+ − 370 int new_, /* File descriptor for new executable */
428
+ − 371 long newsyms, /* Offset of Symbol table in new executable */
+ − 372 int nsyms, /* Number of symbol table entries */
+ − 373 long symoff, /* Offset of External Symbols in old file */
+ − 374 long stroff) /* Offset of string table in old file */
+ − 375 {
+ − 376 long i;
+ − 377 int found = 0;
+ − 378 EXTR n_end, n_edata;
+ − 379
+ − 380 /* We go through the symbol table entries until we have found the two
+ − 381 symbols. */
+ − 382
+ − 383 /* cbEXTR is the size of an external symbol table entry */
+ − 384
+ − 385 for (i = 0; i < nsyms && found < 2; i += cbEXTR)
+ − 386 {
+ − 387 REGISTER pEXTR x = (pEXTR) (old + symoff + i);
+ − 388 char *s;
+ − 389
+ − 390 s = old + stroff + x->asym.iss; /* name of the symbol */
+ − 391
+ − 392 if (!strcmp(s,"_edata"))
+ − 393 {
+ − 394 found++;
+ − 395 memcpy (&n_edata, x, cbEXTR);
+ − 396 n_edata.asym.value = Brk;
3025
+ − 397 SEEK (new_, newsyms + cbHDRR + i,
428
+ − 398 "seeking to symbol _edata in %s", new_name);
3025
+ − 399 WRITE (new_, &n_edata, cbEXTR,
428
+ − 400 "writing symbol table entry for _edata into %s", new_name);
+ − 401 }
+ − 402 else if (!strcmp(s,"_end"))
+ − 403 {
+ − 404 found++;
+ − 405 memcpy (&n_end, x, cbEXTR);
+ − 406 n_end.asym.value = Brk;
3025
+ − 407 SEEK (new_, newsyms + cbHDRR + i,
428
+ − 408 "seeking to symbol _end in %s", new_name);
3025
+ − 409 WRITE (new_, &n_end, cbEXTR,
428
+ − 410 "writing symbol table entry for _end into %s", new_name);
+ − 411 }
+ − 412 }
+ − 413
+ − 414 }
+ − 415
+ − 416 #endif
+ − 417
+ − 418
+ − 419 /*
+ − 420 * mark_x
+ − 421 *
+ − 422 * After successfully building the new a.out, mark it executable
+ − 423 */
+ − 424
+ − 425 static void
+ − 426 mark_x (char *name)
+ − 427 {
+ − 428 struct stat sbuf;
+ − 429 int um = umask (777);
+ − 430 umask (um);
+ − 431 if (stat (name, &sbuf) < 0)
+ − 432 fatal_unexec ("getting protection on %s", name);
+ − 433 sbuf.st_mode |= 0111 & ~um;
+ − 434 if (chmod (name, sbuf.st_mode) < 0)
+ − 435 fatal_unexec ("setting protection on %s", name);
+ − 436 }
+ − 437
+ − 438 static void
+ − 439 fatal_unexec (char *s, char *arg)
+ − 440 {
+ − 441 if (errno == EEOF)
+ − 442 fputs ("unexec: unexpected end of file, ", stderr);
+ − 443 else
+ − 444 fprintf (stderr, "unexec: %s, ", strerror (errno));
+ − 445 fprintf (stderr, s, arg);
+ − 446 fputs (".\n", stderr);
+ − 447 exit (1);
+ − 448 }