Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/boot/elf2ecoff.c
26424 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
#include <stdint.h>
47
#include <inttypes.h>
48
49
#include "ecoff.h"
50
51
/*
52
* Some extra ELF definitions
53
*/
54
#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
55
#define PT_MIPS_ABIFLAGS 0x70000003 /* Records ABI related flags */
56
57
/* -------------------------------------------------------------------- */
58
59
struct sect {
60
uint32_t vaddr;
61
uint32_t len;
62
};
63
64
int *symTypeTable;
65
int must_convert_endian;
66
int format_bigendian;
67
68
static void copy(int out, int in, off_t offset, off_t size)
69
{
70
char ibuf[4096];
71
int remaining, cur, count;
72
73
/* Go to the start of the ELF symbol table... */
74
if (lseek(in, offset, SEEK_SET) < 0) {
75
perror("copy: lseek");
76
exit(1);
77
}
78
79
remaining = size;
80
while (remaining) {
81
cur = remaining;
82
if (cur > sizeof ibuf)
83
cur = sizeof ibuf;
84
remaining -= cur;
85
if ((count = read(in, ibuf, cur)) != cur) {
86
fprintf(stderr, "copy: read: %s\n",
87
count ? strerror(errno) :
88
"premature end of file");
89
exit(1);
90
}
91
if ((count = write(out, ibuf, cur)) != cur) {
92
perror("copy: write");
93
exit(1);
94
}
95
}
96
}
97
98
/*
99
* Combine two segments, which must be contiguous. If pad is true, it's
100
* okay for there to be padding between.
101
*/
102
static void combine(struct sect *base, struct sect *new, int pad)
103
{
104
if (!base->len)
105
*base = *new;
106
else if (new->len) {
107
if (base->vaddr + base->len != new->vaddr) {
108
if (pad)
109
base->len = new->vaddr - base->vaddr;
110
else {
111
fprintf(stderr,
112
"Non-contiguous data can't be converted.\n");
113
exit(1);
114
}
115
}
116
base->len += new->len;
117
}
118
}
119
120
static int phcmp(const void *v1, const void *v2)
121
{
122
const Elf32_Phdr *h1 = v1;
123
const Elf32_Phdr *h2 = v2;
124
125
if (h1->p_vaddr > h2->p_vaddr)
126
return 1;
127
else if (h1->p_vaddr < h2->p_vaddr)
128
return -1;
129
else
130
return 0;
131
}
132
133
static char *saveRead(int file, off_t offset, off_t len, char *name)
134
{
135
char *tmp;
136
int count;
137
off_t off;
138
if ((off = lseek(file, offset, SEEK_SET)) < 0) {
139
fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
140
exit(1);
141
}
142
if (!(tmp = (char *) malloc(len))) {
143
fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name,
144
len);
145
exit(1);
146
}
147
count = read(file, tmp, len);
148
if (count != len) {
149
fprintf(stderr, "%s: read: %s.\n",
150
name,
151
count ? strerror(errno) : "End of file reached");
152
exit(1);
153
}
154
return tmp;
155
}
156
157
#define swab16(x) \
158
((uint16_t)( \
159
(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
160
(((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
161
162
#define swab32(x) \
163
((unsigned int)( \
164
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
165
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
166
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
167
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
168
169
static void convert_elf_hdr(Elf32_Ehdr * e)
170
{
171
e->e_type = swab16(e->e_type);
172
e->e_machine = swab16(e->e_machine);
173
e->e_version = swab32(e->e_version);
174
e->e_entry = swab32(e->e_entry);
175
e->e_phoff = swab32(e->e_phoff);
176
e->e_shoff = swab32(e->e_shoff);
177
e->e_flags = swab32(e->e_flags);
178
e->e_ehsize = swab16(e->e_ehsize);
179
e->e_phentsize = swab16(e->e_phentsize);
180
e->e_phnum = swab16(e->e_phnum);
181
e->e_shentsize = swab16(e->e_shentsize);
182
e->e_shnum = swab16(e->e_shnum);
183
e->e_shstrndx = swab16(e->e_shstrndx);
184
}
185
186
static void convert_elf_phdrs(Elf32_Phdr * p, int num)
187
{
188
int i;
189
190
for (i = 0; i < num; i++, p++) {
191
p->p_type = swab32(p->p_type);
192
p->p_offset = swab32(p->p_offset);
193
p->p_vaddr = swab32(p->p_vaddr);
194
p->p_paddr = swab32(p->p_paddr);
195
p->p_filesz = swab32(p->p_filesz);
196
p->p_memsz = swab32(p->p_memsz);
197
p->p_flags = swab32(p->p_flags);
198
p->p_align = swab32(p->p_align);
199
}
200
201
}
202
203
static void convert_elf_shdrs(Elf32_Shdr * s, int num)
204
{
205
int i;
206
207
for (i = 0; i < num; i++, s++) {
208
s->sh_name = swab32(s->sh_name);
209
s->sh_type = swab32(s->sh_type);
210
s->sh_flags = swab32(s->sh_flags);
211
s->sh_addr = swab32(s->sh_addr);
212
s->sh_offset = swab32(s->sh_offset);
213
s->sh_size = swab32(s->sh_size);
214
s->sh_link = swab32(s->sh_link);
215
s->sh_info = swab32(s->sh_info);
216
s->sh_addralign = swab32(s->sh_addralign);
217
s->sh_entsize = swab32(s->sh_entsize);
218
}
219
}
220
221
static void convert_ecoff_filehdr(struct filehdr *f)
222
{
223
f->f_magic = swab16(f->f_magic);
224
f->f_nscns = swab16(f->f_nscns);
225
f->f_timdat = swab32(f->f_timdat);
226
f->f_symptr = swab32(f->f_symptr);
227
f->f_nsyms = swab32(f->f_nsyms);
228
f->f_opthdr = swab16(f->f_opthdr);
229
f->f_flags = swab16(f->f_flags);
230
}
231
232
static void convert_ecoff_aouthdr(struct aouthdr *a)
233
{
234
a->magic = swab16(a->magic);
235
a->vstamp = swab16(a->vstamp);
236
a->tsize = swab32(a->tsize);
237
a->dsize = swab32(a->dsize);
238
a->bsize = swab32(a->bsize);
239
a->entry = swab32(a->entry);
240
a->text_start = swab32(a->text_start);
241
a->data_start = swab32(a->data_start);
242
a->bss_start = swab32(a->bss_start);
243
a->gprmask = swab32(a->gprmask);
244
a->cprmask[0] = swab32(a->cprmask[0]);
245
a->cprmask[1] = swab32(a->cprmask[1]);
246
a->cprmask[2] = swab32(a->cprmask[2]);
247
a->cprmask[3] = swab32(a->cprmask[3]);
248
a->gp_value = swab32(a->gp_value);
249
}
250
251
static void convert_ecoff_esecs(struct scnhdr *s, int num)
252
{
253
int i;
254
255
for (i = 0; i < num; i++, s++) {
256
s->s_paddr = swab32(s->s_paddr);
257
s->s_vaddr = swab32(s->s_vaddr);
258
s->s_size = swab32(s->s_size);
259
s->s_scnptr = swab32(s->s_scnptr);
260
s->s_relptr = swab32(s->s_relptr);
261
s->s_lnnoptr = swab32(s->s_lnnoptr);
262
s->s_nreloc = swab16(s->s_nreloc);
263
s->s_nlnno = swab16(s->s_nlnno);
264
s->s_flags = swab32(s->s_flags);
265
}
266
}
267
268
int main(int argc, char *argv[])
269
{
270
Elf32_Ehdr ex;
271
Elf32_Phdr *ph;
272
Elf32_Shdr *sh;
273
int i, pad;
274
struct sect text, data, bss;
275
struct filehdr efh;
276
struct aouthdr eah;
277
struct scnhdr esecs[6];
278
int infile, outfile;
279
uint32_t cur_vma = UINT32_MAX;
280
int addflag = 0;
281
int nosecs;
282
283
text.len = data.len = bss.len = 0;
284
text.vaddr = data.vaddr = bss.vaddr = 0;
285
286
/* Check args... */
287
if (argc < 3 || argc > 4) {
288
usage:
289
fprintf(stderr,
290
"usage: elf2ecoff <elf executable> <ecoff executable> [-a]\n");
291
exit(1);
292
}
293
if (argc == 4) {
294
if (strcmp(argv[3], "-a"))
295
goto usage;
296
addflag = 1;
297
}
298
299
/* Try the input file... */
300
if ((infile = open(argv[1], O_RDONLY)) < 0) {
301
fprintf(stderr, "Can't open %s for read: %s\n",
302
argv[1], strerror(errno));
303
exit(1);
304
}
305
306
/* Read the header, which is at the beginning of the file... */
307
i = read(infile, &ex, sizeof ex);
308
if (i != sizeof ex) {
309
fprintf(stderr, "ex: %s: %s.\n",
310
argv[1],
311
i ? strerror(errno) : "End of file reached");
312
exit(1);
313
}
314
315
if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
316
format_bigendian = 1;
317
318
if (ntohs(0xaa55) == 0xaa55) {
319
if (!format_bigendian)
320
must_convert_endian = 1;
321
} else {
322
if (format_bigendian)
323
must_convert_endian = 1;
324
}
325
if (must_convert_endian)
326
convert_elf_hdr(&ex);
327
328
/* Read the program headers... */
329
ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
330
ex.e_phnum * sizeof(Elf32_Phdr),
331
"ph");
332
if (must_convert_endian)
333
convert_elf_phdrs(ph, ex.e_phnum);
334
/* Read the section headers... */
335
sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
336
ex.e_shnum * sizeof(Elf32_Shdr),
337
"sh");
338
if (must_convert_endian)
339
convert_elf_shdrs(sh, ex.e_shnum);
340
341
/* Figure out if we can cram the program header into an ECOFF
342
header... Basically, we can't handle anything but loadable
343
segments, but we can ignore some kinds of segments. We can't
344
handle holes in the address space. Segments may be out of order,
345
so we sort them first. */
346
347
qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
348
349
for (i = 0; i < ex.e_phnum; i++) {
350
/* Section types we can ignore... */
351
switch (ph[i].p_type) {
352
case PT_NULL:
353
case PT_NOTE:
354
case PT_PHDR:
355
case PT_MIPS_REGINFO:
356
case PT_MIPS_ABIFLAGS:
357
continue;
358
359
case PT_LOAD:
360
/* Writable (data) segment? */
361
if (ph[i].p_flags & PF_W) {
362
struct sect ndata, nbss;
363
364
ndata.vaddr = ph[i].p_vaddr;
365
ndata.len = ph[i].p_filesz;
366
nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
367
nbss.len = ph[i].p_memsz - ph[i].p_filesz;
368
369
combine(&data, &ndata, 0);
370
combine(&bss, &nbss, 1);
371
} else {
372
struct sect ntxt;
373
374
ntxt.vaddr = ph[i].p_vaddr;
375
ntxt.len = ph[i].p_filesz;
376
377
combine(&text, &ntxt, 0);
378
}
379
/* Remember the lowest segment start address. */
380
if (ph[i].p_vaddr < cur_vma)
381
cur_vma = ph[i].p_vaddr;
382
break;
383
384
default:
385
/* Section types we can't handle... */
386
fprintf(stderr,
387
"Program header %d type %d can't be converted.\n",
388
ex.e_phnum, ph[i].p_type);
389
exit(1);
390
}
391
}
392
393
/* Sections must be in order to be converted... */
394
if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
395
text.vaddr + text.len > data.vaddr
396
|| data.vaddr + data.len > bss.vaddr) {
397
fprintf(stderr,
398
"Sections ordering prevents a.out conversion.\n");
399
exit(1);
400
}
401
402
/* If there's a data section but no text section, then the loader
403
combined everything into one section. That needs to be the
404
text section, so just make the data section zero length following
405
text. */
406
if (data.len && !text.len) {
407
text = data;
408
data.vaddr = text.vaddr + text.len;
409
data.len = 0;
410
}
411
412
/* If there is a gap between text and data, we'll fill it when we copy
413
the data, so update the length of the text segment as represented in
414
a.out to reflect that, since a.out doesn't allow gaps in the program
415
address space. */
416
if (text.vaddr + text.len < data.vaddr)
417
text.len = data.vaddr - text.vaddr;
418
419
/* We now have enough information to cons up an a.out header... */
420
eah.magic = OMAGIC;
421
eah.vstamp = 200;
422
eah.tsize = text.len;
423
eah.dsize = data.len;
424
eah.bsize = bss.len;
425
eah.entry = ex.e_entry;
426
eah.text_start = text.vaddr;
427
eah.data_start = data.vaddr;
428
eah.bss_start = bss.vaddr;
429
eah.gprmask = 0xf3fffffe;
430
memset(&eah.cprmask, '\0', sizeof eah.cprmask);
431
eah.gp_value = 0; /* unused. */
432
433
if (format_bigendian)
434
efh.f_magic = MIPSEBMAGIC;
435
else
436
efh.f_magic = MIPSELMAGIC;
437
if (addflag)
438
nosecs = 6;
439
else
440
nosecs = 3;
441
efh.f_nscns = nosecs;
442
efh.f_timdat = 0; /* bogus */
443
efh.f_symptr = 0;
444
efh.f_nsyms = 0;
445
efh.f_opthdr = sizeof eah;
446
efh.f_flags = 0x100f; /* Stripped, not shareable. */
447
448
memset(esecs, 0, sizeof esecs);
449
strcpy(esecs[0].s_name, ".text");
450
strcpy(esecs[1].s_name, ".data");
451
strcpy(esecs[2].s_name, ".bss");
452
if (addflag) {
453
strcpy(esecs[3].s_name, ".rdata");
454
strcpy(esecs[4].s_name, ".sdata");
455
strcpy(esecs[5].s_name, ".sbss");
456
}
457
esecs[0].s_paddr = esecs[0].s_vaddr = eah.text_start;
458
esecs[1].s_paddr = esecs[1].s_vaddr = eah.data_start;
459
esecs[2].s_paddr = esecs[2].s_vaddr = eah.bss_start;
460
if (addflag) {
461
esecs[3].s_paddr = esecs[3].s_vaddr = 0;
462
esecs[4].s_paddr = esecs[4].s_vaddr = 0;
463
esecs[5].s_paddr = esecs[5].s_vaddr = 0;
464
}
465
esecs[0].s_size = eah.tsize;
466
esecs[1].s_size = eah.dsize;
467
esecs[2].s_size = eah.bsize;
468
if (addflag) {
469
esecs[3].s_size = 0;
470
esecs[4].s_size = 0;
471
esecs[5].s_size = 0;
472
}
473
esecs[0].s_scnptr = N_TXTOFF(efh, eah);
474
esecs[1].s_scnptr = N_DATOFF(efh, eah);
475
#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
476
#define ECOFF_ROUND(s, a) (((s)+(a)-1)&~((a)-1))
477
esecs[2].s_scnptr = esecs[1].s_scnptr +
478
ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(&eah));
479
if (addflag) {
480
esecs[3].s_scnptr = 0;
481
esecs[4].s_scnptr = 0;
482
esecs[5].s_scnptr = 0;
483
}
484
esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
485
esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
486
esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
487
esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
488
if (addflag) {
489
esecs[3].s_relptr = esecs[4].s_relptr
490
= esecs[5].s_relptr = 0;
491
esecs[3].s_lnnoptr = esecs[4].s_lnnoptr
492
= esecs[5].s_lnnoptr = 0;
493
esecs[3].s_nreloc = esecs[4].s_nreloc = esecs[5].s_nreloc =
494
0;
495
esecs[3].s_nlnno = esecs[4].s_nlnno = esecs[5].s_nlnno = 0;
496
}
497
esecs[0].s_flags = 0x20;
498
esecs[1].s_flags = 0x40;
499
esecs[2].s_flags = 0x82;
500
if (addflag) {
501
esecs[3].s_flags = 0x100;
502
esecs[4].s_flags = 0x200;
503
esecs[5].s_flags = 0x400;
504
}
505
506
/* Make the output file... */
507
if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
508
fprintf(stderr, "Unable to create %s: %s\n", argv[2],
509
strerror(errno));
510
exit(1);
511
}
512
513
if (must_convert_endian)
514
convert_ecoff_filehdr(&efh);
515
/* Write the headers... */
516
i = write(outfile, &efh, sizeof efh);
517
if (i != sizeof efh) {
518
perror("efh: write");
519
exit(1);
520
521
for (i = 0; i < nosecs; i++) {
522
printf
523
("Section %d: %s phys %"PRIx32" size %"PRIx32"\t file offset %"PRIx32"\n",
524
i, esecs[i].s_name, esecs[i].s_paddr,
525
esecs[i].s_size, esecs[i].s_scnptr);
526
}
527
}
528
fprintf(stderr, "wrote %d byte file header.\n", i);
529
530
if (must_convert_endian)
531
convert_ecoff_aouthdr(&eah);
532
i = write(outfile, &eah, sizeof eah);
533
if (i != sizeof eah) {
534
perror("eah: write");
535
exit(1);
536
}
537
fprintf(stderr, "wrote %d byte a.out header.\n", i);
538
539
if (must_convert_endian)
540
convert_ecoff_esecs(&esecs[0], nosecs);
541
i = write(outfile, &esecs, nosecs * sizeof(struct scnhdr));
542
if (i != nosecs * sizeof(struct scnhdr)) {
543
perror("esecs: write");
544
exit(1);
545
}
546
fprintf(stderr, "wrote %d bytes of section headers.\n", i);
547
548
pad = (sizeof(efh) + sizeof(eah) + nosecs * sizeof(struct scnhdr)) & 15;
549
if (pad) {
550
pad = 16 - pad;
551
i = write(outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
552
if (i < 0) {
553
perror("ipad: write");
554
exit(1);
555
}
556
fprintf(stderr, "wrote %d byte pad.\n", i);
557
}
558
559
/*
560
* Copy the loadable sections. Zero-fill any gaps less than 64k;
561
* complain about any zero-filling, and die if we're asked to zero-fill
562
* more than 64k.
563
*/
564
for (i = 0; i < ex.e_phnum; i++) {
565
/* Unprocessable sections were handled above, so just verify that
566
the section can be loaded before copying. */
567
if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
568
if (cur_vma != ph[i].p_vaddr) {
569
uint32_t gap = ph[i].p_vaddr - cur_vma;
570
char obuf[1024];
571
if (gap > 65536) {
572
fprintf(stderr,
573
"Intersegment gap (%"PRId32" bytes) too large.\n",
574
gap);
575
exit(1);
576
}
577
fprintf(stderr,
578
"Warning: %d byte intersegment gap.\n",
579
gap);
580
memset(obuf, 0, sizeof obuf);
581
while (gap) {
582
int count =
583
write(outfile, obuf,
584
(gap >
585
sizeof obuf ? sizeof
586
obuf : gap));
587
if (count < 0) {
588
fprintf(stderr,
589
"Error writing gap: %s\n",
590
strerror(errno));
591
exit(1);
592
}
593
gap -= count;
594
}
595
}
596
fprintf(stderr, "writing %d bytes...\n",
597
ph[i].p_filesz);
598
copy(outfile, infile, ph[i].p_offset,
599
ph[i].p_filesz);
600
cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
601
}
602
}
603
604
/*
605
* Write a page of padding for boot PROMS that read entire pages.
606
* Without this, they may attempt to read past the end of the
607
* data section, incur an error, and refuse to boot.
608
*/
609
{
610
char obuf[4096];
611
memset(obuf, 0, sizeof obuf);
612
if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
613
fprintf(stderr, "Error writing PROM padding: %s\n",
614
strerror(errno));
615
exit(1);
616
}
617
}
618
619
/* Looks like we won... */
620
exit(0);
621
}
622
623