| 1 | /* Unexec for MIPS (including IRIS4D). |
| 2 | Note that the GNU project considers support for MIPS operation |
| 3 | a peripheral activity which should not be allowed to divert effort |
| 4 | from development of the GNU system. Changes in this code will be |
| 5 | installed when users send them in, but aside from that |
| 6 | we don't plan to think about it, or about whether other Emacs |
| 7 | maintenance might break it. |
| 8 | |
| 9 | Copyright (C) 1988, 1994 Free Software Foundation, Inc. |
| 10 | |
| 11 | This file is part of GNU Emacs. |
| 12 | |
| 13 | GNU Emacs is free software; you can redistribute it and/or modify |
| 14 | it under the terms of the GNU General Public License as published by |
| 15 | the Free Software Foundation; either version 2, or (at your option) |
| 16 | any later version. |
| 17 | |
| 18 | GNU Emacs is distributed in the hope that it will be useful, |
| 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 21 | GNU General Public License for more details. |
| 22 | |
| 23 | You should have received a copy of the GNU General Public License |
| 24 | along with GNU Emacs; see the file COPYING. If not, write to |
| 25 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
| 26 | |
| 27 | \f |
| 28 | #include <config.h> |
| 29 | #include <sys/types.h> |
| 30 | #include <sys/file.h> |
| 31 | #include <sys/stat.h> |
| 32 | #include <stdio.h> |
| 33 | #include <varargs.h> |
| 34 | #include <filehdr.h> |
| 35 | #include <aouthdr.h> |
| 36 | #include <scnhdr.h> |
| 37 | #include <sym.h> |
| 38 | |
| 39 | #if defined (IRIS_4D) || defined (sony) |
| 40 | #include "getpagesize.h" |
| 41 | #include <fcntl.h> |
| 42 | #endif |
| 43 | |
| 44 | static void fatal_unexec (); |
| 45 | static void mark_x (); |
| 46 | |
| 47 | #define READ(_fd, _buffer, _size, _error_message, _error_arg) \ |
| 48 | errno = EEOF; \ |
| 49 | if (read (_fd, _buffer, _size) != _size) \ |
| 50 | fatal_unexec (_error_message, _error_arg); |
| 51 | |
| 52 | #define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \ |
| 53 | if (write (_fd, _buffer, _size) != _size) \ |
| 54 | fatal_unexec (_error_message, _error_arg); |
| 55 | |
| 56 | #define SEEK(_fd, _position, _error_message, _error_arg) \ |
| 57 | errno = EEOF; \ |
| 58 | if (lseek (_fd, _position, L_SET) != _position) \ |
| 59 | fatal_unexec (_error_message, _error_arg); |
| 60 | |
| 61 | extern int errno; |
| 62 | extern char *strerror (); |
| 63 | #define EEOF -1 |
| 64 | |
| 65 | static struct scnhdr *text_section; |
| 66 | static struct scnhdr *init_section; |
| 67 | static struct scnhdr *finit_section; |
| 68 | static struct scnhdr *rdata_section; |
| 69 | static struct scnhdr *data_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 | struct headers { |
| 77 | struct filehdr fhdr; |
| 78 | struct aouthdr aout; |
| 79 | struct scnhdr section[10]; |
| 80 | }; |
| 81 | |
| 82 | /* Define name of label for entry point for the dumped executable. */ |
| 83 | |
| 84 | #ifndef DEFAULT_ENTRY_ADDRESS |
| 85 | #define DEFAULT_ENTRY_ADDRESS __start |
| 86 | #endif |
| 87 | \f |
| 88 | unexec (new_name, a_name, data_start, bss_start, entry_address) |
| 89 | char *new_name, *a_name; |
| 90 | unsigned data_start, bss_start, entry_address; |
| 91 | { |
| 92 | int new, old; |
| 93 | int pagesize, brk; |
| 94 | int newsyms, symrel; |
| 95 | int nread; |
| 96 | struct headers hdr; |
| 97 | int i; |
| 98 | int vaddr, scnptr; |
| 99 | #define BUFSIZE 8192 |
| 100 | char buffer[BUFSIZE]; |
| 101 | |
| 102 | old = open (a_name, O_RDONLY, 0); |
| 103 | if (old < 0) fatal_unexec ("opening %s", a_name); |
| 104 | |
| 105 | new = creat (new_name, 0666); |
| 106 | if (new < 0) fatal_unexec ("creating %s", new_name); |
| 107 | |
| 108 | hdr = *((struct headers *)TEXT_START); |
| 109 | #ifdef MIPS2 |
| 110 | if (hdr.fhdr.f_magic != MIPSELMAGIC |
| 111 | && hdr.fhdr.f_magic != MIPSEBMAGIC |
| 112 | && hdr.fhdr.f_magic != (MIPSELMAGIC | 1) |
| 113 | && hdr.fhdr.f_magic != (MIPSEBMAGIC | 1)) |
| 114 | { |
| 115 | fprintf (stderr, |
| 116 | "unexec: input file magic number is %x, not %x, %x, %x or %x.\n", |
| 117 | hdr.fhdr.f_magic, |
| 118 | MIPSELMAGIC, MIPSEBMAGIC, |
| 119 | MIPSELMAGIC | 1, MIPSEBMAGIC | 1); |
| 120 | exit(1); |
| 121 | } |
| 122 | #else /* not MIPS2 */ |
| 123 | if (hdr.fhdr.f_magic != MIPSELMAGIC |
| 124 | && hdr.fhdr.f_magic != MIPSEBMAGIC) |
| 125 | { |
| 126 | fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n", |
| 127 | hdr.fhdr.f_magic, MIPSELMAGIC, MIPSEBMAGIC); |
| 128 | exit (1); |
| 129 | } |
| 130 | #endif /* not MIPS2 */ |
| 131 | if (hdr.fhdr.f_opthdr != sizeof (hdr.aout)) |
| 132 | { |
| 133 | fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n", |
| 134 | hdr.fhdr.f_opthdr, sizeof (hdr.aout)); |
| 135 | exit (1); |
| 136 | } |
| 137 | if (hdr.aout.magic != ZMAGIC) |
| 138 | { |
| 139 | fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n", |
| 140 | hdr.aout.magic, ZMAGIC); |
| 141 | exit (1); |
| 142 | } |
| 143 | |
| 144 | #define CHECK_SCNHDR(ptr, name, flags) \ |
| 145 | ptr = NULL; \ |
| 146 | for (i = 0; i < hdr.fhdr.f_nscns && !ptr; i++) \ |
| 147 | if (strcmp (hdr.section[i].s_name, name) == 0) \ |
| 148 | { \ |
| 149 | if (hdr.section[i].s_flags != flags) \ |
| 150 | fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \ |
| 151 | hdr.section[i].s_flags, flags, name); \ |
| 152 | ptr = hdr.section + i; \ |
| 153 | } \ |
| 154 | |
| 155 | CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT); |
| 156 | CHECK_SCNHDR (init_section, _INIT, STYP_INIT); |
| 157 | CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA); |
| 158 | CHECK_SCNHDR (data_section, _DATA, STYP_DATA); |
| 159 | #ifdef _LIT8 |
| 160 | CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8); |
| 161 | CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4); |
| 162 | #endif /* _LIT8 */ |
| 163 | CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA); |
| 164 | CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS); |
| 165 | CHECK_SCNHDR (bss_section, _BSS, STYP_BSS); |
| 166 | #if 0 /* Apparently this error check goes off on irix 3.3, |
| 167 | but it doesn't indicate a real problem. */ |
| 168 | if (i != hdr.fhdr.f_nscns) |
| 169 | fprintf (stderr, "unexec: %d sections found instead of %d.\n", |
| 170 | i, hdr.fhdr.f_nscns); |
| 171 | #endif |
| 172 | |
| 173 | text_section->s_scnptr = 0; |
| 174 | |
| 175 | pagesize = getpagesize (); |
| 176 | /* Casting to int avoids compiler error on NEWS-OS 5.0.2. */ |
| 177 | brk = (((int) (sbrk (0))) + pagesize - 1) & (-pagesize); |
| 178 | hdr.aout.dsize = brk - DATA_START; |
| 179 | hdr.aout.bsize = 0; |
| 180 | if (entry_address == 0) |
| 181 | { |
| 182 | extern DEFAULT_ENTRY_ADDRESS (); |
| 183 | hdr.aout.entry = (unsigned)DEFAULT_ENTRY_ADDRESS; |
| 184 | } |
| 185 | else |
| 186 | hdr.aout.entry = entry_address; |
| 187 | |
| 188 | hdr.aout.bss_start = hdr.aout.data_start + hdr.aout.dsize; |
| 189 | rdata_section->s_size = data_start - DATA_START; |
| 190 | |
| 191 | /* Adjust start and virtual addresses of rdata_section, too. */ |
| 192 | rdata_section->s_vaddr = DATA_START; |
| 193 | rdata_section->s_paddr = DATA_START; |
| 194 | rdata_section->s_scnptr = text_section->s_scnptr + hdr.aout.tsize; |
| 195 | |
| 196 | data_section->s_vaddr = data_start; |
| 197 | data_section->s_paddr = data_start; |
| 198 | data_section->s_size = brk - data_start; |
| 199 | data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size; |
| 200 | vaddr = data_section->s_vaddr + data_section->s_size; |
| 201 | scnptr = data_section->s_scnptr + data_section->s_size; |
| 202 | if (lit8_section != NULL) |
| 203 | { |
| 204 | lit8_section->s_vaddr = vaddr; |
| 205 | lit8_section->s_paddr = vaddr; |
| 206 | lit8_section->s_size = 0; |
| 207 | lit8_section->s_scnptr = scnptr; |
| 208 | } |
| 209 | if (lit4_section != NULL) |
| 210 | { |
| 211 | lit4_section->s_vaddr = vaddr; |
| 212 | lit4_section->s_paddr = vaddr; |
| 213 | lit4_section->s_size = 0; |
| 214 | lit4_section->s_scnptr = scnptr; |
| 215 | } |
| 216 | if (sdata_section != NULL) |
| 217 | { |
| 218 | sdata_section->s_vaddr = vaddr; |
| 219 | sdata_section->s_paddr = vaddr; |
| 220 | sdata_section->s_size = 0; |
| 221 | sdata_section->s_scnptr = scnptr; |
| 222 | } |
| 223 | if (sbss_section != NULL) |
| 224 | { |
| 225 | sbss_section->s_vaddr = vaddr; |
| 226 | sbss_section->s_paddr = vaddr; |
| 227 | sbss_section->s_size = 0; |
| 228 | sbss_section->s_scnptr = scnptr; |
| 229 | } |
| 230 | if (bss_section != NULL) |
| 231 | { |
| 232 | bss_section->s_vaddr = vaddr; |
| 233 | bss_section->s_paddr = vaddr; |
| 234 | bss_section->s_size = 0; |
| 235 | bss_section->s_scnptr = scnptr; |
| 236 | } |
| 237 | |
| 238 | WRITE (new, (char *)TEXT_START, hdr.aout.tsize, |
| 239 | "writing text section to %s", new_name); |
| 240 | WRITE (new, (char *)DATA_START, hdr.aout.dsize, |
| 241 | "writing data section to %s", new_name); |
| 242 | |
| 243 | SEEK (old, hdr.fhdr.f_symptr, "seeking to start of symbols in %s", a_name); |
| 244 | errno = EEOF; |
| 245 | nread = read (old, buffer, BUFSIZE); |
| 246 | if (nread < sizeof (HDRR)) fatal_unexec ("reading symbols from %s", a_name); |
| 247 | #define symhdr ((pHDRR)buffer) |
| 248 | newsyms = hdr.aout.tsize + hdr.aout.dsize; |
| 249 | symrel = newsyms - hdr.fhdr.f_symptr; |
| 250 | hdr.fhdr.f_symptr = newsyms; |
| 251 | symhdr->cbLineOffset += symrel; |
| 252 | symhdr->cbDnOffset += symrel; |
| 253 | symhdr->cbPdOffset += symrel; |
| 254 | symhdr->cbSymOffset += symrel; |
| 255 | symhdr->cbOptOffset += symrel; |
| 256 | symhdr->cbAuxOffset += symrel; |
| 257 | symhdr->cbSsOffset += symrel; |
| 258 | symhdr->cbSsExtOffset += symrel; |
| 259 | symhdr->cbFdOffset += symrel; |
| 260 | symhdr->cbRfdOffset += symrel; |
| 261 | symhdr->cbExtOffset += symrel; |
| 262 | #undef symhdr |
| 263 | do |
| 264 | { |
| 265 | if (write (new, buffer, nread) != nread) |
| 266 | fatal_unexec ("writing symbols to %s", new_name); |
| 267 | nread = read (old, buffer, BUFSIZE); |
| 268 | if (nread < 0) fatal_unexec ("reading symbols from %s", a_name); |
| 269 | #undef BUFSIZE |
| 270 | } while (nread != 0); |
| 271 | |
| 272 | SEEK (new, 0, "seeking to start of header in %s", new_name); |
| 273 | WRITE (new, &hdr, sizeof (hdr), |
| 274 | "writing header of %s", new_name); |
| 275 | |
| 276 | close (old); |
| 277 | close (new); |
| 278 | mark_x (new_name); |
| 279 | } |
| 280 | \f |
| 281 | /* |
| 282 | * mark_x |
| 283 | * |
| 284 | * After successfully building the new a.out, mark it executable |
| 285 | */ |
| 286 | |
| 287 | static void |
| 288 | mark_x (name) |
| 289 | char *name; |
| 290 | { |
| 291 | struct stat sbuf; |
| 292 | int um = umask (777); |
| 293 | umask (um); |
| 294 | if (stat (name, &sbuf) < 0) |
| 295 | fatal_unexec ("getting protection on %s", name); |
| 296 | sbuf.st_mode |= 0111 & ~um; |
| 297 | if (chmod (name, sbuf.st_mode) < 0) |
| 298 | fatal_unexec ("setting protection on %s", name); |
| 299 | } |
| 300 | |
| 301 | static void |
| 302 | fatal_unexec (s, va_alist) |
| 303 | va_dcl |
| 304 | { |
| 305 | va_list ap; |
| 306 | if (errno == EEOF) |
| 307 | fputs ("unexec: unexpected end of file, ", stderr); |
| 308 | else |
| 309 | fprintf (stderr, "unexec: %s, ", strerror (errno)); |
| 310 | va_start (ap); |
| 311 | _doprnt (s, ap, stderr); |
| 312 | fputs (".\n", stderr); |
| 313 | exit (1); |
| 314 | } |