elf2aout.c revision 1.13 1 /* $NetBSD: elf2aout.c,v 1.13 2011/06/28 13:15:24 tsutsui 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 /* elf2aout.c
32
33 This program converts an elf executable to a NetBSD a.out executable.
34 The minimal symbol table is copied, but the debugging symbols and
35 other informational sections are not. */
36
37 #include <sys/types.h>
38 #include <sys/exec_aout.h>
39 #include <sys/exec_elf.h>
40
41 #include <a.out.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <limits.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50
51
52 struct sect {
53 unsigned long vaddr;
54 unsigned long len;
55 };
56
57 void combine(struct sect *, struct sect *, int);
58 int phcmp(const void *, const void *);
59 char *saveRead(int file, off_t offset, off_t len, const char *name);
60 void copy(int, int, off_t, off_t);
61 void translate_syms(int, int, off_t, off_t, off_t, off_t);
62
63 int *symTypeTable;
64
65 int
66 main(int argc, char **argv)
67 {
68 Elf32_Ehdr ex;
69 Elf32_Phdr *ph;
70 Elf32_Shdr *sh;
71 char *shstrtab;
72 int strtabix, symtabix;
73 int i;
74 struct sect text, data, bss;
75 struct exec aex;
76 int infile, outfile;
77 unsigned long cur_vma = ULONG_MAX;
78 int symflag = 0;
79
80 strtabix = symtabix = 0;
81 text.len = data.len = bss.len = 0;
82 text.vaddr = data.vaddr = bss.vaddr = 0;
83
84 /* Check args... */
85 if (argc < 3 || argc > 4) {
86 usage:
87 fprintf(stderr,
88 "usage: elf2aout <elf executable> <a.out executable> [-s]\n");
89 exit(1);
90 }
91 if (argc == 4) {
92 if (strcmp(argv[3], "-s"))
93 goto usage;
94 symflag = 1;
95 }
96 /* Try the input file... */
97 if ((infile = open(argv[1], O_RDONLY)) < 0) {
98 fprintf(stderr, "Can't open %s for read: %s\n",
99 argv[1], strerror(errno));
100 exit(1);
101 }
102 /* Read the header, which is at the beginning of the file... */
103 i = read(infile, &ex, sizeof ex);
104 if (i != sizeof ex) {
105 fprintf(stderr, "ex: %s: %s.\n",
106 argv[1], i ? strerror(errno) : "End of file reached");
107 exit(1);
108 }
109 /* Read the program headers... */
110 ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
111 ex.e_phnum * sizeof(Elf32_Phdr), "ph");
112 /* Read the section headers... */
113 sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
114 ex.e_shnum * sizeof(Elf32_Shdr), "sh");
115 /* Read in the section string table. */
116 shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
117 sh[ex.e_shstrndx].sh_size, "shstrtab");
118
119 /* Find space for a table matching ELF section indices to a.out symbol
120 * types. */
121 symTypeTable = malloc(ex.e_shnum * sizeof(int));
122 if (symTypeTable == NULL) {
123 fprintf(stderr, "symTypeTable: can't allocate.\n");
124 exit(1);
125 }
126 memset(symTypeTable, 0, ex.e_shnum * sizeof(int));
127
128 /* Look for the symbol table and string table... Also map section
129 * indices to symbol types for a.out */
130 for (i = 0; i < ex.e_shnum; i++) {
131 char *name = shstrtab + sh[i].sh_name;
132 if (!strcmp(name, ".symtab"))
133 symtabix = i;
134 else
135 if (!strcmp(name, ".strtab"))
136 strtabix = i;
137 else
138 if (!strcmp(name, ".text") || !strcmp(name, ".rodata"))
139 symTypeTable[i] = N_TEXT;
140 else
141 if (!strcmp(name, ".data") || !strcmp(name, ".sdata") ||
142 !strcmp(name, ".lit4") || !strcmp(name, ".lit8"))
143 symTypeTable[i] = N_DATA;
144 else
145 if (!strcmp(name, ".bss") || !strcmp(name, ".sbss"))
146 symTypeTable[i] = N_BSS;
147 }
148
149 /* Figure out if we can cram the program header into an a.out
150 * header... Basically, we can't handle anything but loadable
151 * segments, but we can ignore some kinds of segments. We can't
152 * handle holes in the address space, and we handle start addresses
153 * other than 0x1000 by hoping that the loader will know where to load
154 * - a.out doesn't have an explicit load address. Segments may be
155 * out of order, so we sort them first. */
156 qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
157 for (i = 0; i < ex.e_phnum; i++) {
158 /* Section types we can ignore... */
159 if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
160 ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO)
161 continue;
162 /* Section types we can't handle... */
163 else
164 if (ph[i].p_type != PT_LOAD)
165 errx(1, "Program header %d type %d can't be converted.", i, ph[i].p_type);
166 /* Writable (data) segment? */
167 if (ph[i].p_flags & PF_W) {
168 struct sect ndata, nbss;
169
170 ndata.vaddr = ph[i].p_vaddr;
171 ndata.len = ph[i].p_filesz;
172 nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
173 nbss.len = ph[i].p_memsz - ph[i].p_filesz;
174
175 combine(&data, &ndata, 0);
176 combine(&bss, &nbss, 1);
177 } else {
178 struct sect ntxt;
179
180 ntxt.vaddr = ph[i].p_vaddr;
181 ntxt.len = ph[i].p_filesz;
182
183 combine(&text, &ntxt, 0);
184 }
185 /* Remember the lowest segment start address. */
186 if (ph[i].p_vaddr < cur_vma)
187 cur_vma = ph[i].p_vaddr;
188 }
189
190 /* Sections must be in order to be converted... */
191 if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
192 text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
193 fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
194 exit(1);
195 }
196 /* If there's a data section but no text section, then the loader
197 * combined everything into one section. That needs to be the text
198 * section, so just make the data section zero length following text. */
199 if (data.len && text.len == 0) {
200 text = data;
201 data.vaddr = text.vaddr + text.len;
202 data.len = 0;
203 }
204 /* If there is a gap between text and data, we'll fill it when we copy
205 * the data, so update the length of the text segment as represented
206 * in a.out to reflect that, since a.out doesn't allow gaps in the
207 * program address space. */
208 if (text.vaddr + text.len < data.vaddr)
209 text.len = data.vaddr - text.vaddr;
210
211 /* We now have enough information to cons up an a.out header... */
212 aex.a_midmag = htonl((symflag << 26) | (MID_PMAX << 16) | OMAGIC);
213 if (ex.e_machine == EM_PPC)
214 aex.a_midmag = htonl((symflag << 26) | (MID_POWERPC << 16)
215 | OMAGIC);
216
217 aex.a_text = text.len;
218 aex.a_data = data.len;
219 aex.a_bss = bss.len;
220 aex.a_entry = ex.e_entry;
221 aex.a_syms = (sizeof(struct nlist) *
222 (symtabix != -1
223 ? sh[symtabix].sh_size / sizeof(Elf32_Sym) : 0));
224 aex.a_trsize = 0;
225 aex.a_drsize = 0;
226
227 /* Make the output file... */
228 if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
229 fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
230 exit(1);
231 }
232 /* Truncate file... */
233 if (ftruncate(outfile, 0)) {
234 warn("ftruncate %s", argv[2]);
235 }
236 /* Write the header... */
237 i = write(outfile, &aex, sizeof aex);
238 if (i != sizeof aex) {
239 perror("aex: write");
240 exit(1);
241 }
242 /* Copy the loadable sections. Zero-fill any gaps less than 64k;
243 * complain about any zero-filling, and die if we're asked to
244 * zero-fill more than 64k. */
245 for (i = 0; i < ex.e_phnum; i++) {
246 /* Unprocessable sections were handled above, so just verify
247 * that the section can be loaded before copying. */
248 if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
249 if (cur_vma != ph[i].p_vaddr) {
250 unsigned long gap = ph[i].p_vaddr - cur_vma;
251 char obuf[1024];
252 if (gap > 65536)
253 errx(1,
254 "Intersegment gap (%ld bytes) too large.", (long) gap);
255 #ifdef DEBUG
256 warnx("Warning: %ld byte intersegment gap.",
257 (long)gap);
258 #endif
259 memset(obuf, 0, sizeof obuf);
260 while (gap) {
261 int count = write(outfile, obuf, (gap > sizeof obuf
262 ? sizeof obuf : gap));
263 if (count < 0) {
264 fprintf(stderr, "Error writing gap: %s\n",
265 strerror(errno));
266 exit(1);
267 }
268 gap -= count;
269 }
270 }
271 copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
272 cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
273 }
274 }
275
276 /* Copy and translate the symbol table... */
277 translate_syms(outfile, infile,
278 sh[symtabix].sh_offset, sh[symtabix].sh_size,
279 sh[strtabix].sh_offset, sh[strtabix].sh_size);
280
281 /* Looks like we won... */
282 exit(0);
283 }
284 /* translate_syms (out, in, offset, size)
285
286 Read the ELF symbol table from in at offset; translate it into a.out
287 nlist format and write it to out. */
288
289 void
290 translate_syms(int out, int in, off_t symoff, off_t symsize,
291 off_t stroff, off_t strsize)
292 {
293 #define SYMS_PER_PASS 64
294 Elf32_Sym inbuf[64];
295 struct nlist outbuf[64];
296 int i, remaining, cur;
297 char *oldstrings;
298 char *newstrings, *nsp;
299 int newstringsize;
300
301 /* Zero the unused fields in the output buffer.. */
302 memset(outbuf, 0, sizeof outbuf);
303
304 /* Find number of symbols to process... */
305 remaining = symsize / sizeof(Elf32_Sym);
306
307 /* Suck in the old string table... */
308 oldstrings = saveRead(in, stroff, strsize, "string table");
309
310 /* Allocate space for the new one. XXX We make the wild assumption
311 * that no two symbol table entries will point at the same place in
312 * the string table - if that assumption is bad, this could easily
313 * blow up. */
314 newstringsize = strsize + remaining;
315 newstrings = malloc(newstringsize);
316 if (newstrings == NULL) {
317 fprintf(stderr, "No memory for new string table!\n");
318 exit(1);
319 }
320 /* Initialize the table pointer... */
321 nsp = newstrings;
322
323 /* Go the start of the ELF symbol table... */
324 if (lseek(in, symoff, SEEK_SET) < 0) {
325 perror("translate_syms: lseek");
326 exit(1);
327 }
328 /* Translate and copy symbols... */
329 while (remaining) {
330 cur = remaining;
331 if (cur > SYMS_PER_PASS)
332 cur = SYMS_PER_PASS;
333 remaining -= cur;
334 if ((i = read(in, inbuf, cur * sizeof(Elf32_Sym)))
335 != cur * (long)sizeof(Elf32_Sym)) {
336 if (i < 0)
337 perror("translate_syms");
338 else
339 fprintf(stderr, "translate_syms: premature end of file.\n");
340 exit(1);
341 }
342 /* Do the translation... */
343 for (i = 0; i < cur; i++) {
344 int binding, type;
345
346 /* Copy the symbol into the new table, but prepend an
347 * underscore. */
348 *nsp = '_';
349 strcpy(nsp + 1, oldstrings + inbuf[i].st_name);
350 outbuf[i].n_un.n_strx = nsp - newstrings + 4;
351 nsp += strlen(nsp) + 1;
352
353 type = ELF32_ST_TYPE(inbuf[i].st_info);
354 binding = ELF32_ST_BIND(inbuf[i].st_info);
355
356 /* Convert ELF symbol type/section/etc info into a.out
357 * type info. */
358 if (type == STT_FILE)
359 outbuf[i].n_type = N_FN;
360 else
361 if (inbuf[i].st_shndx == SHN_UNDEF)
362 outbuf[i].n_type = N_UNDF;
363 else
364 if (inbuf[i].st_shndx == SHN_ABS)
365 outbuf[i].n_type = N_ABS;
366 else
367 if (inbuf[i].st_shndx == SHN_COMMON ||
368 inbuf[i].st_shndx == SHN_MIPS_ACOMMON)
369 outbuf[i].n_type = N_COMM;
370 else
371 outbuf[i].n_type = symTypeTable[inbuf[i].st_shndx];
372 if (binding == STB_GLOBAL)
373 outbuf[i].n_type |= N_EXT;
374 /* Symbol values in executables should be compatible. */
375 outbuf[i].n_value = inbuf[i].st_value;
376 }
377 /* Write out the symbols... */
378 if ((i = write(out, outbuf, cur * sizeof(struct nlist)))
379 != cur * (long)sizeof(struct nlist)) {
380 fprintf(stderr, "translate_syms: write: %s\n", strerror(errno));
381 exit(1);
382 }
383 }
384 /* Write out the string table length... */
385 if (write(out, &newstringsize, sizeof newstringsize)
386 != sizeof newstringsize) {
387 fprintf(stderr,
388 "translate_syms: newstringsize: %s\n", strerror(errno));
389 exit(1);
390 }
391 /* Write out the string table... */
392 if (write(out, newstrings, newstringsize) != newstringsize) {
393 fprintf(stderr, "translate_syms: newstrings: %s\n", strerror(errno));
394 exit(1);
395 }
396 }
397
398 void
399 copy(int out, int in, off_t offset, off_t size)
400 {
401 char ibuf[4096];
402 int remaining, cur, count;
403
404 /* Go to the start of the ELF symbol table... */
405 if (lseek(in, offset, SEEK_SET) < 0) {
406 perror("copy: lseek");
407 exit(1);
408 }
409 remaining = size;
410 while (remaining) {
411 cur = remaining;
412 if (cur > (long)sizeof ibuf)
413 cur = sizeof ibuf;
414 remaining -= cur;
415 if ((count = read(in, ibuf, cur)) != cur) {
416 fprintf(stderr, "copy: read: %s\n",
417 count ? strerror(errno) : "premature end of file");
418 exit(1);
419 }
420 if ((count = write(out, ibuf, cur)) != cur) {
421 perror("copy: write");
422 exit(1);
423 }
424 }
425 }
426 /* Combine two segments, which must be contiguous. If pad is true, it's
427 okay for there to be padding between. */
428 void
429 combine(struct sect *base, struct sect *new, int pad)
430 {
431
432 if (base->len == 0)
433 *base = *new;
434 else
435 if (new->len) {
436 if (base->vaddr + base->len != new->vaddr) {
437 if (pad)
438 base->len = new->vaddr - base->vaddr;
439 else {
440 fprintf(stderr,
441 "Non-contiguous data can't be converted.\n");
442 exit(1);
443 }
444 }
445 base->len += new->len;
446 }
447 }
448
449 int
450 phcmp(const void *vh1, const void *vh2)
451 {
452 const Elf32_Phdr *h1, *h2;
453
454 h1 = (const Elf32_Phdr *)vh1;
455 h2 = (const Elf32_Phdr *)vh2;
456
457 if (h1->p_vaddr > h2->p_vaddr)
458 return 1;
459 else
460 if (h1->p_vaddr < h2->p_vaddr)
461 return -1;
462 else
463 return 0;
464 }
465
466 char *
467 saveRead(int file, off_t offset, off_t len, const char *name)
468 {
469 char *tmp;
470 int count;
471 off_t off;
472 if ((off = lseek(file, offset, SEEK_SET)) < 0) {
473 fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
474 exit(1);
475 }
476 if ((tmp = malloc(len)) == NULL)
477 errx(1, "%s: Can't allocate %ld bytes.", name, (long)len);
478 count = read(file, tmp, len);
479 if (count != len) {
480 fprintf(stderr, "%s: read: %s.\n",
481 name, count ? strerror(errno) : "End of file reached");
482 exit(1);
483 }
484 return tmp;
485 }
486