Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
elf2ecoff.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1995
3  * Ted Lemon (hereinafter referred to as the author)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /* elf2ecoff.c
30 
31  This program converts an elf executable to an ECOFF executable.
32  No symbol table is retained. This is useful primarily in building
33  net-bootable kernels for machines (e.g., DECstation and Alpha) which
34  only support the ECOFF object file format. */
35 
36 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <elf.h>
43 #include <limits.h>
44 #include <netinet/in.h>
45 #include <stdlib.h>
46 
47 #include "ecoff.h"
48 
49 /*
50  * Some extra ELF definitions
51  */
52 #define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
53 
54 /* -------------------------------------------------------------------- */
55 
56 struct sect {
57  unsigned long vaddr;
58  unsigned long len;
59 };
60 
64 
65 static void copy(int out, int in, off_t offset, off_t size)
66 {
67  char ibuf[4096];
68  int remaining, cur, count;
69 
70  /* Go to the start of the ELF symbol table... */
71  if (lseek(in, offset, SEEK_SET) < 0) {
72  perror("copy: lseek");
73  exit(1);
74  }
75 
76  remaining = size;
77  while (remaining) {
78  cur = remaining;
79  if (cur > sizeof ibuf)
80  cur = sizeof ibuf;
81  remaining -= cur;
82  if ((count = read(in, ibuf, cur)) != cur) {
83  fprintf(stderr, "copy: read: %s\n",
84  count ? strerror(errno) :
85  "premature end of file");
86  exit(1);
87  }
88  if ((count = write(out, ibuf, cur)) != cur) {
89  perror("copy: write");
90  exit(1);
91  }
92  }
93 }
94 
95 /*
96  * Combine two segments, which must be contiguous. If pad is true, it's
97  * okay for there to be padding between.
98  */
99 static void combine(struct sect *base, struct sect *new, int pad)
100 {
101  if (!base->len)
102  *base = *new;
103  else if (new->len) {
104  if (base->vaddr + base->len != new->vaddr) {
105  if (pad)
106  base->len = new->vaddr - base->vaddr;
107  else {
108  fprintf(stderr,
109  "Non-contiguous data can't be converted.\n");
110  exit(1);
111  }
112  }
113  base->len += new->len;
114  }
115 }
116 
117 static int phcmp(const void *v1, const void *v2)
118 {
119  const Elf32_Phdr *h1 = v1;
120  const Elf32_Phdr *h2 = v2;
121 
122  if (h1->p_vaddr > h2->p_vaddr)
123  return 1;
124  else if (h1->p_vaddr < h2->p_vaddr)
125  return -1;
126  else
127  return 0;
128 }
129 
130 static char *saveRead(int file, off_t offset, off_t len, char *name)
131 {
132  char *tmp;
133  int count;
134  off_t off;
135  if ((off = lseek(file, offset, SEEK_SET)) < 0) {
136  fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
137  exit(1);
138  }
139  if (!(tmp = (char *) malloc(len))) {
140  fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
141  len);
142  exit(1);
143  }
144  count = read(file, tmp, len);
145  if (count != len) {
146  fprintf(stderr, "%s: read: %s.\n",
147  name,
148  count ? strerror(errno) : "End of file reached");
149  exit(1);
150  }
151  return tmp;
152 }
153 
154 #define swab16(x) \
155  ((unsigned short)( \
156  (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \
157  (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) ))
158 
159 #define swab32(x) \
160  ((unsigned int)( \
161  (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
162  (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \
163  (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \
164  (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
165 
166 static void convert_elf_hdr(Elf32_Ehdr * e)
167 {
168  e->e_type = swab16(e->e_type);
169  e->e_machine = swab16(e->e_machine);
170  e->e_version = swab32(e->e_version);
171  e->e_entry = swab32(e->e_entry);
172  e->e_phoff = swab32(e->e_phoff);
173  e->e_shoff = swab32(e->e_shoff);
174  e->e_flags = swab32(e->e_flags);
175  e->e_ehsize = swab16(e->e_ehsize);
176  e->e_phentsize = swab16(e->e_phentsize);
177  e->e_phnum = swab16(e->e_phnum);
178  e->e_shentsize = swab16(e->e_shentsize);
179  e->e_shnum = swab16(e->e_shnum);
180  e->e_shstrndx = swab16(e->e_shstrndx);
181 }
182 
183 static void convert_elf_phdrs(Elf32_Phdr * p, int num)
184 {
185  int i;
186 
187  for (i = 0; i < num; i++, p++) {
188  p->p_type = swab32(p->p_type);
189  p->p_offset = swab32(p->p_offset);
190  p->p_vaddr = swab32(p->p_vaddr);
191  p->p_paddr = swab32(p->p_paddr);
192  p->p_filesz = swab32(p->p_filesz);
193  p->p_memsz = swab32(p->p_memsz);
194  p->p_flags = swab32(p->p_flags);
195  p->p_align = swab32(p->p_align);
196  }
197 
198 }
199 
200 static void convert_elf_shdrs(Elf32_Shdr * s, int num)
201 {
202  int i;
203 
204  for (i = 0; i < num; i++, s++) {
205  s->sh_name = swab32(s->sh_name);
206  s->sh_type = swab32(s->sh_type);
207  s->sh_flags = swab32(s->sh_flags);
208  s->sh_addr = swab32(s->sh_addr);
209  s->sh_offset = swab32(s->sh_offset);
210  s->sh_size = swab32(s->sh_size);
211  s->sh_link = swab32(s->sh_link);
212  s->sh_info = swab32(s->sh_info);
214  s->sh_entsize = swab32(s->sh_entsize);
215  }
216 }
217 
218 static void convert_ecoff_filehdr(struct filehdr *f)
219 {
220  f->f_magic = swab16(f->f_magic);
221  f->f_nscns = swab16(f->f_nscns);
222  f->f_timdat = swab32(f->f_timdat);
223  f->f_symptr = swab32(f->f_symptr);
224  f->f_nsyms = swab32(f->f_nsyms);
225  f->f_opthdr = swab16(f->f_opthdr);
226  f->f_flags = swab16(f->f_flags);
227 }
228 
229 static void convert_ecoff_aouthdr(struct aouthdr *a)
230 {
231  a->magic = swab16(a->magic);
232  a->vstamp = swab16(a->vstamp);
233  a->tsize = swab32(a->tsize);
234  a->dsize = swab32(a->dsize);
235  a->bsize = swab32(a->bsize);
236  a->entry = swab32(a->entry);
237  a->text_start = swab32(a->text_start);
238  a->data_start = swab32(a->data_start);
239  a->bss_start = swab32(a->bss_start);
240  a->gprmask = swab32(a->gprmask);
241  a->cprmask[0] = swab32(a->cprmask[0]);
242  a->cprmask[1] = swab32(a->cprmask[1]);
243  a->cprmask[2] = swab32(a->cprmask[2]);
244  a->cprmask[3] = swab32(a->cprmask[3]);
245  a->gp_value = swab32(a->gp_value);
246 }
247 
248 static void convert_ecoff_esecs(struct scnhdr *s, int num)
249 {
250  int i;
251 
252  for (i = 0; i < num; i++, s++) {
253  s->s_paddr = swab32(s->s_paddr);
254  s->s_vaddr = swab32(s->s_vaddr);
255  s->s_size = swab32(s->s_size);
256  s->s_scnptr = swab32(s->s_scnptr);
257  s->s_relptr = swab32(s->s_relptr);
258  s->s_lnnoptr = swab32(s->s_lnnoptr);
259  s->s_nreloc = swab16(s->s_nreloc);
260  s->s_nlnno = swab16(s->s_nlnno);
261  s->s_flags = swab32(s->s_flags);
262  }
263 }
264 
265 int main(int argc, char *argv[])
266 {
267  Elf32_Ehdr ex;
268  Elf32_Phdr *ph;
269  Elf32_Shdr *sh;
270  char *shstrtab;
271  int i, pad;
272  struct sect text, data, bss;
273  struct filehdr efh;
274  struct aouthdr eah;
275  struct scnhdr esecs[6];
276  int infile, outfile;
277  unsigned long cur_vma = ULONG_MAX;
278  int addflag = 0;
279  int nosecs;
280 
281  text.len = data.len = bss.len = 0;
282  text.vaddr = data.vaddr = bss.vaddr = 0;
283 
284  /* Check args... */
285  if (argc < 3 || argc > 4) {
286  usage:
287  fprintf(stderr,
288  "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
289  exit(1);
290  }
291  if (argc == 4) {
292  if (strcmp(argv[3], "-a"))
293  goto usage;
294  addflag = 1;
295  }
296 
297  /* Try the input file... */
298  if ((infile = open(argv[1], O_RDONLY)) < 0) {
299  fprintf(stderr, "Can't open %s for read: %s\n",
300  argv[1], strerror(errno));
301  exit(1);
302  }
303 
304  /* Read the header, which is at the beginning of the file... */
305  i = read(infile, &ex, sizeof ex);
306  if (i != sizeof ex) {
307  fprintf(stderr, "ex: %s: %s.\n",
308  argv[1],
309  i ? strerror(errno) : "End of file reached");
310  exit(1);
311  }
312 
313  if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
314  format_bigendian = 1;
315 
316  if (ntohs(0xaa55) == 0xaa55) {
317  if (!format_bigendian)
319  } else {
320  if (format_bigendian)
322  }
324  convert_elf_hdr(&ex);
325 
326  /* Read the program headers... */
327  ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
328  ex.e_phnum * sizeof(Elf32_Phdr),
329  "ph");
331  convert_elf_phdrs(ph, ex.e_phnum);
332  /* Read the section headers... */
333  sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
334  ex.e_shnum * sizeof(Elf32_Shdr),
335  "sh");
337  convert_elf_shdrs(sh, ex.e_shnum);
338  /* Read in the section string table. */
339  shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
340  sh[ex.e_shstrndx].sh_size, "shstrtab");
341 
342  /* Figure out if we can cram the program header into an ECOFF
343  header... Basically, we can't handle anything but loadable
344  segments, but we can ignore some kinds of segments. We can't
345  handle holes in the address space. Segments may be out of order,
346  so we sort them first. */
347 
348  qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
349 
350  for (i = 0; i < ex.e_phnum; i++) {
351  /* Section types we can ignore... */
352  if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
353  ph[i].p_type == PT_PHDR
354  || ph[i].p_type == PT_MIPS_REGINFO)
355  continue;
356  /* Section types we can't handle... */
357  else if (ph[i].p_type != PT_LOAD) {
358  fprintf(stderr,
359  "Program header %d type %d can't be converted.\n",
360  ex.e_phnum, ph[i].p_type);
361  exit(1);
362  }
363  /* Writable (data) segment? */
364  if (ph[i].p_flags & PF_W) {
365  struct sect ndata, nbss;
366 
367  ndata.vaddr = ph[i].p_vaddr;
368  ndata.len = ph[i].p_filesz;
369  nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
370  nbss.len = ph[i].p_memsz - ph[i].p_filesz;
371 
372  combine(&data, &ndata, 0);
373  combine(&bss, &nbss, 1);
374  } else {
375  struct sect ntxt;
376 
377  ntxt.vaddr = ph[i].p_vaddr;
378  ntxt.len = ph[i].p_filesz;
379 
380  combine(&text, &ntxt, 0);
381  }
382  /* Remember the lowest segment start address. */
383  if (ph[i].p_vaddr < cur_vma)
384  cur_vma = ph[i].p_vaddr;
385  }
386 
387  /* Sections must be in order to be converted... */
388  if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
389  text.vaddr + text.len > data.vaddr
390  || data.vaddr + data.len > bss.vaddr) {
391  fprintf(stderr,
392  "Sections ordering prevents a.out conversion.\n");
393  exit(1);
394  }
395 
396  /* If there's a data section but no text section, then the loader
397  combined everything into one section. That needs to be the
398  text section, so just make the data section zero length following
399  text. */
400  if (data.len && !text.len) {
401  text = data;
402  data.vaddr = text.vaddr + text.len;
403  data.len = 0;
404  }
405 
406  /* If there is a gap between text and data, we'll fill it when we copy
407  the data, so update the length of the text segment as represented in
408  a.out to reflect that, since a.out doesn't allow gaps in the program
409  address space. */
410  if (text.vaddr + text.len < data.vaddr)
411  text.len = data.vaddr - text.vaddr;
412 
413  /* We now have enough information to cons up an a.out header... */
414  eah.magic = OMAGIC;
415  eah.vstamp = 200;
416  eah.tsize = text.len;
417  eah.dsize = data.len;
418  eah.bsize = bss.len;
419  eah.entry = ex.e_entry;
420  eah.text_start = text.vaddr;
421  eah.data_start = data.vaddr;
422  eah.bss_start = bss.vaddr;
423  eah.gprmask = 0xf3fffffe;
424  memset(&eah.cprmask, '\0', sizeof eah.cprmask);
425  eah.gp_value = 0; /* unused. */
426 
427  if (format_bigendian)
428  efh.f_magic = MIPSEBMAGIC;
429  else
430  efh.f_magic = MIPSELMAGIC;
431  if (addflag)
432  nosecs = 6;
433  else
434  nosecs = 3;
435  efh.f_nscns = nosecs;
436  efh.f_timdat = 0; /* bogus */
437  efh.f_symptr = 0;
438  efh.f_nsyms = 0;
439  efh.f_opthdr = sizeof eah;
440  efh.f_flags = 0x100f; /* Stripped, not sharable. */
441 
442  memset(esecs, 0, sizeof esecs);
443  strcpy(esecs[0].s_name, ".text");
444  strcpy(esecs[1].s_name, ".data");
445  strcpy(esecs[2].s_name, ".bss");
446  if (addflag) {
447  strcpy(esecs[3].s_name, ".rdata");
448  strcpy(esecs[4].s_name, ".sdata");
449  strcpy(esecs[5].s_name, ".sbss");
450  }
451  esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
452  esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
453  esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
454  if (addflag) {
455  esecs[3].s_paddr = esecs[3].s_vaddr = 0;
456  esecs[4].s_paddr = esecs[4].s_vaddr = 0;
457  esecs[5].s_paddr = esecs[5].s_vaddr = 0;
458  }
459  esecs[0].s_size = eah.tsize;
460  esecs[1].s_size = eah.dsize;
461  esecs[2].s_size = eah.bsize;
462  if (addflag) {
463  esecs[3].s_size = 0;
464  esecs[4].s_size = 0;
465  esecs[5].s_size = 0;
466  }
467  esecs[0].s_scnptr = N_TXTOFF(efh, eah);
468  esecs[1].s_scnptr = N_DATOFF(efh, eah);
469 #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
470 #define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
471  esecs[2].s_scnptr = esecs[1].s_scnptr +
472  ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
473  if (addflag) {
474  esecs[3].s_scnptr = 0;
475  esecs[4].s_scnptr = 0;
476  esecs[5].s_scnptr = 0;
477  }
478  esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
479  esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
480  esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
481  esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
482  if (addflag) {
483  esecs[3].s_relptr = esecs[4].s_relptr
484  = esecs[5].s_relptr = 0;
485  esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
486  = esecs[5].s_lnnoptr = 0;
487  esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
488  0;
489  esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
490  }
491  esecs[0].s_flags = 0x20;
492  esecs[1].s_flags = 0x40;
493  esecs[2].s_flags = 0x82;
494  if (addflag) {
495  esecs[3].s_flags = 0x100;
496  esecs[4].s_flags = 0x200;
497  esecs[5].s_flags = 0x400;
498  }
499 
500  /* Make the output file... */
501  if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
502  fprintf(stderr, "Unable to create %s: %s\n", argv[2],
503  strerror(errno));
504  exit(1);
505  }
506 
508  convert_ecoff_filehdr(&efh);
509  /* Write the headers... */
510  i = write(outfile, &efh, sizeof efh);
511  if (i != sizeof efh) {
512  perror("efh: write");
513  exit(1);
514 
515  for (i = 0; i < nosecs; i++) {
516  printf
517  ("Section %d: %s phys %lx size %lx file offset %lx\n",
518  i, esecs[i].s_name, esecs[i].s_paddr,
519  esecs[i].s_size, esecs[i].s_scnptr);
520  }
521  }
522  fprintf(stderr, "wrote %d byte file header.\n", i);
523 
525  convert_ecoff_aouthdr(&eah);
526  i = write(outfile, &eah, sizeof eah);
527  if (i != sizeof eah) {
528  perror("eah: write");
529  exit(1);
530  }
531  fprintf(stderr, "wrote %d byte a.out header.\n", i);
532 
534  convert_ecoff_esecs(&esecs[0], nosecs);
535  i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
536  if (i != nosecs * sizeof(struct scnhdr)) {
537  perror("esecs: write");
538  exit(1);
539  }
540  fprintf(stderr, "wrote %d bytes of section headers.\n", i);
541 
542  pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
543  if (pad) {
544  pad = 16 - pad;
545  i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
546  if (i < 0) {
547  perror("ipad: write");
548  exit(1);
549  }
550  fprintf(stderr, "wrote %d byte pad.\n", i);
551  }
552 
553  /*
554  * Copy the loadable sections. Zero-fill any gaps less than 64k;
555  * complain about any zero-filling, and die if we're asked to zero-fill
556  * more than 64k.
557  */
558  for (i = 0; i < ex.e_phnum; i++) {
559  /* Unprocessable sections were handled above, so just verify that
560  the section can be loaded before copying. */
561  if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
562  if (cur_vma != ph[i].p_vaddr) {
563  unsigned long gap =
564  ph[i].p_vaddr - cur_vma;
565  char obuf[1024];
566  if (gap > 65536) {
567  fprintf(stderr,
568  "Intersegment gap (%ld bytes) too large.\n",
569  gap);
570  exit(1);
571  }
572  fprintf(stderr,
573  "Warning: %ld byte intersegment gap.\n",
574  gap);
575  memset(obuf, 0, sizeof obuf);
576  while (gap) {
577  int count =
578  write(outfile, obuf,
579  (gap >
580  sizeof obuf ? sizeof
581  obuf : gap));
582  if (count < 0) {
583  fprintf(stderr,
584  "Error writing gap: %s\n",
585  strerror(errno));
586  exit(1);
587  }
588  gap -= count;
589  }
590  }
591  fprintf(stderr, "writing %d bytes...\n",
592  ph[i].p_filesz);
593  copy(outfile, infile, ph[i].p_offset,
594  ph[i].p_filesz);
595  cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
596  }
597  }
598 
599  /*
600  * Write a page of padding for boot PROMS that read entire pages.
601  * Without this, they may attempt to read past the end of the
602  * data section, incur an error, and refuse to boot.
603  */
604  {
605  char obuf[4096];
606  memset(obuf, 0, sizeof obuf);
607  if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
608  fprintf(stderr, "Error writing PROM padding: %s\n",
609  strerror(errno));
610  exit(1);
611  }
612  }
613 
614  /* Looks like we won... */
615  exit(0);
616 }