elf2aout.c revision 1.25 1 1.25 gutterid /* $NetBSD: elf2aout.c,v 1.25 2024/11/01 00:35:53 gutteridge Exp $ */
2 1.2 jonathan
3 1.1 jonathan /*
4 1.1 jonathan * Copyright (c) 1995
5 1.1 jonathan * Ted Lemon (hereinafter referred to as the author)
6 1.1 jonathan *
7 1.1 jonathan * Redistribution and use in source and binary forms, with or without
8 1.1 jonathan * modification, are permitted provided that the following conditions
9 1.1 jonathan * are met:
10 1.1 jonathan * 1. Redistributions of source code must retain the above copyright
11 1.1 jonathan * notice, this list of conditions and the following disclaimer.
12 1.1 jonathan * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jonathan * notice, this list of conditions and the following disclaimer in the
14 1.1 jonathan * documentation and/or other materials provided with the distribution.
15 1.1 jonathan * 3. The name of the author may not be used to endorse or promote products
16 1.1 jonathan * derived from this software without specific prior written permission.
17 1.1 jonathan *
18 1.1 jonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
19 1.1 jonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 1.1 jonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 1.1 jonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
22 1.1 jonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 1.1 jonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 1.1 jonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 1.1 jonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 1.1 jonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 1.1 jonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 1.1 jonathan * SUCH DAMAGE.
29 1.1 jonathan */
30 1.1 jonathan
31 1.1 jonathan /* elf2aout.c
32 1.1 jonathan
33 1.1 jonathan This program converts an elf executable to a NetBSD a.out executable.
34 1.1 jonathan The minimal symbol table is copied, but the debugging symbols and
35 1.1 jonathan other informational sections are not. */
36 1.1 jonathan
37 1.15 tsutsui #if HAVE_NBTOOL_CONFIG_H
38 1.15 tsutsui #include "nbtool_config.h"
39 1.15 tsutsui #endif
40 1.15 tsutsui
41 1.15 tsutsui #ifndef TARGET_BYTE_ORDER
42 1.15 tsutsui #define TARGET_BYTE_ORDER BYTE_ORDER
43 1.15 tsutsui #endif
44 1.15 tsutsui
45 1.1 jonathan #include <sys/types.h>
46 1.25 gutterid #include <sys/endian.h>
47 1.5 lukem #include <sys/exec_aout.h>
48 1.5 lukem #include <sys/exec_elf.h>
49 1.5 lukem
50 1.5 lukem #include <a.out.h>
51 1.5 lukem #include <err.h>
52 1.5 lukem #include <errno.h>
53 1.1 jonathan #include <fcntl.h>
54 1.5 lukem #include <limits.h>
55 1.1 jonathan #include <stdio.h>
56 1.5 lukem #include <stdlib.h>
57 1.1 jonathan #include <string.h>
58 1.5 lukem #include <unistd.h>
59 1.1 jonathan
60 1.3 jonathan
61 1.1 jonathan struct sect {
62 1.15 tsutsui /* should be unsigned long, but assume no a.out binaries on LP64 */
63 1.15 tsutsui uint32_t vaddr;
64 1.15 tsutsui uint32_t len;
65 1.1 jonathan };
66 1.1 jonathan
67 1.22 christos static void combine(struct sect *, struct sect *, int);
68 1.22 christos static int phcmp(const void *, const void *);
69 1.22 christos static void *saveRead(int file, off_t offset, size_t len, const char *name);
70 1.22 christos static void copy(int, int, off_t, off_t);
71 1.22 christos static void translate_syms(int, int, off_t, off_t, off_t, off_t);
72 1.5 lukem
73 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
74 1.22 christos static void bswap32_region(int32_t* , int);
75 1.15 tsutsui #endif
76 1.15 tsutsui
77 1.22 christos static int *symTypeTable;
78 1.22 christos static int debug;
79 1.22 christos
80 1.22 christos static __dead void
81 1.22 christos usage(void)
82 1.22 christos {
83 1.23 wiz fprintf(stderr, "Usage: %s [-Os] <elf executable> <a.out executable>\n",
84 1.22 christos getprogname());
85 1.22 christos exit(EXIT_FAILURE);
86 1.22 christos }
87 1.22 christos
88 1.22 christos static const struct {
89 1.22 christos const char *n;
90 1.22 christos int v;
91 1.22 christos } nv[] = {
92 1.22 christos { ".text", N_TEXT },
93 1.22 christos { ".rodata", N_TEXT },
94 1.22 christos { ".data", N_DATA },
95 1.22 christos { ".sdata", N_DATA },
96 1.22 christos { ".lit4", N_DATA },
97 1.22 christos { ".lit8", N_DATA },
98 1.22 christos { ".bss", N_BSS },
99 1.22 christos { ".sbss", N_BSS },
100 1.22 christos };
101 1.22 christos
102 1.22 christos static int
103 1.22 christos get_symtab_type(const char *name)
104 1.22 christos {
105 1.22 christos size_t i;
106 1.22 christos for (i = 0; i < __arraycount(nv); i++) {
107 1.22 christos if (strcmp(name, nv[i].n) == 0)
108 1.22 christos return nv[i].v;
109 1.22 christos }
110 1.22 christos if (debug)
111 1.22 christos warnx("section `%s' is not handled\n", name);
112 1.22 christos return 0;
113 1.22 christos }
114 1.22 christos
115 1.22 christos static uint32_t
116 1.22 christos get_mid(const Elf32_Ehdr *ex)
117 1.22 christos {
118 1.22 christos switch (ex->e_machine) {
119 1.22 christos #ifdef notyet
120 1.22 christos case EM_AARCH64:
121 1.22 christos return MID_AARCH64;
122 1.22 christos case EM_ALPHA:
123 1.22 christos return MID_ALPHA;
124 1.22 christos #endif
125 1.22 christos case EM_ARM:
126 1.22 christos return MID_ARM6;
127 1.22 christos #ifdef notyet
128 1.22 christos case EM_PARISC:
129 1.22 christos return MID_HPPA;
130 1.22 christos #endif
131 1.22 christos case EM_386:
132 1.22 christos return MID_I386;
133 1.22 christos case EM_68K:
134 1.22 christos return MID_M68K;
135 1.22 christos case EM_OR1K:
136 1.22 christos return MID_OR1K;
137 1.22 christos case EM_MIPS:
138 1.22 christos if (ex->e_ident[EI_DATA] == ELFDATA2LSB)
139 1.22 christos return MID_PMAX;
140 1.22 christos else
141 1.22 christos return MID_MIPS;
142 1.22 christos case EM_PPC:
143 1.22 christos return MID_POWERPC;
144 1.22 christos #ifdef notyet
145 1.22 christos case EM_PPC64:
146 1.22 christos return MID_POWERPC64;
147 1.22 christos break;
148 1.22 christos #endif
149 1.22 christos case EM_RISCV:
150 1.22 christos return MID_RISCV;
151 1.22 christos case EM_SH:
152 1.22 christos return MID_SH3;
153 1.22 christos case EM_SPARC:
154 1.22 christos case EM_SPARC32PLUS:
155 1.22 christos case EM_SPARCV9:
156 1.22 christos if (ex->e_ident[EI_CLASS] == ELFCLASS32)
157 1.22 christos return MID_SPARC;
158 1.22 christos #ifdef notyet
159 1.22 christos return MID_SPARC64;
160 1.22 christos case EM_X86_64:
161 1.22 christos return MID_X86_64;
162 1.22 christos #else
163 1.22 christos break;
164 1.22 christos #endif
165 1.22 christos case EM_VAX:
166 1.22 christos return MID_VAX;
167 1.22 christos case EM_NONE:
168 1.22 christos return MID_ZERO;
169 1.22 christos default:
170 1.22 christos break;
171 1.22 christos }
172 1.22 christos if (debug)
173 1.22 christos warnx("Unsupported machine `%d'", ex->e_machine);
174 1.22 christos return MID_ZERO;
175 1.22 christos }
176 1.22 christos
177 1.22 christos static unsigned char
178 1.22 christos get_type(Elf32_Half shndx)
179 1.22 christos {
180 1.22 christos switch (shndx) {
181 1.22 christos case SHN_UNDEF:
182 1.22 christos return N_UNDF;
183 1.22 christos case SHN_ABS:
184 1.22 christos return N_ABS;
185 1.22 christos case SHN_COMMON:
186 1.22 christos case SHN_MIPS_ACOMMON:
187 1.22 christos return N_COMM;
188 1.22 christos default:
189 1.22 christos return (unsigned char)symTypeTable[shndx];
190 1.22 christos }
191 1.22 christos }
192 1.5 lukem
193 1.5 lukem int
194 1.5 lukem main(int argc, char **argv)
195 1.1 jonathan {
196 1.5 lukem Elf32_Ehdr ex;
197 1.5 lukem Elf32_Phdr *ph;
198 1.5 lukem Elf32_Shdr *sh;
199 1.5 lukem char *shstrtab;
200 1.17 christos ssize_t i, strtabix, symtabix;
201 1.5 lukem struct sect text, data, bss;
202 1.5 lukem struct exec aex;
203 1.5 lukem int infile, outfile;
204 1.15 tsutsui uint32_t cur_vma = UINT32_MAX;
205 1.15 tsutsui uint32_t mid;
206 1.22 christos int symflag = 0, c;
207 1.22 christos unsigned long magic = ZMAGIC;
208 1.5 lukem
209 1.5 lukem strtabix = symtabix = 0;
210 1.5 lukem text.len = data.len = bss.len = 0;
211 1.5 lukem text.vaddr = data.vaddr = bss.vaddr = 0;
212 1.5 lukem
213 1.22 christos while ((c = getopt(argc, argv, "dOs")) != -1) {
214 1.22 christos switch (c) {
215 1.22 christos case 'd':
216 1.22 christos debug++;
217 1.22 christos break;
218 1.22 christos case 's':
219 1.22 christos symflag = 1;
220 1.22 christos break;
221 1.22 christos case 'O':
222 1.22 christos magic = OMAGIC;
223 1.22 christos break;
224 1.22 christos case '?':
225 1.22 christos default:
226 1.22 christos usage:
227 1.22 christos usage();
228 1.22 christos }
229 1.22 christos }
230 1.22 christos
231 1.22 christos argc -= optind;
232 1.22 christos argv += optind;
233 1.22 christos
234 1.5 lukem /* Check args... */
235 1.22 christos if (argc != 2)
236 1.22 christos goto usage;
237 1.22 christos
238 1.22 christos
239 1.5 lukem /* Try the input file... */
240 1.22 christos if ((infile = open(argv[0], O_RDONLY)) < 0)
241 1.22 christos err(EXIT_FAILURE, "Can't open `%s' for read", argv[0]);
242 1.17 christos
243 1.5 lukem /* Read the header, which is at the beginning of the file... */
244 1.5 lukem i = read(infile, &ex, sizeof ex);
245 1.5 lukem if (i != sizeof ex) {
246 1.17 christos if (i == -1)
247 1.17 christos err(EXIT_FAILURE, "Error reading `%s'", argv[1]);
248 1.17 christos else
249 1.17 christos errx(EXIT_FAILURE, "End of file reading `%s'", argv[1]);
250 1.5 lukem }
251 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
252 1.15 tsutsui ex.e_type = bswap16(ex.e_type);
253 1.15 tsutsui ex.e_machine = bswap16(ex.e_machine);
254 1.15 tsutsui ex.e_version = bswap32(ex.e_version);
255 1.15 tsutsui ex.e_entry = bswap32(ex.e_entry);
256 1.15 tsutsui ex.e_phoff = bswap32(ex.e_phoff);
257 1.15 tsutsui ex.e_shoff = bswap32(ex.e_shoff);
258 1.15 tsutsui ex.e_flags = bswap32(ex.e_flags);
259 1.15 tsutsui ex.e_ehsize = bswap16(ex.e_ehsize);
260 1.15 tsutsui ex.e_phentsize = bswap16(ex.e_phentsize);
261 1.15 tsutsui ex.e_phnum = bswap16(ex.e_phnum);
262 1.15 tsutsui ex.e_shentsize = bswap16(ex.e_shentsize);
263 1.15 tsutsui ex.e_shnum = bswap16(ex.e_shnum);
264 1.15 tsutsui ex.e_shstrndx = bswap16(ex.e_shstrndx);
265 1.15 tsutsui #endif
266 1.22 christos // Not yet
267 1.22 christos if (ex.e_ident[EI_CLASS] == ELFCLASS64)
268 1.22 christos errx(EXIT_FAILURE, "Only 32 bit is supported");
269 1.22 christos
270 1.5 lukem /* Read the program headers... */
271 1.17 christos ph = saveRead(infile, ex.e_phoff,
272 1.17 christos (size_t)ex.e_phnum * sizeof(Elf32_Phdr), "ph");
273 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
274 1.15 tsutsui bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum);
275 1.15 tsutsui #endif
276 1.5 lukem /* Read the section headers... */
277 1.17 christos sh = saveRead(infile, ex.e_shoff,
278 1.17 christos (size_t)ex.e_shnum * sizeof(Elf32_Shdr), "sh");
279 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
280 1.15 tsutsui bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum);
281 1.15 tsutsui #endif
282 1.5 lukem /* Read in the section string table. */
283 1.5 lukem shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
284 1.17 christos (size_t)sh[ex.e_shstrndx].sh_size, "shstrtab");
285 1.5 lukem
286 1.5 lukem /* Find space for a table matching ELF section indices to a.out symbol
287 1.5 lukem * types. */
288 1.13 tsutsui symTypeTable = malloc(ex.e_shnum * sizeof(int));
289 1.17 christos if (symTypeTable == NULL)
290 1.17 christos err(EXIT_FAILURE, "symTypeTable: can't allocate");
291 1.5 lukem memset(symTypeTable, 0, ex.e_shnum * sizeof(int));
292 1.5 lukem
293 1.5 lukem /* Look for the symbol table and string table... Also map section
294 1.5 lukem * indices to symbol types for a.out */
295 1.5 lukem for (i = 0; i < ex.e_shnum; i++) {
296 1.5 lukem char *name = shstrtab + sh[i].sh_name;
297 1.5 lukem if (!strcmp(name, ".symtab"))
298 1.5 lukem symtabix = i;
299 1.22 christos else if (!strcmp(name, ".strtab"))
300 1.22 christos strtabix = i;
301 1.5 lukem else
302 1.22 christos symTypeTable[i] = get_symtab_type(name);
303 1.5 lukem }
304 1.5 lukem
305 1.5 lukem /* Figure out if we can cram the program header into an a.out
306 1.5 lukem * header... Basically, we can't handle anything but loadable
307 1.5 lukem * segments, but we can ignore some kinds of segments. We can't
308 1.5 lukem * handle holes in the address space, and we handle start addresses
309 1.5 lukem * other than 0x1000 by hoping that the loader will know where to load
310 1.5 lukem * - a.out doesn't have an explicit load address. Segments may be
311 1.5 lukem * out of order, so we sort them first. */
312 1.5 lukem qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), phcmp);
313 1.5 lukem for (i = 0; i < ex.e_phnum; i++) {
314 1.5 lukem /* Section types we can ignore... */
315 1.7 drochner if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
316 1.7 drochner ph[i].p_type == PT_PHDR || ph[i].p_type == PT_MIPS_REGINFO)
317 1.5 lukem continue;
318 1.5 lukem /* Section types we can't handle... */
319 1.22 christos if (ph[i].p_type == PT_TLS) {
320 1.22 christos if (debug)
321 1.22 christos warnx("Can't handle TLS section");
322 1.22 christos continue;
323 1.22 christos }
324 1.22 christos if (ph[i].p_type != PT_LOAD)
325 1.22 christos errx(EXIT_FAILURE, "Program header %zd "
326 1.22 christos "type %d can't be converted.", i, ph[i].p_type);
327 1.5 lukem /* Writable (data) segment? */
328 1.5 lukem if (ph[i].p_flags & PF_W) {
329 1.5 lukem struct sect ndata, nbss;
330 1.5 lukem
331 1.5 lukem ndata.vaddr = ph[i].p_vaddr;
332 1.5 lukem ndata.len = ph[i].p_filesz;
333 1.5 lukem nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
334 1.5 lukem nbss.len = ph[i].p_memsz - ph[i].p_filesz;
335 1.5 lukem
336 1.5 lukem combine(&data, &ndata, 0);
337 1.5 lukem combine(&bss, &nbss, 1);
338 1.5 lukem } else {
339 1.5 lukem struct sect ntxt;
340 1.5 lukem
341 1.5 lukem ntxt.vaddr = ph[i].p_vaddr;
342 1.5 lukem ntxt.len = ph[i].p_filesz;
343 1.5 lukem
344 1.5 lukem combine(&text, &ntxt, 0);
345 1.1 jonathan }
346 1.5 lukem /* Remember the lowest segment start address. */
347 1.5 lukem if (ph[i].p_vaddr < cur_vma)
348 1.5 lukem cur_vma = ph[i].p_vaddr;
349 1.5 lukem }
350 1.5 lukem
351 1.5 lukem /* Sections must be in order to be converted... */
352 1.5 lukem if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
353 1.17 christos text.vaddr + text.len > data.vaddr ||
354 1.17 christos data.vaddr + data.len > bss.vaddr)
355 1.17 christos errx(EXIT_FAILURE, "Sections ordering prevents a.out "
356 1.17 christos "conversion.");
357 1.5 lukem /* If there's a data section but no text section, then the loader
358 1.5 lukem * combined everything into one section. That needs to be the text
359 1.5 lukem * section, so just make the data section zero length following text. */
360 1.13 tsutsui if (data.len && text.len == 0) {
361 1.5 lukem text = data;
362 1.5 lukem data.vaddr = text.vaddr + text.len;
363 1.5 lukem data.len = 0;
364 1.5 lukem }
365 1.5 lukem /* If there is a gap between text and data, we'll fill it when we copy
366 1.5 lukem * the data, so update the length of the text segment as represented
367 1.5 lukem * in a.out to reflect that, since a.out doesn't allow gaps in the
368 1.5 lukem * program address space. */
369 1.5 lukem if (text.vaddr + text.len < data.vaddr)
370 1.5 lukem text.len = data.vaddr - text.vaddr;
371 1.5 lukem
372 1.5 lukem /* We now have enough information to cons up an a.out header... */
373 1.22 christos mid = get_mid(&ex);
374 1.25 gutterid aex.a_midmag = (u_long)htobe32(((u_long)symflag << 26)
375 1.22 christos | ((u_long)mid << 16) | magic);
376 1.13 tsutsui
377 1.5 lukem aex.a_text = text.len;
378 1.5 lukem aex.a_data = data.len;
379 1.5 lukem aex.a_bss = bss.len;
380 1.5 lukem aex.a_entry = ex.e_entry;
381 1.5 lukem aex.a_syms = (sizeof(struct nlist) *
382 1.22 christos (symtabix != -1 ? sh[symtabix].sh_size / sizeof(Elf32_Sym) : 0));
383 1.5 lukem aex.a_trsize = 0;
384 1.5 lukem aex.a_drsize = 0;
385 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
386 1.15 tsutsui aex.a_text = bswap32(aex.a_text);
387 1.15 tsutsui aex.a_data = bswap32(aex.a_data);
388 1.15 tsutsui aex.a_bss = bswap32(aex.a_bss);
389 1.15 tsutsui aex.a_entry = bswap32(aex.a_entry);
390 1.15 tsutsui aex.a_syms = bswap32(aex.a_syms);
391 1.15 tsutsui aex.a_trsize = bswap32(aex.a_trsize);
392 1.15 tsutsui aex.a_drsize = bswap32(aex.a_drsize);
393 1.15 tsutsui #endif
394 1.5 lukem
395 1.5 lukem /* Make the output file... */
396 1.22 christos if ((outfile = open(argv[1], O_WRONLY | O_CREAT, 0777)) < 0)
397 1.22 christos err(EXIT_FAILURE, "Unable to create `%s'", argv[1]);
398 1.6 simonb /* Truncate file... */
399 1.6 simonb if (ftruncate(outfile, 0)) {
400 1.22 christos warn("ftruncate %s", argv[1]);
401 1.6 simonb }
402 1.5 lukem /* Write the header... */
403 1.5 lukem i = write(outfile, &aex, sizeof aex);
404 1.17 christos if (i != sizeof aex)
405 1.22 christos err(EXIT_FAILURE, "Can't write `%s'", argv[1]);
406 1.5 lukem /* Copy the loadable sections. Zero-fill any gaps less than 64k;
407 1.5 lukem * complain about any zero-filling, and die if we're asked to
408 1.5 lukem * zero-fill more than 64k. */
409 1.5 lukem for (i = 0; i < ex.e_phnum; i++) {
410 1.5 lukem /* Unprocessable sections were handled above, so just verify
411 1.5 lukem * that the section can be loaded before copying. */
412 1.7 drochner if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
413 1.5 lukem if (cur_vma != ph[i].p_vaddr) {
414 1.15 tsutsui uint32_t gap = ph[i].p_vaddr - cur_vma;
415 1.5 lukem char obuf[1024];
416 1.5 lukem if (gap > 65536)
417 1.17 christos errx(EXIT_FAILURE,
418 1.17 christos "Intersegment gap (%u bytes) too large", gap);
419 1.22 christos if (debug)
420 1.22 christos warnx("%u byte intersegment gap", gap);
421 1.5 lukem memset(obuf, 0, sizeof obuf);
422 1.5 lukem while (gap) {
423 1.17 christos ssize_t count = write(outfile, obuf,
424 1.17 christos (gap > sizeof obuf
425 1.17 christos ? sizeof obuf : gap));
426 1.17 christos if (count < 0)
427 1.17 christos err(EXIT_FAILURE,
428 1.17 christos "Error writing gap");
429 1.17 christos gap -= (uint32_t)count;
430 1.5 lukem }
431 1.5 lukem }
432 1.5 lukem copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
433 1.5 lukem cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
434 1.1 jonathan }
435 1.5 lukem }
436 1.5 lukem
437 1.5 lukem /* Copy and translate the symbol table... */
438 1.5 lukem translate_syms(outfile, infile,
439 1.5 lukem sh[symtabix].sh_offset, sh[symtabix].sh_size,
440 1.5 lukem sh[strtabix].sh_offset, sh[strtabix].sh_size);
441 1.1 jonathan
442 1.17 christos free(ph);
443 1.17 christos free(sh);
444 1.17 christos free(shstrtab);
445 1.17 christos free(symTypeTable);
446 1.5 lukem /* Looks like we won... */
447 1.17 christos return EXIT_SUCCESS;
448 1.1 jonathan }
449 1.1 jonathan /* translate_syms (out, in, offset, size)
450 1.1 jonathan
451 1.1 jonathan Read the ELF symbol table from in at offset; translate it into a.out
452 1.1 jonathan nlist format and write it to out. */
453 1.1 jonathan
454 1.5 lukem void
455 1.13 tsutsui translate_syms(int out, int in, off_t symoff, off_t symsize,
456 1.13 tsutsui off_t stroff, off_t strsize)
457 1.1 jonathan {
458 1.5 lukem #define SYMS_PER_PASS 64
459 1.5 lukem Elf32_Sym inbuf[64];
460 1.5 lukem struct nlist outbuf[64];
461 1.17 christos ssize_t i, remaining, cur;
462 1.5 lukem char *oldstrings;
463 1.5 lukem char *newstrings, *nsp;
464 1.20 skrll size_t newstringsize;
465 1.20 skrll uint32_t stringsizebuf;
466 1.5 lukem
467 1.5 lukem /* Zero the unused fields in the output buffer.. */
468 1.5 lukem memset(outbuf, 0, sizeof outbuf);
469 1.5 lukem
470 1.5 lukem /* Find number of symbols to process... */
471 1.19 martin remaining = (ssize_t)(symsize / (off_t)sizeof(Elf32_Sym));
472 1.5 lukem
473 1.5 lukem /* Suck in the old string table... */
474 1.17 christos oldstrings = saveRead(in, stroff, (size_t)strsize, "string table");
475 1.5 lukem
476 1.20 skrll /*
477 1.20 skrll * Allocate space for the new one. We will increase the space if
478 1.20 skrll * this is too small
479 1.20 skrll */
480 1.17 christos newstringsize = (size_t)(strsize + remaining);
481 1.13 tsutsui newstrings = malloc(newstringsize);
482 1.17 christos if (newstrings == NULL)
483 1.17 christos err(EXIT_FAILURE, "No memory for new string table!");
484 1.5 lukem /* Initialize the table pointer... */
485 1.5 lukem nsp = newstrings;
486 1.5 lukem
487 1.10 soren /* Go the start of the ELF symbol table... */
488 1.17 christos if (lseek(in, symoff, SEEK_SET) < 0)
489 1.17 christos err(EXIT_FAILURE, "Can't seek");
490 1.5 lukem /* Translate and copy symbols... */
491 1.20 skrll for (; remaining; remaining -= cur) {
492 1.5 lukem cur = remaining;
493 1.5 lukem if (cur > SYMS_PER_PASS)
494 1.5 lukem cur = SYMS_PER_PASS;
495 1.17 christos if ((i = read(in, inbuf, (size_t)cur * sizeof(Elf32_Sym)))
496 1.15 tsutsui != cur * (ssize_t)sizeof(Elf32_Sym)) {
497 1.5 lukem if (i < 0)
498 1.17 christos err(EXIT_FAILURE, "%s: read error", __func__);
499 1.5 lukem else
500 1.17 christos errx(EXIT_FAILURE, "%s: premature end of file",
501 1.17 christos __func__);
502 1.5 lukem }
503 1.5 lukem /* Do the translation... */
504 1.5 lukem for (i = 0; i < cur; i++) {
505 1.5 lukem int binding, type;
506 1.20 skrll size_t off, len;
507 1.5 lukem
508 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
509 1.15 tsutsui inbuf[i].st_name = bswap32(inbuf[i].st_name);
510 1.15 tsutsui inbuf[i].st_value = bswap32(inbuf[i].st_value);
511 1.15 tsutsui inbuf[i].st_size = bswap32(inbuf[i].st_size);
512 1.15 tsutsui inbuf[i].st_shndx = bswap16(inbuf[i].st_shndx);
513 1.15 tsutsui #endif
514 1.20 skrll off = (size_t)(nsp - newstrings);
515 1.20 skrll
516 1.20 skrll /* length of this symbol with leading '_' and trailing '\0' */
517 1.20 skrll len = strlen(oldstrings + inbuf[i].st_name) + 1 + 1;
518 1.20 skrll
519 1.20 skrll /* Does it fit? If not make more space */
520 1.20 skrll if (newstringsize - off < len) {
521 1.20 skrll char *nns;
522 1.20 skrll
523 1.20 skrll newstringsize += (size_t)(remaining) * len;
524 1.20 skrll nns = realloc(newstrings, newstringsize);
525 1.20 skrll if (nns == NULL)
526 1.20 skrll err(EXIT_FAILURE, "No memory for new string table!");
527 1.20 skrll newstrings = nns;
528 1.20 skrll nsp = newstrings + off;
529 1.20 skrll }
530 1.5 lukem /* Copy the symbol into the new table, but prepend an
531 1.5 lukem * underscore. */
532 1.5 lukem *nsp = '_';
533 1.5 lukem strcpy(nsp + 1, oldstrings + inbuf[i].st_name);
534 1.5 lukem outbuf[i].n_un.n_strx = nsp - newstrings + 4;
535 1.20 skrll nsp += len;
536 1.5 lukem
537 1.7 drochner type = ELF32_ST_TYPE(inbuf[i].st_info);
538 1.7 drochner binding = ELF32_ST_BIND(inbuf[i].st_info);
539 1.5 lukem
540 1.5 lukem /* Convert ELF symbol type/section/etc info into a.out
541 1.5 lukem * type info. */
542 1.7 drochner if (type == STT_FILE)
543 1.5 lukem outbuf[i].n_type = N_FN;
544 1.5 lukem else
545 1.22 christos outbuf[i].n_type = get_type(inbuf[i].st_shndx);
546 1.7 drochner if (binding == STB_GLOBAL)
547 1.5 lukem outbuf[i].n_type |= N_EXT;
548 1.5 lukem /* Symbol values in executables should be compatible. */
549 1.5 lukem outbuf[i].n_value = inbuf[i].st_value;
550 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
551 1.15 tsutsui outbuf[i].n_un.n_strx = bswap32(outbuf[i].n_un.n_strx);
552 1.15 tsutsui outbuf[i].n_desc = bswap16(outbuf[i].n_desc);
553 1.15 tsutsui outbuf[i].n_value = bswap32(outbuf[i].n_value);
554 1.15 tsutsui #endif
555 1.5 lukem }
556 1.5 lukem /* Write out the symbols... */
557 1.17 christos if ((i = write(out, outbuf, (size_t)cur * sizeof(struct nlist)))
558 1.17 christos != cur * (ssize_t)sizeof(struct nlist))
559 1.17 christos err(EXIT_FAILURE, "%s: write failed", __func__);
560 1.5 lukem }
561 1.5 lukem /* Write out the string table length... */
562 1.21 skrll stringsizebuf = (uint32_t)newstringsize;
563 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
564 1.15 tsutsui stringsizebuf = bswap32(stringsizebuf);
565 1.15 tsutsui #endif
566 1.15 tsutsui if (write(out, &stringsizebuf, sizeof stringsizebuf)
567 1.17 christos != sizeof stringsizebuf)
568 1.17 christos err(EXIT_FAILURE, "%s: newstringsize: write failed", __func__);
569 1.5 lukem /* Write out the string table... */
570 1.17 christos if (write(out, newstrings, newstringsize) != (ssize_t)newstringsize)
571 1.17 christos err(EXIT_FAILURE, "%s: newstrings: write failed", __func__);
572 1.17 christos free(newstrings);
573 1.16 martin free(oldstrings);
574 1.1 jonathan }
575 1.5 lukem
576 1.22 christos static void
577 1.13 tsutsui copy(int out, int in, off_t offset, off_t size)
578 1.1 jonathan {
579 1.5 lukem char ibuf[4096];
580 1.17 christos ssize_t remaining, cur, count;
581 1.1 jonathan
582 1.20 skrll /* Go to the start of the segment... */
583 1.17 christos if (lseek(in, offset, SEEK_SET) < 0)
584 1.17 christos err(EXIT_FAILURE, "%s: lseek failed", __func__);
585 1.18 martin if (size > SSIZE_MAX)
586 1.18 martin err(EXIT_FAILURE, "%s: can not copy this much", __func__);
587 1.18 martin remaining = (ssize_t)size;
588 1.5 lukem while (remaining) {
589 1.5 lukem cur = remaining;
590 1.15 tsutsui if (cur > (int)sizeof ibuf)
591 1.5 lukem cur = sizeof ibuf;
592 1.5 lukem remaining -= cur;
593 1.17 christos if ((count = read(in, ibuf, (size_t)cur)) != cur) {
594 1.17 christos if (count < 0)
595 1.17 christos err(EXIT_FAILURE, "%s: read error", __func__);
596 1.17 christos else
597 1.17 christos errx(EXIT_FAILURE, "%s: premature end of file",
598 1.17 christos __func__);
599 1.5 lukem }
600 1.17 christos if ((count = write(out, ibuf, (size_t)cur)) != cur)
601 1.17 christos err(EXIT_FAILURE, "%s: write failed", __func__);
602 1.1 jonathan }
603 1.1 jonathan }
604 1.22 christos
605 1.1 jonathan /* Combine two segments, which must be contiguous. If pad is true, it's
606 1.1 jonathan okay for there to be padding between. */
607 1.22 christos static void
608 1.13 tsutsui combine(struct sect *base, struct sect *new, int pad)
609 1.1 jonathan {
610 1.13 tsutsui
611 1.13 tsutsui if (base->len == 0)
612 1.5 lukem *base = *new;
613 1.5 lukem else
614 1.5 lukem if (new->len) {
615 1.5 lukem if (base->vaddr + base->len != new->vaddr) {
616 1.5 lukem if (pad)
617 1.5 lukem base->len = new->vaddr - base->vaddr;
618 1.17 christos else
619 1.17 christos errx(EXIT_FAILURE, "Non-contiguous "
620 1.17 christos "data can't be converted");
621 1.5 lukem }
622 1.5 lukem base->len += new->len;
623 1.5 lukem }
624 1.1 jonathan }
625 1.1 jonathan
626 1.22 christos static int
627 1.13 tsutsui phcmp(const void *vh1, const void *vh2)
628 1.1 jonathan {
629 1.12 dogcow const Elf32_Phdr *h1, *h2;
630 1.13 tsutsui
631 1.13 tsutsui h1 = (const Elf32_Phdr *)vh1;
632 1.13 tsutsui h2 = (const Elf32_Phdr *)vh2;
633 1.5 lukem
634 1.5 lukem if (h1->p_vaddr > h2->p_vaddr)
635 1.5 lukem return 1;
636 1.5 lukem else
637 1.5 lukem if (h1->p_vaddr < h2->p_vaddr)
638 1.5 lukem return -1;
639 1.5 lukem else
640 1.5 lukem return 0;
641 1.1 jonathan }
642 1.1 jonathan
643 1.22 christos static void *
644 1.17 christos saveRead(int file, off_t offset, size_t len, const char *name)
645 1.1 jonathan {
646 1.5 lukem char *tmp;
647 1.17 christos ssize_t count;
648 1.5 lukem off_t off;
649 1.17 christos
650 1.17 christos if ((off = lseek(file, offset, SEEK_SET)) < 0)
651 1.17 christos errx(EXIT_FAILURE, "%s: seek failed", name);
652 1.13 tsutsui if ((tmp = malloc(len)) == NULL)
653 1.17 christos errx(EXIT_FAILURE,
654 1.17 christos "%s: Can't allocate %jd bytes.", name, (intmax_t)len);
655 1.5 lukem count = read(file, tmp, len);
656 1.17 christos if ((size_t)count != len) {
657 1.17 christos if (count < 0)
658 1.17 christos err(EXIT_FAILURE, "%s: read error", name);
659 1.17 christos else
660 1.17 christos errx(EXIT_FAILURE, "%s: premature end of file",
661 1.17 christos name);
662 1.5 lukem }
663 1.5 lukem return tmp;
664 1.1 jonathan }
665 1.15 tsutsui
666 1.15 tsutsui #if TARGET_BYTE_ORDER != BYTE_ORDER
667 1.15 tsutsui /* swap a 32bit region */
668 1.22 christos static void
669 1.15 tsutsui bswap32_region(int32_t* p, int len)
670 1.15 tsutsui {
671 1.15 tsutsui size_t i;
672 1.15 tsutsui
673 1.15 tsutsui for (i = 0; i < len / sizeof(int32_t); i++, p++)
674 1.15 tsutsui *p = bswap32(*p);
675 1.15 tsutsui }
676 1.15 tsutsui #endif
677