Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/boot/elf2ecoff.c
10820 views
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
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)
318
must_convert_endian = 1;
319
} else {
320
if (format_bigendian)
321
must_convert_endian = 1;
322
}
323
if (must_convert_endian)
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");
330
if (must_convert_endian)
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");
336
if (must_convert_endian)
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
507
if (must_convert_endian)
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
524
if (must_convert_endian)
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
533
if (must_convert_endian)
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
}
617
618