OSDN Git Service

MIPS: elf2ecoff: Fix warning due to dead code.
[uclinux-h8/linux.git] / arch / mips / boot / elf2ecoff.c
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
61 int *symTypeTable;
62 int must_convert_endian;
63 int format_bigendian;
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);
213                 s->sh_addralign = swab32(s->sh_addralign);
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         int i, pad;
271         struct sect text, data, bss;
272         struct filehdr efh;
273         struct aouthdr eah;
274         struct scnhdr esecs[6];
275         int infile, outfile;
276         unsigned long cur_vma = ULONG_MAX;
277         int addflag = 0;
278         int nosecs;
279
280         text.len = data.len = bss.len = 0;
281         text.vaddr = data.vaddr = bss.vaddr = 0;
282
283         /* Check args... */
284         if (argc < 3 || argc > 4) {
285               usage:
286                 fprintf(stderr,
287                         "usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
288                 exit(1);
289         }
290         if (argc == 4) {
291                 if (strcmp(argv[3], "-a"))
292                         goto usage;
293                 addflag = 1;
294         }
295
296         /* Try the input file... */
297         if ((infile = open(argv[1], O_RDONLY)) < 0) {
298                 fprintf(stderr, "Can't open %s for read: %s\n",
299                         argv[1], strerror(errno));
300                 exit(1);
301         }
302
303         /* Read the header, which is at the beginning of the file... */
304         i = read(infile, &ex, sizeof ex);
305         if (i != sizeof ex) {
306                 fprintf(stderr, "ex: %s: %s.\n",
307                         argv[1],
308                         i ? strerror(errno) : "End of file reached");
309                 exit(1);
310         }
311
312         if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
313                 format_bigendian = 1;
314
315         if (ntohs(0xaa55) == 0xaa55) {
316                 if (!format_bigendian)
317                         must_convert_endian = 1;
318         } else {
319                 if (format_bigendian)
320                         must_convert_endian = 1;
321         }
322         if (must_convert_endian)
323                 convert_elf_hdr(&ex);
324
325         /* Read the program headers... */
326         ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
327                                      ex.e_phnum * sizeof(Elf32_Phdr),
328                                      "ph");
329         if (must_convert_endian)
330                 convert_elf_phdrs(ph, ex.e_phnum);
331         /* Read the section headers... */
332         sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
333                                      ex.e_shnum * sizeof(Elf32_Shdr),
334                                      "sh");
335         if (must_convert_endian)
336                 convert_elf_shdrs(sh, ex.e_shnum);
337
338         /* Figure out if we can cram the program header into an ECOFF
339            header...  Basically, we can't handle anything but loadable
340            segments, but we can ignore some kinds of segments.  We can't
341            handle holes in the address space.  Segments may be out of order,
342            so we sort them first. */
343
344         qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
345
346         for (i = 0; i < ex.e_phnum; i++) {
347                 /* Section types we can ignore... */
348                 if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
349                     ph[i].p_type == PT_PHDR
350                     || ph[i].p_type == PT_MIPS_REGINFO)
351                         continue;
352                 /* Section types we can't handle... */
353                 else if (ph[i].p_type != PT_LOAD) {
354                         fprintf(stderr,
355                                 "Program header %d type %d can't be converted.\n",
356                                 ex.e_phnum, ph[i].p_type);
357                         exit(1);
358                 }
359                 /* Writable (data) segment? */
360                 if (ph[i].p_flags & PF_W) {
361                         struct sect ndata, nbss;
362
363                         ndata.vaddr = ph[i].p_vaddr;
364                         ndata.len = ph[i].p_filesz;
365                         nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
366                         nbss.len = ph[i].p_memsz - ph[i].p_filesz;
367
368                         combine(&data, &ndata, 0);
369                         combine(&bss, &nbss, 1);
370                 } else {
371                         struct sect ntxt;
372
373                         ntxt.vaddr = ph[i].p_vaddr;
374                         ntxt.len = ph[i].p_filesz;
375
376                         combine(&text, &ntxt, 0);
377                 }
378                 /* Remember the lowest segment start address. */
379                 if (ph[i].p_vaddr < cur_vma)
380                         cur_vma = ph[i].p_vaddr;
381         }
382
383         /* Sections must be in order to be converted... */
384         if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
385             text.vaddr + text.len > data.vaddr
386             || data.vaddr + data.len > bss.vaddr) {
387                 fprintf(stderr,
388                         "Sections ordering prevents a.out conversion.\n");
389                 exit(1);
390         }
391
392         /* If there's a data section but no text section, then the loader
393            combined everything into one section.   That needs to be the
394            text section, so just make the data section zero length following
395            text. */
396         if (data.len && !text.len) {
397                 text = data;
398                 data.vaddr = text.vaddr + text.len;
399                 data.len = 0;
400         }
401
402         /* If there is a gap between text and data, we'll fill it when we copy
403            the data, so update the length of the text segment as represented in
404            a.out to reflect that, since a.out doesn't allow gaps in the program
405            address space. */
406         if (text.vaddr + text.len < data.vaddr)
407                 text.len = data.vaddr - text.vaddr;
408
409         /* We now have enough information to cons up an a.out header... */
410         eah.magic = OMAGIC;
411         eah.vstamp = 200;
412         eah.tsize = text.len;
413         eah.dsize = data.len;
414         eah.bsize = bss.len;
415         eah.entry = ex.e_entry;
416         eah.text_start = text.vaddr;
417         eah.data_start = data.vaddr;
418         eah.bss_start = bss.vaddr;
419         eah.gprmask = 0xf3fffffe;
420         memset(&eah.cprmask, '\0', sizeof eah.cprmask);
421         eah.gp_value = 0;       /* unused. */
422
423         if (format_bigendian)
424                 efh.f_magic = MIPSEBMAGIC;
425         else
426                 efh.f_magic = MIPSELMAGIC;
427         if (addflag)
428                 nosecs = 6;
429         else
430                 nosecs = 3;
431         efh.f_nscns = nosecs;
432         efh.f_timdat = 0;       /* bogus */
433         efh.f_symptr = 0;
434         efh.f_nsyms = 0;
435         efh.f_opthdr = sizeof eah;
436         efh.f_flags = 0x100f;   /* Stripped, not sharable. */
437
438         memset(esecs, 0, sizeof esecs);
439         strcpy(esecs[0].s_name, ".text");
440         strcpy(esecs[1].s_name, ".data");
441         strcpy(esecs[2].s_name, ".bss");
442         if (addflag) {
443                 strcpy(esecs[3].s_name, ".rdata");
444                 strcpy(esecs[4].s_name, ".sdata");
445                 strcpy(esecs[5].s_name, ".sbss");
446         }
447         esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
448         esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
449         esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
450         if (addflag) {
451                 esecs[3].s_paddr = esecs[3].s_vaddr = 0;
452                 esecs[4].s_paddr = esecs[4].s_vaddr = 0;
453                 esecs[5].s_paddr = esecs[5].s_vaddr = 0;
454         }
455         esecs[0].s_size = eah.tsize;
456         esecs[1].s_size = eah.dsize;
457         esecs[2].s_size = eah.bsize;
458         if (addflag) {
459                 esecs[3].s_size = 0;
460                 esecs[4].s_size = 0;
461                 esecs[5].s_size = 0;
462         }
463         esecs[0].s_scnptr = N_TXTOFF(efh, eah);
464         esecs[1].s_scnptr = N_DATOFF(efh, eah);
465 #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
466 #define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
467         esecs[2].s_scnptr = esecs[1].s_scnptr +
468             ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
469         if (addflag) {
470                 esecs[3].s_scnptr = 0;
471                 esecs[4].s_scnptr = 0;
472                 esecs[5].s_scnptr = 0;
473         }
474         esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
475         esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
476         esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
477         esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
478         if (addflag) {
479                 esecs[3].s_relptr = esecs[4].s_relptr
480                     = esecs[5].s_relptr = 0;
481                 esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
482                     = esecs[5].s_lnnoptr = 0;
483                 esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
484                     0;
485                 esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
486         }
487         esecs[0].s_flags = 0x20;
488         esecs[1].s_flags = 0x40;
489         esecs[2].s_flags = 0x82;
490         if (addflag) {
491                 esecs[3].s_flags = 0x100;
492                 esecs[4].s_flags = 0x200;
493                 esecs[5].s_flags = 0x400;
494         }
495
496         /* Make the output file... */
497         if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
498                 fprintf(stderr, "Unable to create %s: %s\n", argv[2],
499                         strerror(errno));
500                 exit(1);
501         }
502
503         if (must_convert_endian)
504                 convert_ecoff_filehdr(&efh);
505         /* Write the headers... */
506         i = write(outfile, &efh, sizeof efh);
507         if (i != sizeof efh) {
508                 perror("efh: write");
509                 exit(1);
510
511                 for (i = 0; i < nosecs; i++) {
512                         printf
513                             ("Section %d: %s phys %lx  size %lx  file offset %lx\n",
514                              i, esecs[i].s_name, esecs[i].s_paddr,
515                              esecs[i].s_size, esecs[i].s_scnptr);
516                 }
517         }
518         fprintf(stderr, "wrote %d byte file header.\n", i);
519
520         if (must_convert_endian)
521                 convert_ecoff_aouthdr(&eah);
522         i = write(outfile, &eah, sizeof eah);
523         if (i != sizeof eah) {
524                 perror("eah: write");
525                 exit(1);
526         }
527         fprintf(stderr, "wrote %d byte a.out header.\n", i);
528
529         if (must_convert_endian)
530                 convert_ecoff_esecs(&esecs[0], nosecs);
531         i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
532         if (i != nosecs * sizeof(struct scnhdr)) {
533                 perror("esecs: write");
534                 exit(1);
535         }
536         fprintf(stderr, "wrote %d bytes of section headers.\n", i);
537
538         pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
539         if (pad) {
540                 pad = 16 - pad;
541                 i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
542                 if (i < 0) {
543                         perror("ipad: write");
544                         exit(1);
545                 }
546                 fprintf(stderr, "wrote %d byte pad.\n", i);
547         }
548
549         /*
550          * Copy the loadable sections.   Zero-fill any gaps less than 64k;
551          * complain about any zero-filling, and die if we're asked to zero-fill
552          * more than 64k.
553          */
554         for (i = 0; i < ex.e_phnum; i++) {
555                 /* Unprocessable sections were handled above, so just verify that
556                    the section can be loaded before copying. */
557                 if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
558                         if (cur_vma != ph[i].p_vaddr) {
559                                 unsigned long gap =
560                                     ph[i].p_vaddr - cur_vma;
561                                 char obuf[1024];
562                                 if (gap > 65536) {
563                                         fprintf(stderr,
564                                                 "Intersegment gap (%ld bytes) too large.\n",
565                                                 gap);
566                                         exit(1);
567                                 }
568                                 fprintf(stderr,
569                                         "Warning: %ld byte intersegment gap.\n",
570                                         gap);
571                                 memset(obuf, 0, sizeof obuf);
572                                 while (gap) {
573                                         int count =
574                                             write(outfile, obuf,
575                                                   (gap >
576                                                    sizeof obuf ? sizeof
577                                                    obuf : gap));
578                                         if (count < 0) {
579                                                 fprintf(stderr,
580                                                         "Error writing gap: %s\n",
581                                                         strerror(errno));
582                                                 exit(1);
583                                         }
584                                         gap -= count;
585                                 }
586                         }
587                         fprintf(stderr, "writing %d bytes...\n",
588                                 ph[i].p_filesz);
589                         copy(outfile, infile, ph[i].p_offset,
590                              ph[i].p_filesz);
591                         cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
592                 }
593         }
594
595         /*
596          * Write a page of padding for boot PROMS that read entire pages.
597          * Without this, they may attempt to read past the end of the
598          * data section, incur an error, and refuse to boot.
599          */
600         {
601                 char obuf[4096];
602                 memset(obuf, 0, sizeof obuf);
603                 if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
604                         fprintf(stderr, "Error writing PROM padding: %s\n",
605                                 strerror(errno));
606                         exit(1);
607                 }
608         }
609
610         /* Looks like we won... */
611         exit(0);
612 }