elf2ecoff.c revision 1.4
1/* $NetBSD: elf2ecoff.c,v 1.4 1997/01/09 20:18:37 tls 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 <sys/exec_elf.h> 42#include <sys/exec_aout.h> 43#include <stdio.h> 44#include <sys/exec_ecoff.h> 45#include <sys/errno.h> 46#include <string.h> 47#include <limits.h> 48 49 50/* Elf Program segment permissions, in program header flags field */ 51 52#define PF_X (1 << 0) /* Segment is executable */ 53#define PF_W (1 << 1) /* Segment is writable */ 54#define PF_R (1 << 2) /* Segment is readable */ 55#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */ 56 57struct sect { 58 unsigned long vaddr; 59 unsigned long len; 60}; 61 62int phcmp (); 63char *saveRead (int file, off_t offset, off_t len, char *name); 64int copy (int, int, off_t, off_t); 65int translate_syms (int, int, off_t, off_t, off_t, off_t); 66extern int errno; 67int *symTypeTable; 68 69main (int argc, char **argv, char **envp) 70{ 71 Elf32_Ehdr ex; 72 Elf32_Phdr *ph; 73 Elf32_Shdr *sh; 74 Elf32_Sym *symtab; 75 char *shstrtab; 76 int strtabix, symtabix; 77 int i, pad; 78 struct sect text, data, bss; 79 struct ecoff_exechdr ep; 80 struct ecoff_scnhdr esecs [3]; 81 int infile, outfile; 82 unsigned long cur_vma = ULONG_MAX; 83 int symflag = 0; 84 85 text.len = data.len = bss.len = 0; 86 text.vaddr = data.vaddr = bss.vaddr = 0; 87 88 /* Check args... */ 89 if (argc < 3 || argc > 4) 90 { 91 usage: 92 fprintf (stderr, 93 "usage: elf2aout <elf executable> <a.out executable> [-s]\n"); 94 exit (1); 95 } 96 if (argc == 4) 97 { 98 if (strcmp (argv [3], "-s")) 99 goto usage; 100 symflag = 1; 101 } 102 103 /* Try the input file... */ 104 if ((infile = open (argv [1], O_RDONLY)) < 0) 105 { 106 fprintf (stderr, "Can't open %s for read: %s\n", 107 argv [1], strerror (errno)); 108 exit (1); 109 } 110 111 /* Read the header, which is at the beginning of the file... */ 112 i = read (infile, &ex, sizeof ex); 113 if (i != sizeof ex) 114 { 115 fprintf (stderr, "ex: %s: %s.\n", 116 argv [1], i ? strerror (errno) : "End of file reached"); 117 exit (1); 118 } 119 120 /* Read the program headers... */ 121 ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff, 122 ex.e_phnum * sizeof (Elf32_Phdr), "ph"); 123 /* Read the section headers... */ 124 sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff, 125 ex.e_shnum * sizeof (Elf32_Shdr), "sh"); 126 /* Read in the section string table. */ 127 shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset, 128 sh [ex.e_shstrndx].sh_size, "shstrtab"); 129 130 /* Figure out if we can cram the program header into an ECOFF 131 header... Basically, we can't handle anything but loadable 132 segments, but we can ignore some kinds of segments. We can't 133 handle holes in the address space. Segments may be out of order, 134 so we sort them first. */ 135 136 qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp); 137 138 for (i = 0; i < ex.e_phnum; i++) 139 { 140 /* Section types we can ignore... */ 141 if (ph [i].p_type == Elf_pt_null || ph [i].p_type == Elf_pt_note || 142 ph [i].p_type == Elf_pt_phdr || ph [i].p_type == Elf_pt_mips_reginfo) 143 continue; 144 /* Section types we can't handle... */ 145 else if (ph [i].p_type != Elf_pt_load) 146 { 147 fprintf (stderr, "Program header %d type %d can't be converted.\n"); 148 exit (1); 149 } 150 /* Writable (data) segment? */ 151 if (ph [i].p_flags & PF_W) 152 { 153 struct sect ndata, nbss; 154 155 ndata.vaddr = ph [i].p_vaddr; 156 ndata.len = ph [i].p_filesz; 157 nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz; 158 nbss.len = ph [i].p_memsz - ph [i].p_filesz; 159 160 combine (&data, &ndata, 0); 161 combine (&bss, &nbss, 1); 162 } 163 else 164 { 165 struct sect ntxt; 166 167 ntxt.vaddr = ph [i].p_vaddr; 168 ntxt.len = ph [i].p_filesz; 169 170 combine (&text, &ntxt); 171 } 172 /* Remember the lowest segment start address. */ 173 if (ph [i].p_vaddr < cur_vma) 174 cur_vma = ph [i].p_vaddr; 175 } 176 177 /* Sections must be in order to be converted... */ 178 if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || 179 text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) 180 { 181 fprintf (stderr, "Sections ordering prevents a.out conversion.\n"); 182 exit (1); 183 } 184 185 /* If there's a data section but no text section, then the loader 186 combined everything into one section. That needs to be the 187 text section, so just make the data section zero length following 188 text. */ 189 if (data.len && !text.len) 190 { 191 text = data; 192 data.vaddr = text.vaddr + text.len; 193 data.len = 0; 194 } 195 196 /* If there is a gap between text and data, we'll fill it when we copy 197 the data, so update the length of the text segment as represented in 198 a.out to reflect that, since a.out doesn't allow gaps in the program 199 address space. */ 200 if (text.vaddr + text.len < data.vaddr) 201 text.len = data.vaddr - text.vaddr; 202 203 /* We now have enough information to cons up an a.out header... */ 204 ep.a.magic = ECOFF_OMAGIC; 205 ep.a.vstamp = 200; 206 ep.a.tsize = text.len; 207 ep.a.dsize = data.len; 208 ep.a.bsize = bss.len; 209 ep.a.entry = ex.e_entry; 210 ep.a.text_start = text.vaddr; 211 ep.a.data_start = data.vaddr; 212 ep.a.bss_start = bss.vaddr; 213 ep.a.gprmask = 0xf3fffffe; 214 bzero (&ep.a.cprmask, sizeof ep.a.cprmask); 215 ep.a.gp_value = 0; /* unused. */ 216 217 ep.f.f_magic = ECOFF_MAGIC_MIPSEL; 218 ep.f.f_nscns = 3; 219 ep.f.f_timdat = 0; /* bogus */ 220 ep.f.f_symptr = 0; 221 ep.f.f_nsyms = 0; 222 ep.f.f_opthdr = sizeof ep.a; 223 ep.f.f_flags = 0x100f; /* Stripped, not sharable. */ 224 225 strcpy (esecs [0].s_name, ".text"); 226 strcpy (esecs [1].s_name, ".data"); 227 strcpy (esecs [2].s_name, ".bss"); 228 esecs [0].s_paddr = esecs [0].s_vaddr = ep.a.text_start; 229 esecs [1].s_paddr = esecs [1].s_vaddr = ep.a.data_start; 230 esecs [2].s_paddr = esecs [2].s_vaddr = ep.a.bss_start; 231 esecs [0].s_size = ep.a.tsize; 232 esecs [1].s_size = ep.a.dsize; 233 esecs [2].s_size = ep.a.bsize; 234 235 esecs [0].s_scnptr = ECOFF_TXTOFF (&ep); 236 esecs [1].s_scnptr = ECOFF_DATOFF (&ep); 237 esecs [2].s_scnptr = esecs [1].s_scnptr + 238 ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&ep)); 239 esecs [0].s_relptr = esecs [1].s_relptr 240 = esecs [2].s_relptr = 0; 241 esecs [0].s_lnnoptr = esecs [1].s_lnnoptr 242 = esecs [2].s_lnnoptr = 0; 243 esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0; 244 esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0; 245 esecs [0].s_flags = 0x20; 246 esecs [1].s_flags = 0x40; 247 esecs [2].s_flags = 0x82; 248 249 /* Make the output file... */ 250 if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0) 251 { 252 fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno)); 253 exit (1); 254 } 255 256 /* Write the headers... */ 257 i = write (outfile, &ep.f, sizeof ep.f); 258 if (i != sizeof ep.f) 259 { 260 perror ("ep.f: write"); 261 exit (1); 262 263 for (i = 0; i < 6; i++) 264 { 265 printf ("Section %d: %s phys %x size %x file offset %x\n", 266 i, esecs [i].s_name, esecs [i].s_paddr, 267 esecs [i].s_size, esecs [i].s_scnptr); 268 } 269 } 270 fprintf (stderr, "wrote %d byte file header.\n", i); 271 272 i = write (outfile, &ep.a, sizeof ep.a); 273 if (i != sizeof ep.a) 274 { 275 perror ("ep.a: write"); 276 exit (1); 277 } 278 fprintf (stderr, "wrote %d byte a.out header.\n", i); 279 280 i = write (outfile, &esecs, sizeof esecs); 281 if (i != sizeof esecs) 282 { 283 perror ("esecs: write"); 284 exit (1); 285 } 286 fprintf (stderr, "wrote %d bytes of section headers.\n", i); 287 288 if (pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15)) 289 { 290 pad = 16 - pad; 291 i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad); 292 if (i < 0) 293 { 294 perror ("ipad: write"); 295 exit (1); 296 } 297 fprintf (stderr, "wrote %d byte pad.\n", i); 298 } 299 300 /* Copy the loadable sections. Zero-fill any gaps less than 64k; 301 complain about any zero-filling, and die if we're asked to zero-fill 302 more than 64k. */ 303 for (i = 0; i < ex.e_phnum; i++) 304 { 305 /* Unprocessable sections were handled above, so just verify that 306 the section can be loaded before copying. */ 307 if (ph [i].p_type == Elf_pt_load && ph [i].p_filesz) 308 { 309 if (cur_vma != ph [i].p_vaddr) 310 { 311 unsigned long gap = ph [i].p_vaddr - cur_vma; 312 char obuf [1024]; 313 if (gap > 65536) 314 { 315 fprintf (stderr, "Intersegment gap (%d bytes) too large.\n", 316 gap); 317 exit (1); 318 } 319 fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap); 320 memset (obuf, 0, sizeof obuf); 321 while (gap) 322 { 323 int count = write (outfile, obuf, (gap > sizeof obuf 324 ? sizeof obuf : gap)); 325 if (count < 0) 326 { 327 fprintf (stderr, "Error writing gap: %s\n", 328 strerror (errno)); 329 exit (1); 330 } 331 gap -= count; 332 } 333 } 334fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz); 335 copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz); 336 cur_vma = ph [i].p_vaddr + ph [i].p_filesz; 337 } 338 } 339 340 /* Looks like we won... */ 341 exit (0); 342} 343 344copy (out, in, offset, size) 345 int out, in; 346 off_t offset, size; 347{ 348 char ibuf [4096]; 349 int remaining, cur, count; 350 351 /* Go the the start of the ELF symbol table... */ 352 if (lseek (in, offset, SEEK_SET) < 0) 353 { 354 perror ("copy: lseek"); 355 exit (1); 356 } 357 358 remaining = size; 359 while (remaining) 360 { 361 cur = remaining; 362 if (cur > sizeof ibuf) 363 cur = sizeof ibuf; 364 remaining -= cur; 365 if ((count = read (in, ibuf, cur)) != cur) 366 { 367 fprintf (stderr, "copy: read: %s\n", 368 count ? strerror (errno) : "premature end of file"); 369 exit (1); 370 } 371 if ((count = write (out, ibuf, cur)) != cur) 372 { 373 perror ("copy: write"); 374 exit (1); 375 } 376 } 377} 378 379/* Combine two segments, which must be contiguous. If pad is true, it's 380 okay for there to be padding between. */ 381combine (base, new, pad) 382 struct sect *base, *new; 383 int pad; 384{ 385 if (!base -> len) 386 *base = *new; 387 else if (new -> len) 388 { 389 if (base -> vaddr + base -> len != new -> vaddr) 390 { 391 if (pad) 392 base -> len = new -> vaddr - base -> vaddr; 393 else 394 { 395 fprintf (stderr, 396 "Non-contiguous data can't be converted.\n"); 397 exit (1); 398 } 399 } 400 base -> len += new -> len; 401 } 402} 403 404int 405phcmp (h1, h2) 406 Elf32_Phdr *h1, *h2; 407{ 408 if (h1 -> p_vaddr > h2 -> p_vaddr) 409 return 1; 410 else if (h1 -> p_vaddr < h2 -> p_vaddr) 411 return -1; 412 else 413 return 0; 414} 415 416char *saveRead (int file, off_t offset, off_t len, char *name) 417{ 418 char *tmp; 419 int count; 420 off_t off; 421 if ((off = lseek (file, offset, SEEK_SET)) < 0) 422 { 423 fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno)); 424 exit (1); 425 } 426 if (!(tmp = (char *)malloc (len))) 427 { 428 fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len); 429 exit (1); 430 } 431 count = read (file, tmp, len); 432 if (count != len) 433 { 434 fprintf (stderr, "%s: read: %s.\n", 435 name, count ? strerror (errno) : "End of file reached"); 436 exit (1); 437 } 438 return tmp; 439} 440