elf2ecoff.c revision 1.2
1/* $NetBSD: elf2ecoff.c,v 1.2 1996/09/29 22:01:45 jonathan Exp $ */ 2 3/* 4 * Copyright (c) 1995 5 * Ted Lemon (hereinafter referred to as the author) 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31/* elf2ecoff.c 32 33 This program converts an elf executable to an ECOFF executable. 34 No symbol table is retained. This is useful primarily in building 35 net-bootable kernels for machines (e.g., DECstation and Alpha) which 36 only support the ECOFF object file format. */ 37 38#include <sys/types.h> 39#include <fcntl.h> 40#include <unistd.h> 41#include <machine/elf.h> 42#include <stdio.h> 43#include <sys/exec_ecoff.h> 44#include <sys/errno.h> 45#include <string.h> 46#include <limits.h> 47 48struct sect { 49 unsigned long vaddr; 50 unsigned long len; 51}; 52 53int phcmp (); 54char *saveRead (int file, off_t offset, off_t len, char *name); 55int copy (int, int, off_t, off_t); 56int translate_syms (int, int, off_t, off_t, off_t, off_t); 57extern int errno; 58int *symTypeTable; 59 60main (int argc, char **argv, char **envp) 61{ 62 struct ehdr ex; 63 struct phdr *ph; 64 struct shdr *sh; 65 struct sym *symtab; 66 char *shstrtab; 67 int strtabix, symtabix; 68 int i, pad; 69 struct sect text, data, bss; 70 struct ecoff_exechdr ep; 71 struct ecoff_scnhdr esecs [3]; 72 int infile, outfile; 73 unsigned long cur_vma = ULONG_MAX; 74 int symflag = 0; 75 76 text.len = data.len = bss.len = 0; 77 text.vaddr = data.vaddr = bss.vaddr = 0; 78 79 /* Check args... */ 80 if (argc < 3 || argc > 4) 81 { 82 usage: 83 fprintf (stderr, 84 "usage: elf2aout <elf executable> <a.out executable> [-s]\n"); 85 exit (1); 86 } 87 if (argc == 4) 88 { 89 if (strcmp (argv [3], "-s")) 90 goto usage; 91 symflag = 1; 92 } 93 94 /* Try the input file... */ 95 if ((infile = open (argv [1], O_RDONLY)) < 0) 96 { 97 fprintf (stderr, "Can't open %s for read: %s\n", 98 argv [1], strerror (errno)); 99 exit (1); 100 } 101 102 /* Read the header, which is at the beginning of the file... */ 103 i = read (infile, &ex, sizeof ex); 104 if (i != sizeof ex) 105 { 106 fprintf (stderr, "ex: %s: %s.\n", 107 argv [1], i ? strerror (errno) : "End of file reached"); 108 exit (1); 109 } 110 111 /* Read the program headers... */ 112 ph = (struct phdr *)saveRead (infile, ex.phoff, 113 ex.phcount * sizeof (struct phdr), "ph"); 114 /* Read the section headers... */ 115 sh = (struct shdr *)saveRead (infile, ex.shoff, 116 ex.shcount * sizeof (struct shdr), "sh"); 117 /* Read in the section string table. */ 118 shstrtab = saveRead (infile, sh [ex.shstrndx].offset, 119 sh [ex.shstrndx].size, "shstrtab"); 120 121 /* Figure out if we can cram the program header into an ECOFF 122 header... Basically, we can't handle anything but loadable 123 segments, but we can ignore some kinds of segments. We can't 124 handle holes in the address space. Segments may be out of order, 125 so we sort them first. */ 126 127 qsort (ph, ex.phcount, sizeof (struct phdr), phcmp); 128 129 for (i = 0; i < ex.phcount; i++) 130 { 131 /* Section types we can ignore... */ 132 if (ph [i].type == PT_NULL || ph [i].type == PT_NOTE || 133 ph [i].type == PT_PHDR || ph [i].type == PT_MIPS_REGINFO) 134 continue; 135 /* Section types we can't handle... */ 136 else if (ph [i].type != PT_LOAD) 137 { 138 fprintf (stderr, "Program header %d type %d can't be converted.\n"); 139 exit (1); 140 } 141 /* Writable (data) segment? */ 142 if (ph [i].flags & PF_W) 143 { 144 struct sect ndata, nbss; 145 146 ndata.vaddr = ph [i].vaddr; 147 ndata.len = ph [i].filesz; 148 nbss.vaddr = ph [i].vaddr + ph [i].filesz; 149 nbss.len = ph [i].memsz - ph [i].filesz; 150 151 combine (&data, &ndata, 0); 152 combine (&bss, &nbss, 1); 153 } 154 else 155 { 156 struct sect ntxt; 157 158 ntxt.vaddr = ph [i].vaddr; 159 ntxt.len = ph [i].filesz; 160 161 combine (&text, &ntxt); 162 } 163 /* Remember the lowest segment start address. */ 164 if (ph [i].vaddr < cur_vma) 165 cur_vma = ph [i].vaddr; 166 } 167 168 /* Sections must be in order to be converted... */ 169 if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || 170 text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) 171 { 172 fprintf (stderr, "Sections ordering prevents a.out conversion.\n"); 173 exit (1); 174 } 175 176 /* If there's a data section but no text section, then the loader 177 combined everything into one section. That needs to be the 178 text section, so just make the data section zero length following 179 text. */ 180 if (data.len && !text.len) 181 { 182 text = data; 183 data.vaddr = text.vaddr + text.len; 184 data.len = 0; 185 } 186 187 /* If there is a gap between text and data, we'll fill it when we copy 188 the data, so update the length of the text segment as represented in 189 a.out to reflect that, since a.out doesn't allow gaps in the program 190 address space. */ 191 if (text.vaddr + text.len < data.vaddr) 192 text.len = data.vaddr - text.vaddr; 193 194 /* We now have enough information to cons up an a.out header... */ 195 ep.a.magic = ECOFF_OMAGIC; 196 ep.a.vstamp = 200; 197 ep.a.tsize = text.len; 198 ep.a.dsize = data.len; 199 ep.a.bsize = bss.len; 200 ep.a.entry = ex.entry; 201 ep.a.text_start = text.vaddr; 202 ep.a.data_start = data.vaddr; 203 ep.a.bss_start = bss.vaddr; 204 ep.a.gprmask = 0xf3fffffe; 205 bzero (&ep.a.cprmask, sizeof ep.a.cprmask); 206 ep.a.gp_value = 0; /* unused. */ 207 208 ep.f.f_magic = ECOFF_MAGIC_MIPSEL; 209 ep.f.f_nscns = 3; 210 ep.f.f_timdat = 0; /* bogus */ 211 ep.f.f_symptr = 0; 212 ep.f.f_nsyms = 0; 213 ep.f.f_opthdr = sizeof ep.a; 214 ep.f.f_flags = 0x100f; /* Stripped, not sharable. */ 215 216 strcpy (esecs [0].s_name, ".text"); 217 strcpy (esecs [1].s_name, ".data"); 218 strcpy (esecs [2].s_name, ".bss"); 219 esecs [0].s_paddr = esecs [0].s_vaddr = ep.a.text_start; 220 esecs [1].s_paddr = esecs [1].s_vaddr = ep.a.data_start; 221 esecs [2].s_paddr = esecs [2].s_vaddr = ep.a.bss_start; 222 esecs [0].s_size = ep.a.tsize; 223 esecs [1].s_size = ep.a.dsize; 224 esecs [2].s_size = ep.a.bsize; 225 226 esecs [0].s_scnptr = ECOFF_TXTOFF (&ep); 227 esecs [1].s_scnptr = ECOFF_DATOFF (&ep); 228 esecs [2].s_scnptr = esecs [1].s_scnptr + 229 ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&ep)); 230 esecs [0].s_relptr = esecs [1].s_relptr 231 = esecs [2].s_relptr = 0; 232 esecs [0].s_lnnoptr = esecs [1].s_lnnoptr 233 = esecs [2].s_lnnoptr = 0; 234 esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0; 235 esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0; 236 esecs [0].s_flags = 0x20; 237 esecs [1].s_flags = 0x40; 238 esecs [2].s_flags = 0x82; 239 240 /* Make the output file... */ 241 if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0) 242 { 243 fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno)); 244 exit (1); 245 } 246 247 /* Write the headers... */ 248 i = write (outfile, &ep.f, sizeof ep.f); 249 if (i != sizeof ep.f) 250 { 251 perror ("ep.f: write"); 252 exit (1); 253 254 for (i = 0; i < 6; i++) 255 { 256 printf ("Section %d: %s phys %x size %x file offset %x\n", 257 i, esecs [i].s_name, esecs [i].s_paddr, 258 esecs [i].s_size, esecs [i].s_scnptr); 259 } 260 } 261 fprintf (stderr, "wrote %d byte file header.\n", i); 262 263 i = write (outfile, &ep.a, sizeof ep.a); 264 if (i != sizeof ep.a) 265 { 266 perror ("ep.a: write"); 267 exit (1); 268 } 269 fprintf (stderr, "wrote %d byte a.out header.\n", i); 270 271 i = write (outfile, &esecs, sizeof esecs); 272 if (i != sizeof esecs) 273 { 274 perror ("esecs: write"); 275 exit (1); 276 } 277 fprintf (stderr, "wrote %d bytes of section headers.\n", i); 278 279 if (pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15)) 280 { 281 pad = 16 - pad; 282 i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad); 283 if (i < 0) 284 { 285 perror ("ipad: write"); 286 exit (1); 287 } 288 fprintf (stderr, "wrote %d byte pad.\n", i); 289 } 290 291 /* Copy the loadable sections. Zero-fill any gaps less than 64k; 292 complain about any zero-filling, and die if we're asked to zero-fill 293 more than 64k. */ 294 for (i = 0; i < ex.phcount; i++) 295 { 296 /* Unprocessable sections were handled above, so just verify that 297 the section can be loaded before copying. */ 298 if (ph [i].type == PT_LOAD && ph [i].filesz) 299 { 300 if (cur_vma != ph [i].vaddr) 301 { 302 unsigned long gap = ph [i].vaddr - cur_vma; 303 char obuf [1024]; 304 if (gap > 65536) 305 { 306 fprintf (stderr, "Intersegment gap (%d bytes) too large.\n", 307 gap); 308 exit (1); 309 } 310 fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap); 311 memset (obuf, 0, sizeof obuf); 312 while (gap) 313 { 314 int count = write (outfile, obuf, (gap > sizeof obuf 315 ? sizeof obuf : gap)); 316 if (count < 0) 317 { 318 fprintf (stderr, "Error writing gap: %s\n", 319 strerror (errno)); 320 exit (1); 321 } 322 gap -= count; 323 } 324 } 325fprintf (stderr, "writing %d bytes...\n", ph [i].filesz); 326 copy (outfile, infile, ph [i].offset, ph [i].filesz); 327 cur_vma = ph [i].vaddr + ph [i].filesz; 328 } 329 } 330 331 /* Looks like we won... */ 332 exit (0); 333} 334 335copy (out, in, offset, size) 336 int out, in; 337 off_t offset, size; 338{ 339 char ibuf [4096]; 340 int remaining, cur, count; 341 342 /* Go the the start of the ELF symbol table... */ 343 if (lseek (in, offset, SEEK_SET) < 0) 344 { 345 perror ("copy: lseek"); 346 exit (1); 347 } 348 349 remaining = size; 350 while (remaining) 351 { 352 cur = remaining; 353 if (cur > sizeof ibuf) 354 cur = sizeof ibuf; 355 remaining -= cur; 356 if ((count = read (in, ibuf, cur)) != cur) 357 { 358 fprintf (stderr, "copy: read: %s\n", 359 count ? strerror (errno) : "premature end of file"); 360 exit (1); 361 } 362 if ((count = write (out, ibuf, cur)) != cur) 363 { 364 perror ("copy: write"); 365 exit (1); 366 } 367 } 368} 369 370/* Combine two segments, which must be contiguous. If pad is true, it's 371 okay for there to be padding between. */ 372combine (base, new, pad) 373 struct sect *base, *new; 374 int pad; 375{ 376 if (!base -> len) 377 *base = *new; 378 else if (new -> len) 379 { 380 if (base -> vaddr + base -> len != new -> vaddr) 381 { 382 if (pad) 383 base -> len = new -> vaddr - base -> vaddr; 384 else 385 { 386 fprintf (stderr, 387 "Non-contiguous data can't be converted.\n"); 388 exit (1); 389 } 390 } 391 base -> len += new -> len; 392 } 393} 394 395phcmp (h1, h2) 396 struct phdr *h1, *h2; 397{ 398 if (h1 -> vaddr > h2 -> vaddr) 399 return 1; 400 else if (h1 -> vaddr < h2 -> vaddr) 401 return -1; 402 else 403 return 0; 404} 405 406char *saveRead (int file, off_t offset, off_t len, char *name) 407{ 408 char *tmp; 409 int count; 410 off_t off; 411 if ((off = lseek (file, offset, SEEK_SET)) < 0) 412 { 413 fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno)); 414 exit (1); 415 } 416 if (!(tmp = (char *)malloc (len))) 417 { 418 fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len); 419 exit (1); 420 } 421 count = read (file, tmp, len); 422 if (count != len) 423 { 424 fprintf (stderr, "%s: read: %s.\n", 425 name, count ? strerror (errno) : "End of file reached"); 426 exit (1); 427 } 428 return tmp; 429} 430