elf2ecoff.c revision 1.28 1 1.28 christos /* $NetBSD: elf2ecoff.c,v 1.28 2011/08/23 20:27:22 christos Exp $ */
2 1.2 jonathan
3 1.1 jonathan /*
4 1.8 jonathan * Copyright (c) 1997 Jonathan Stone
5 1.8 jonathan * All rights reserved.
6 1.1 jonathan * Copyright (c) 1995
7 1.1 jonathan * Ted Lemon (hereinafter referred to as the author)
8 1.1 jonathan *
9 1.1 jonathan * Redistribution and use in source and binary forms, with or without
10 1.1 jonathan * modification, are permitted provided that the following conditions
11 1.1 jonathan * are met:
12 1.1 jonathan * 1. Redistributions of source code must retain the above copyright
13 1.1 jonathan * notice, this list of conditions and the following disclaimer.
14 1.1 jonathan * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 jonathan * notice, this list of conditions and the following disclaimer in the
16 1.1 jonathan * documentation and/or other materials provided with the distribution.
17 1.1 jonathan * 3. The name of the author may not be used to endorse or promote products
18 1.1 jonathan * derived from this software without specific prior written permission.
19 1.1 jonathan *
20 1.1 jonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
21 1.1 jonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 1.1 jonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 1.1 jonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
24 1.1 jonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 1.1 jonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 1.1 jonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 1.1 jonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 1.1 jonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 1.1 jonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 1.1 jonathan * SUCH DAMAGE.
31 1.1 jonathan */
32 1.1 jonathan
33 1.1 jonathan /* elf2ecoff.c
34 1.1 jonathan
35 1.1 jonathan This program converts an elf executable to an ECOFF executable.
36 1.1 jonathan No symbol table is retained. This is useful primarily in building
37 1.1 jonathan net-bootable kernels for machines (e.g., DECstation and Alpha) which
38 1.1 jonathan only support the ECOFF object file format. */
39 1.1 jonathan
40 1.21 lukem #if HAVE_NBTOOL_CONFIG_H
41 1.21 lukem #include "nbtool_config.h"
42 1.20 tv #endif
43 1.20 tv
44 1.1 jonathan #include <sys/types.h>
45 1.11 simonb #include <err.h>
46 1.12 kleink #include <errno.h>
47 1.1 jonathan #include <fcntl.h>
48 1.1 jonathan #include <unistd.h>
49 1.3 jonathan #include <sys/exec_elf.h>
50 1.1 jonathan #include <stdio.h>
51 1.1 jonathan #include <sys/exec_ecoff.h>
52 1.6 jonathan #include <stdlib.h>
53 1.1 jonathan #include <string.h>
54 1.1 jonathan #include <limits.h>
55 1.3 jonathan
56 1.6 jonathan #define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
57 1.6 jonathan
58 1.1 jonathan struct sect {
59 1.9 lukem unsigned long vaddr;
60 1.9 lukem unsigned long len;
61 1.1 jonathan };
62 1.1 jonathan
63 1.8 jonathan struct elf_syms {
64 1.9 lukem int nsymbols;
65 1.8 jonathan Elf32_Sym *elf_syms;
66 1.9 lukem off_t stringsize;
67 1.9 lukem char *stringtab;
68 1.8 jonathan };
69 1.8 jonathan
70 1.8 jonathan struct ecoff_syms {
71 1.9 lukem int nsymbols;
72 1.8 jonathan struct ecoff_extsym *ecoff_syms;
73 1.9 lukem off_t stringsize;
74 1.9 lukem char *stringtab;
75 1.8 jonathan };
76 1.8 jonathan
77 1.28 christos static int debug = 0;
78 1.28 christos static int needswap;
79 1.6 jonathan
80 1.28 christos static int phcmp(Elf32_Phdr *, Elf32_Phdr *);
81 1.28 christos static char *saveRead(int, off_t, off_t, const char *);
82 1.28 christos static void safewrite(int, const void *, off_t, const char *);
83 1.28 christos static void copy(int, int, off_t, off_t);
84 1.28 christos static void combine(struct sect *, struct sect *, int);
85 1.28 christos static void translate_syms(struct elf_syms *, struct ecoff_syms *);
86 1.28 christos static void elf_symbol_table_to_ecoff(int, int, struct ecoff_exechdr *,
87 1.28 christos off_t, off_t, off_t, off_t);
88 1.28 christos static int make_ecoff_section_hdrs(struct ecoff_exechdr *,
89 1.28 christos struct ecoff_scnhdr *);
90 1.28 christos static void write_ecoff_symhdr(int, struct ecoff_exechdr *,
91 1.28 christos struct ecoff_symhdr *, long, long, long, long);
92 1.28 christos static void pad16(int, int, const char *);
93 1.28 christos static void bswap32_region(int32_t* , int);
94 1.28 christos static void elf_read_syms(struct elf_syms *, int, off_t, off_t, off_t,
95 1.28 christos off_t);
96 1.8 jonathan
97 1.8 jonathan
98 1.6 jonathan int
99 1.28 christos main(int argc, char **argv)
100 1.1 jonathan {
101 1.9 lukem Elf32_Ehdr ex;
102 1.9 lukem Elf32_Phdr *ph;
103 1.9 lukem Elf32_Shdr *sh;
104 1.9 lukem char *shstrtab;
105 1.9 lukem int strtabix, symtabix;
106 1.23 tsutsui size_t i;
107 1.23 tsutsui int pad;
108 1.9 lukem struct sect text, data, bss; /* a.out-compatible sections */
109 1.9 lukem struct sect rdata, sdata, sbss; /* ECOFF-only sections */
110 1.9 lukem
111 1.9 lukem struct ecoff_exechdr ep;
112 1.9 lukem struct ecoff_scnhdr esecs[6];
113 1.9 lukem struct ecoff_symhdr symhdr;
114 1.9 lukem
115 1.9 lukem int infile, outfile;
116 1.9 lukem unsigned long cur_vma = ULONG_MAX;
117 1.9 lukem int symflag = 0;
118 1.9 lukem int nsecs = 0;
119 1.16 bouyer int mipsel;
120 1.16 bouyer
121 1.9 lukem
122 1.9 lukem text.len = data.len = bss.len = 0;
123 1.9 lukem text.vaddr = data.vaddr = bss.vaddr = 0;
124 1.9 lukem
125 1.9 lukem rdata.len = sdata.len = sbss.len = 0;
126 1.9 lukem rdata.vaddr = sdata.vaddr = sbss.vaddr = 0;
127 1.9 lukem
128 1.9 lukem /* Check args... */
129 1.9 lukem if (argc < 3 || argc > 4) {
130 1.9 lukem usage:
131 1.9 lukem fprintf(stderr,
132 1.28 christos "Usage: %s <elf executable> <ECOFF executable> [-s]\n",
133 1.28 christos getprogname());
134 1.9 lukem exit(1);
135 1.9 lukem }
136 1.9 lukem if (argc == 4) {
137 1.9 lukem if (strcmp(argv[3], "-s"))
138 1.9 lukem goto usage;
139 1.9 lukem symflag = 1;
140 1.1 jonathan }
141 1.9 lukem /* Try the input file... */
142 1.28 christos if ((infile = open(argv[1], O_RDONLY)) < 0)
143 1.28 christos err(1, "Can't open %s for read", argv[1]);
144 1.9 lukem /* Read the header, which is at the beginning of the file... */
145 1.9 lukem i = read(infile, &ex, sizeof ex);
146 1.28 christos if (i != sizeof ex)
147 1.28 christos err(1, "Short header read from %s", argv[1]);
148 1.16 bouyer if (ex.e_ident[EI_DATA] == ELFDATA2LSB)
149 1.16 bouyer mipsel = 1;
150 1.16 bouyer else if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
151 1.16 bouyer mipsel = 0;
152 1.28 christos else
153 1.28 christos errx(1, "invalid ELF byte order %d", ex.e_ident[EI_DATA]);
154 1.16 bouyer #if BYTE_ORDER == BIG_ENDIAN
155 1.16 bouyer if (mipsel)
156 1.16 bouyer needswap = 1;
157 1.16 bouyer else
158 1.16 bouyer needswap = 0;
159 1.16 bouyer #elif BYTE_ORDER == LITTLE_ENDIAN
160 1.16 bouyer if (mipsel)
161 1.16 bouyer needswap = 0;
162 1.16 bouyer else
163 1.16 bouyer needswap = 1;
164 1.16 bouyer #else
165 1.16 bouyer #error "unknown endian"
166 1.16 bouyer #endif
167 1.16 bouyer
168 1.16 bouyer if (needswap) {
169 1.16 bouyer ex.e_type = bswap16(ex.e_type);
170 1.16 bouyer ex.e_machine = bswap16(ex.e_machine);
171 1.16 bouyer ex.e_version = bswap32(ex.e_version);
172 1.16 bouyer ex.e_entry = bswap32(ex.e_entry);
173 1.16 bouyer ex.e_phoff = bswap32(ex.e_phoff);
174 1.16 bouyer ex.e_shoff = bswap32(ex.e_shoff);
175 1.16 bouyer ex.e_flags = bswap32(ex.e_flags);
176 1.16 bouyer ex.e_ehsize = bswap16(ex.e_ehsize);
177 1.16 bouyer ex.e_phentsize = bswap16(ex.e_phentsize);
178 1.16 bouyer ex.e_phnum = bswap16(ex.e_phnum);
179 1.16 bouyer ex.e_shentsize = bswap16(ex.e_shentsize);
180 1.16 bouyer ex.e_shnum = bswap16(ex.e_shnum);
181 1.16 bouyer ex.e_shstrndx = bswap16(ex.e_shstrndx);
182 1.16 bouyer }
183 1.16 bouyer
184 1.9 lukem /* Read the program headers... */
185 1.9 lukem ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
186 1.9 lukem ex.e_phnum * sizeof(Elf32_Phdr), "ph");
187 1.16 bouyer if (needswap)
188 1.22 simonb bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum);
189 1.9 lukem /* Read the section headers... */
190 1.9 lukem sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
191 1.9 lukem ex.e_shnum * sizeof(Elf32_Shdr), "sh");
192 1.16 bouyer if (needswap)
193 1.22 simonb bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum);
194 1.16 bouyer
195 1.9 lukem /* Read in the section string table. */
196 1.9 lukem shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
197 1.9 lukem sh[ex.e_shstrndx].sh_size, "shstrtab");
198 1.9 lukem
199 1.9 lukem
200 1.9 lukem /* Look for the symbol table and string table... Also map section
201 1.9 lukem * indices to symbol types for a.out */
202 1.9 lukem symtabix = 0;
203 1.9 lukem strtabix = 0;
204 1.9 lukem for (i = 0; i < ex.e_shnum; i++) {
205 1.9 lukem char *name = shstrtab + sh[i].sh_name;
206 1.9 lukem if (!strcmp(name, ".symtab"))
207 1.9 lukem symtabix = i;
208 1.9 lukem else
209 1.9 lukem if (!strcmp(name, ".strtab"))
210 1.9 lukem strtabix = i;
211 1.1 jonathan
212 1.9 lukem }
213 1.6 jonathan
214 1.28 christos /*
215 1.28 christos * Figure out if we can cram the program header into an ECOFF
216 1.9 lukem * header... Basically, we can't handle anything but loadable
217 1.9 lukem * segments, but we can ignore some kinds of segments. We can't
218 1.9 lukem * handle holes in the address space. Segments may be out of order,
219 1.28 christos * so we sort them first.
220 1.28 christos */
221 1.9 lukem
222 1.9 lukem qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr),
223 1.9 lukem (int (*) (const void *, const void *)) phcmp);
224 1.9 lukem
225 1.9 lukem for (i = 0; i < ex.e_phnum; i++) {
226 1.9 lukem /* Section types we can ignore... */
227 1.13 drochner if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
228 1.13 drochner ph[i].p_type == PT_PHDR ||
229 1.13 drochner ph[i].p_type == PT_MIPS_REGINFO) {
230 1.9 lukem
231 1.9 lukem if (debug) {
232 1.28 christos fprintf(stderr, " skipping PH %zu type %d "
233 1.28 christos "flags 0x%x\n",
234 1.9 lukem i, ph[i].p_type, ph[i].p_flags);
235 1.9 lukem }
236 1.9 lukem continue;
237 1.9 lukem }
238 1.9 lukem /* Section types we can't handle... */
239 1.9 lukem else
240 1.28 christos if (ph[i].p_type != PT_LOAD)
241 1.28 christos errx(1, "Program header %zu type %d can't be "
242 1.28 christos "converted", i, ph[i].p_type);
243 1.9 lukem /* Writable (data) segment? */
244 1.9 lukem if (ph[i].p_flags & PF_W) {
245 1.9 lukem struct sect ndata, nbss;
246 1.9 lukem
247 1.9 lukem ndata.vaddr = ph[i].p_vaddr;
248 1.9 lukem ndata.len = ph[i].p_filesz;
249 1.9 lukem nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
250 1.9 lukem nbss.len = ph[i].p_memsz - ph[i].p_filesz;
251 1.9 lukem
252 1.9 lukem if (debug) {
253 1.28 christos fprintf(stderr, " combinining PH %zu type %d "
254 1.28 christos "flags 0x%x with data, ndata = %ld, "
255 1.28 christos "nbss =%ld\n", i, ph[i].p_type,
256 1.28 christos ph[i].p_flags, ndata.len, nbss.len);
257 1.9 lukem }
258 1.9 lukem combine(&data, &ndata, 0);
259 1.9 lukem combine(&bss, &nbss, 1);
260 1.9 lukem } else {
261 1.9 lukem struct sect ntxt;
262 1.9 lukem
263 1.9 lukem ntxt.vaddr = ph[i].p_vaddr;
264 1.9 lukem ntxt.len = ph[i].p_filesz;
265 1.9 lukem if (debug) {
266 1.28 christos fprintf(stderr, " combinining PH %zu type %d "
267 1.28 christos "flags 0x%x with text, len = %ld\n",
268 1.9 lukem i, ph[i].p_type, ph[i].p_flags, ntxt.len);
269 1.9 lukem }
270 1.9 lukem combine(&text, &ntxt, 0);
271 1.9 lukem }
272 1.9 lukem /* Remember the lowest segment start address. */
273 1.9 lukem if (ph[i].p_vaddr < cur_vma)
274 1.9 lukem cur_vma = ph[i].p_vaddr;
275 1.1 jonathan }
276 1.1 jonathan
277 1.9 lukem /* Sections must be in order to be converted... */
278 1.9 lukem if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
279 1.28 christos text.vaddr + text.len > data.vaddr ||
280 1.28 christos data.vaddr + data.len > bss.vaddr)
281 1.28 christos errx(1, "Sections ordering prevents a.out conversion");
282 1.9 lukem /* If there's a data section but no text section, then the loader
283 1.9 lukem * combined everything into one section. That needs to be the text
284 1.9 lukem * section, so just make the data section zero length following text. */
285 1.27 tsutsui if (data.len && text.len == 0) {
286 1.9 lukem text = data;
287 1.9 lukem data.vaddr = text.vaddr + text.len;
288 1.9 lukem data.len = 0;
289 1.9 lukem }
290 1.9 lukem /* If there is a gap between text and data, we'll fill it when we copy
291 1.9 lukem * the data, so update the length of the text segment as represented
292 1.9 lukem * in a.out to reflect that, since a.out doesn't allow gaps in the
293 1.9 lukem * program address space. */
294 1.9 lukem if (text.vaddr + text.len < data.vaddr)
295 1.9 lukem text.len = data.vaddr - text.vaddr;
296 1.9 lukem
297 1.9 lukem /* We now have enough information to cons up an a.out header... */
298 1.9 lukem ep.a.magic = ECOFF_OMAGIC;
299 1.9 lukem ep.a.vstamp = 2 * 256 + 10; /* compatible with version 2.10 */
300 1.9 lukem ep.a.tsize = text.len;
301 1.9 lukem ep.a.dsize = data.len;
302 1.9 lukem ep.a.bsize = bss.len;
303 1.9 lukem ep.a.entry = ex.e_entry;
304 1.9 lukem ep.a.text_start = text.vaddr;
305 1.9 lukem ep.a.data_start = data.vaddr;
306 1.9 lukem ep.a.bss_start = bss.vaddr;
307 1.9 lukem ep.a.gprmask = 0xf3fffffe;
308 1.10 perry memset(&ep.a.cprmask, 0, sizeof ep.a.cprmask);
309 1.9 lukem ep.a.gp_value = 0; /* unused. */
310 1.9 lukem
311 1.16 bouyer if (mipsel)
312 1.15 bouyer ep.f.f_magic = ECOFF_MAGIC_MIPSEL;
313 1.16 bouyer else
314 1.15 bouyer ep.f.f_magic = ECOFF_MAGIC_MIPSEB;
315 1.15 bouyer
316 1.9 lukem ep.f.f_nscns = 6;
317 1.9 lukem ep.f.f_timdat = 0; /* bogus */
318 1.9 lukem ep.f.f_symptr = 0;
319 1.9 lukem ep.f.f_nsyms = sizeof(struct ecoff_symhdr);
320 1.9 lukem ep.f.f_opthdr = sizeof ep.a;
321 1.9 lukem ep.f.f_flags = 0x100f; /* Stripped, not sharable. */
322 1.9 lukem
323 1.10 perry memset(esecs, 0, sizeof(esecs));
324 1.9 lukem
325 1.9 lukem /* Make ECOFF section headers, with empty stubs for
326 1.9 lukem * .rdata/.sdata/.sbss. */
327 1.9 lukem make_ecoff_section_hdrs(&ep, esecs);
328 1.9 lukem
329 1.9 lukem nsecs = ep.f.f_nscns;
330 1.9 lukem
331 1.16 bouyer if (needswap) {
332 1.16 bouyer ep.f.f_magic = bswap16(ep.f.f_magic);
333 1.16 bouyer ep.f.f_nscns = bswap16(ep.f.f_nscns);
334 1.16 bouyer ep.f.f_timdat = bswap32(ep.f.f_timdat);
335 1.16 bouyer ep.f.f_symptr = bswap32(ep.f.f_symptr);
336 1.16 bouyer ep.f.f_nsyms = bswap32(ep.f.f_nsyms);
337 1.16 bouyer ep.f.f_opthdr = bswap16(ep.f.f_opthdr);
338 1.16 bouyer ep.f.f_flags = bswap16(ep.f.f_flags);
339 1.16 bouyer ep.a.magic = bswap16(ep.a.magic);
340 1.16 bouyer ep.a.vstamp = bswap16(ep.a.vstamp);
341 1.16 bouyer ep.a.tsize = bswap32(ep.a.tsize);
342 1.16 bouyer ep.a.dsize = bswap32(ep.a.dsize);
343 1.16 bouyer ep.a.bsize = bswap32(ep.a.bsize);
344 1.16 bouyer ep.a.entry = bswap32(ep.a.entry);
345 1.16 bouyer ep.a.text_start = bswap32(ep.a.text_start);
346 1.16 bouyer ep.a.data_start = bswap32(ep.a.data_start);
347 1.16 bouyer ep.a.bss_start = bswap32(ep.a.bss_start);
348 1.16 bouyer ep.a.gprmask = bswap32(ep.a.gprmask);
349 1.22 simonb bswap32_region((int32_t*)ep.a.cprmask, sizeof(ep.a.cprmask));
350 1.16 bouyer ep.a.gp_value = bswap32(ep.a.gp_value);
351 1.16 bouyer for (i = 0; i < sizeof(esecs) / sizeof(esecs[0]); i++) {
352 1.16 bouyer esecs[i].s_paddr = bswap32(esecs[i].s_paddr);
353 1.16 bouyer esecs[i].s_vaddr = bswap32(esecs[i].s_vaddr);
354 1.16 bouyer esecs[i].s_size = bswap32(esecs[i].s_size);
355 1.16 bouyer esecs[i].s_scnptr = bswap32(esecs[i].s_scnptr);
356 1.16 bouyer esecs[i].s_relptr = bswap32(esecs[i].s_relptr);
357 1.16 bouyer esecs[i].s_lnnoptr = bswap32(esecs[i].s_lnnoptr);
358 1.16 bouyer esecs[i].s_nreloc = bswap16(esecs[i].s_nreloc);
359 1.16 bouyer esecs[i].s_nlnno = bswap16(esecs[i].s_nlnno);
360 1.16 bouyer esecs[i].s_flags = bswap32(esecs[i].s_flags);
361 1.16 bouyer }
362 1.16 bouyer }
363 1.16 bouyer
364 1.9 lukem /* Make the output file... */
365 1.28 christos if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0)
366 1.28 christos err(1, "Unable to create %s", argv[2]);
367 1.28 christos
368 1.11 simonb /* Truncate file... */
369 1.11 simonb if (ftruncate(outfile, 0)) {
370 1.11 simonb warn("ftruncate %s", argv[2]);
371 1.11 simonb }
372 1.9 lukem /* Write the headers... */
373 1.28 christos safewrite(outfile, &ep.f, sizeof(ep.f), "ep.f: write");
374 1.11 simonb if (debug)
375 1.24 matt fprintf(stderr, "wrote %zu byte file header.\n", sizeof(ep.f));
376 1.9 lukem
377 1.28 christos safewrite(outfile, &ep.a, sizeof(ep.a), "ep.a: write");
378 1.11 simonb if (debug)
379 1.24 matt fprintf(stderr, "wrote %zu byte a.out header.\n", sizeof(ep.a));
380 1.9 lukem
381 1.28 christos safewrite(outfile, &esecs, sizeof(esecs[0]) * nsecs, "esecs: write");
382 1.11 simonb if (debug)
383 1.24 matt fprintf(stderr, "wrote %zu bytes of section headers.\n",
384 1.11 simonb sizeof(esecs[0]) * nsecs);
385 1.9 lukem
386 1.9 lukem
387 1.9 lukem pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15);
388 1.9 lukem if (pad) {
389 1.9 lukem pad = 16 - pad;
390 1.28 christos pad16(outfile, pad, "ipad: write");
391 1.11 simonb if (debug)
392 1.11 simonb fprintf(stderr, "wrote %d byte pad.\n", pad);
393 1.9 lukem }
394 1.9 lukem /* Copy the loadable sections. Zero-fill any gaps less than 64k;
395 1.9 lukem * complain about any zero-filling, and die if we're asked to
396 1.9 lukem * zero-fill more than 64k. */
397 1.9 lukem for (i = 0; i < ex.e_phnum; i++) {
398 1.9 lukem /* Unprocessable sections were handled above, so just verify
399 1.9 lukem * that the section can be loaded before copying. */
400 1.13 drochner if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
401 1.9 lukem if (cur_vma != ph[i].p_vaddr) {
402 1.9 lukem unsigned long gap = ph[i].p_vaddr - cur_vma;
403 1.9 lukem char obuf[1024];
404 1.28 christos if (gap > 65536)
405 1.28 christos errx(1, "Intersegment gap (%ld bytes) "
406 1.28 christos "too large", gap);
407 1.11 simonb if (debug)
408 1.28 christos fprintf(stderr, "Warning: %ld byte "
409 1.28 christos "intersegment gap.\n", gap);
410 1.9 lukem memset(obuf, 0, sizeof obuf);
411 1.9 lukem while (gap) {
412 1.28 christos int count = write(outfile, obuf,
413 1.28 christos (gap > sizeof obuf
414 1.28 christos ? sizeof obuf : gap));
415 1.28 christos if (count < 0)
416 1.28 christos err(1, "Error writing gap");
417 1.9 lukem gap -= count;
418 1.9 lukem }
419 1.9 lukem }
420 1.11 simonb if (debug)
421 1.28 christos fprintf(stderr, "writing %d bytes...\n",
422 1.28 christos ph[i].p_filesz);
423 1.9 lukem copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
424 1.9 lukem cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
425 1.9 lukem }
426 1.9 lukem }
427 1.9 lukem
428 1.9 lukem
429 1.9 lukem if (debug)
430 1.9 lukem fprintf(stderr, "writing syms at offset 0x%lx\n",
431 1.9 lukem (u_long) ep.f.f_symptr + sizeof(symhdr));
432 1.9 lukem
433 1.9 lukem /* Copy and translate the symbol table... */
434 1.9 lukem elf_symbol_table_to_ecoff(outfile, infile, &ep,
435 1.9 lukem sh[symtabix].sh_offset, sh[symtabix].sh_size,
436 1.9 lukem sh[strtabix].sh_offset, sh[strtabix].sh_size);
437 1.9 lukem
438 1.9 lukem /*
439 1.9 lukem * Write a page of padding for boot PROMS that read entire pages.
440 1.9 lukem * Without this, they may attempt to read past the end of the
441 1.9 lukem * data section, incur an error, and refuse to boot.
442 1.9 lukem */
443 1.1 jonathan {
444 1.9 lukem char obuf[4096];
445 1.9 lukem memset(obuf, 0, sizeof obuf);
446 1.28 christos if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf))
447 1.28 christos err(1, "Error writing PROM padding");
448 1.9 lukem }
449 1.6 jonathan
450 1.9 lukem /* Looks like we won... */
451 1.28 christos return 0;
452 1.1 jonathan }
453 1.1 jonathan
454 1.28 christos static void
455 1.27 tsutsui copy(int out, int in, off_t offset, off_t size)
456 1.9 lukem {
457 1.9 lukem char ibuf[4096];
458 1.23 tsutsui size_t remaining, cur, count;
459 1.9 lukem
460 1.14 soren /* Go to the start of the ELF symbol table... */
461 1.28 christos if (lseek(in, offset, SEEK_SET) < 0)
462 1.28 christos err(1, "copy: lseek");
463 1.9 lukem remaining = size;
464 1.9 lukem while (remaining) {
465 1.9 lukem cur = remaining;
466 1.9 lukem if (cur > sizeof ibuf)
467 1.9 lukem cur = sizeof ibuf;
468 1.9 lukem remaining -= cur;
469 1.28 christos if ((count = read(in, ibuf, cur)) != cur)
470 1.28 christos err(1, "copy: short read");
471 1.28 christos safewrite(out, ibuf, cur, "copy: write");
472 1.1 jonathan }
473 1.1 jonathan }
474 1.28 christos
475 1.1 jonathan /* Combine two segments, which must be contiguous. If pad is true, it's
476 1.1 jonathan okay for there to be padding between. */
477 1.28 christos static void
478 1.27 tsutsui combine(struct sect *base, struct sect *new, int pad)
479 1.9 lukem {
480 1.27 tsutsui
481 1.27 tsutsui if (base->len == 0)
482 1.9 lukem *base = *new;
483 1.9 lukem else
484 1.9 lukem if (new->len) {
485 1.9 lukem if (base->vaddr + base->len != new->vaddr) {
486 1.9 lukem if (pad)
487 1.9 lukem base->len = new->vaddr - base->vaddr;
488 1.28 christos else
489 1.28 christos errx(1, "Non-contiguous data can't be "
490 1.28 christos "converted");
491 1.9 lukem }
492 1.9 lukem base->len += new->len;
493 1.9 lukem }
494 1.1 jonathan }
495 1.1 jonathan
496 1.28 christos static int
497 1.27 tsutsui phcmp(Elf32_Phdr *h1, Elf32_Phdr *h2)
498 1.1 jonathan {
499 1.27 tsutsui
500 1.9 lukem if (h1->p_vaddr > h2->p_vaddr)
501 1.9 lukem return 1;
502 1.9 lukem else
503 1.9 lukem if (h1->p_vaddr < h2->p_vaddr)
504 1.9 lukem return -1;
505 1.9 lukem else
506 1.9 lukem return 0;
507 1.1 jonathan }
508 1.1 jonathan
509 1.28 christos static char *
510 1.23 tsutsui saveRead(int file, off_t offset, off_t len, const char *name)
511 1.1 jonathan {
512 1.9 lukem char *tmp;
513 1.9 lukem int count;
514 1.9 lukem off_t off;
515 1.27 tsutsui
516 1.28 christos if ((off = lseek(file, offset, SEEK_SET)) < 0)
517 1.28 christos err(1, "%s: fseek", name);
518 1.28 christos if ((tmp = malloc(len)) == NULL)
519 1.28 christos err(1, "%s: Can't allocate %ld bytes", name, (long) len);
520 1.9 lukem count = read(file, tmp, len);
521 1.28 christos if (count != len)
522 1.28 christos err(1, "%s: short read", name);
523 1.9 lukem return tmp;
524 1.6 jonathan }
525 1.6 jonathan
526 1.28 christos static void
527 1.23 tsutsui safewrite(int outfile, const void *buf, off_t len, const char *msg)
528 1.8 jonathan {
529 1.28 christos ssize_t written;
530 1.27 tsutsui
531 1.23 tsutsui written = write(outfile, buf, len);
532 1.28 christos if (written != len)
533 1.28 christos err(1, "%s", msg);
534 1.8 jonathan }
535 1.8 jonathan
536 1.6 jonathan
537 1.8 jonathan /*
538 1.8 jonathan * Output only three ECOFF sections, corresponding to ELF psecs
539 1.8 jonathan * for text, data, and bss.
540 1.6 jonathan */
541 1.28 christos static int
542 1.27 tsutsui make_ecoff_section_hdrs(struct ecoff_exechdr *ep, struct ecoff_scnhdr *esecs)
543 1.27 tsutsui {
544 1.6 jonathan
545 1.8 jonathan ep->f.f_nscns = 6; /* XXX */
546 1.6 jonathan
547 1.9 lukem strcpy(esecs[0].s_name, ".text");
548 1.9 lukem strcpy(esecs[1].s_name, ".data");
549 1.9 lukem strcpy(esecs[2].s_name, ".bss");
550 1.9 lukem
551 1.9 lukem esecs[0].s_paddr = esecs[0].s_vaddr = ep->a.text_start;
552 1.9 lukem esecs[1].s_paddr = esecs[1].s_vaddr = ep->a.data_start;
553 1.9 lukem esecs[2].s_paddr = esecs[2].s_vaddr = ep->a.bss_start;
554 1.9 lukem esecs[0].s_size = ep->a.tsize;
555 1.9 lukem esecs[1].s_size = ep->a.dsize;
556 1.9 lukem esecs[2].s_size = ep->a.bsize;
557 1.6 jonathan
558 1.9 lukem esecs[0].s_scnptr = ECOFF_TXTOFF(ep);
559 1.9 lukem esecs[1].s_scnptr = ECOFF_DATOFF(ep);
560 1.6 jonathan #if 0
561 1.9 lukem esecs[2].s_scnptr = esecs[1].s_scnptr +
562 1.9 lukem ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(ep));
563 1.6 jonathan #endif
564 1.6 jonathan
565 1.9 lukem esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
566 1.9 lukem esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
567 1.9 lukem esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
568 1.9 lukem esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
569 1.8 jonathan
570 1.8 jonathan esecs[1].s_flags = 0x100; /* ECOFF rdata */
571 1.8 jonathan esecs[3].s_flags = 0x200; /* ECOFF sdata */
572 1.8 jonathan esecs[4].s_flags = 0x400; /* ECOFF sbss */
573 1.8 jonathan
574 1.8 jonathan /*
575 1.8 jonathan * Set the symbol-table offset to point at the end of any
576 1.8 jonathan * sections we loaded above, so later code can use it to write
577 1.8 jonathan * symbol table info..
578 1.8 jonathan */
579 1.8 jonathan ep->f.f_symptr = esecs[1].s_scnptr + esecs[1].s_size;
580 1.9 lukem return (ep->f.f_nscns);
581 1.8 jonathan }
582 1.8 jonathan
583 1.8 jonathan
584 1.8 jonathan /*
585 1.8 jonathan * Write the ECOFF symbol header.
586 1.8 jonathan * Guess at how big the symbol table will be.
587 1.8 jonathan * Mark all symbols as EXTERN (for now).
588 1.8 jonathan */
589 1.28 christos static void
590 1.27 tsutsui write_ecoff_symhdr(int out, struct ecoff_exechdr *ep,
591 1.27 tsutsui struct ecoff_symhdr *symhdrp, long nesyms,
592 1.27 tsutsui long extsymoff, long extstroff, long strsize)
593 1.8 jonathan {
594 1.27 tsutsui
595 1.8 jonathan if (debug)
596 1.28 christos fprintf(stderr,
597 1.28 christos "writing symhdr for %ld entries at offset 0x%lx\n",
598 1.9 lukem nesyms, (u_long) ep->f.f_symptr);
599 1.8 jonathan
600 1.9 lukem ep->f.f_nsyms = sizeof(struct ecoff_symhdr);
601 1.8 jonathan
602 1.10 perry memset(symhdrp, 0, sizeof(*symhdrp));
603 1.8 jonathan symhdrp->esymMax = nesyms;
604 1.9 lukem symhdrp->magic = 0x7009;/* XXX */
605 1.8 jonathan symhdrp->cbExtOffset = extsymoff;
606 1.8 jonathan symhdrp->cbSsExtOffset = extstroff;
607 1.8 jonathan
608 1.8 jonathan symhdrp->issExtMax = strsize;
609 1.8 jonathan if (debug)
610 1.8 jonathan fprintf(stderr,
611 1.24 matt "ECOFF symhdr: symhdr %zx, strsize %lx, symsize %lx\n",
612 1.8 jonathan sizeof(*symhdrp), strsize,
613 1.8 jonathan (nesyms * sizeof(struct ecoff_extsym)));
614 1.8 jonathan
615 1.16 bouyer if (needswap) {
616 1.22 simonb bswap32_region(&symhdrp->ilineMax,
617 1.16 bouyer sizeof(*symhdrp) - sizeof(symhdrp->magic) -
618 1.16 bouyer sizeof(symhdrp->ilineMax));
619 1.16 bouyer symhdrp->magic = bswap16(symhdrp->magic);
620 1.16 bouyer symhdrp->ilineMax = bswap16(symhdrp->ilineMax);
621 1.16 bouyer }
622 1.27 tsutsui
623 1.8 jonathan safewrite(out, symhdrp, sizeof(*symhdrp),
624 1.28 christos "writing symbol header");
625 1.8 jonathan }
626 1.8 jonathan
627 1.8 jonathan
628 1.28 christos static void
629 1.27 tsutsui elf_read_syms(struct elf_syms *elfsymsp, int in, off_t symoff, off_t symsize,
630 1.27 tsutsui off_t stroff, off_t strsize)
631 1.8 jonathan {
632 1.8 jonathan register int nsyms;
633 1.16 bouyer int i;
634 1.9 lukem nsyms = symsize / sizeof(Elf32_Sym);
635 1.8 jonathan
636 1.8 jonathan /* Suck in the ELF symbol list... */
637 1.8 jonathan elfsymsp->elf_syms = (Elf32_Sym *)
638 1.9 lukem saveRead(in, symoff, nsyms * sizeof(Elf32_Sym),
639 1.9 lukem "ELF symboltable");
640 1.8 jonathan elfsymsp->nsymbols = nsyms;
641 1.16 bouyer if (needswap) {
642 1.16 bouyer for (i = 0; i < nsyms; i++) {
643 1.16 bouyer Elf32_Sym *s = &elfsymsp->elf_syms[i];
644 1.16 bouyer s->st_name = bswap32(s->st_name);
645 1.16 bouyer s->st_value = bswap32(s->st_value);
646 1.16 bouyer s->st_size = bswap32(s->st_size);
647 1.16 bouyer s->st_shndx = bswap16(s->st_shndx);
648 1.16 bouyer }
649 1.16 bouyer }
650 1.8 jonathan
651 1.8 jonathan /* Suck in the ELF string table... */
652 1.8 jonathan elfsymsp->stringtab = (char *)
653 1.9 lukem saveRead(in, stroff, strsize, "ELF string table");
654 1.8 jonathan elfsymsp->stringsize = strsize;
655 1.8 jonathan }
656 1.8 jonathan
657 1.8 jonathan
658 1.28 christos static void
659 1.27 tsutsui elf_symbol_table_to_ecoff(int out, int in, struct ecoff_exechdr *ep,
660 1.27 tsutsui off_t symoff, off_t symsize, off_t stroff, off_t strsize)
661 1.8 jonathan {
662 1.8 jonathan
663 1.8 jonathan struct elf_syms elfsymtab;
664 1.8 jonathan struct ecoff_syms ecoffsymtab;
665 1.8 jonathan register u_long ecoff_symhdr_off, symtaboff, stringtaboff;
666 1.8 jonathan register u_long nextoff, symtabsize, ecoff_strsize;
667 1.16 bouyer int nsyms, i;
668 1.8 jonathan struct ecoff_symhdr symhdr;
669 1.9 lukem int padding;
670 1.9 lukem
671 1.8 jonathan /* Read in the ELF symbols. */
672 1.8 jonathan elf_read_syms(&elfsymtab, in, symoff, symsize, stroff, strsize);
673 1.8 jonathan
674 1.8 jonathan /* Approximate translation to ECOFF. */
675 1.8 jonathan translate_syms(&elfsymtab, &ecoffsymtab);
676 1.8 jonathan nsyms = ecoffsymtab.nsymbols;
677 1.8 jonathan
678 1.9 lukem /* Compute output ECOFF symbol- and string-table offsets. */
679 1.8 jonathan ecoff_symhdr_off = ep->f.f_symptr;
680 1.8 jonathan
681 1.8 jonathan nextoff = ecoff_symhdr_off + sizeof(struct ecoff_symhdr);
682 1.8 jonathan stringtaboff = nextoff;
683 1.8 jonathan ecoff_strsize = ECOFF_ROUND(ecoffsymtab.stringsize,
684 1.9 lukem (ECOFF_SEGMENT_ALIGNMENT(ep)));
685 1.8 jonathan
686 1.8 jonathan
687 1.8 jonathan nextoff = stringtaboff + ecoff_strsize;
688 1.8 jonathan symtaboff = nextoff;
689 1.8 jonathan symtabsize = nsyms * sizeof(struct ecoff_extsym);
690 1.8 jonathan symtabsize = ECOFF_ROUND(symtabsize, ECOFF_SEGMENT_ALIGNMENT(ep));
691 1.8 jonathan
692 1.8 jonathan /* Write out the symbol header ... */
693 1.9 lukem write_ecoff_symhdr(out, ep, &symhdr, nsyms, symtaboff,
694 1.9 lukem stringtaboff, ecoffsymtab.stringsize);
695 1.8 jonathan
696 1.8 jonathan /* Write out the string table... */
697 1.8 jonathan padding = ecoff_strsize - ecoffsymtab.stringsize;
698 1.9 lukem safewrite(out, ecoffsymtab.stringtab, ecoffsymtab.stringsize,
699 1.28 christos "string table: write");
700 1.8 jonathan if (padding)
701 1.28 christos pad16(out, padding, "string table: padding");
702 1.8 jonathan
703 1.8 jonathan
704 1.8 jonathan /* Write out the symbol table... */
705 1.9 lukem padding = symtabsize - (nsyms * sizeof(struct ecoff_extsym));
706 1.16 bouyer
707 1.16 bouyer for (i = 0; i < nsyms; i++) {
708 1.16 bouyer struct ecoff_extsym *es = &ecoffsymtab.ecoff_syms[i];
709 1.16 bouyer es->es_flags = bswap16(es->es_flags);
710 1.16 bouyer es->es_ifd = bswap16(es->es_ifd);
711 1.16 bouyer bswap32_region(&es->es_strindex,
712 1.16 bouyer sizeof(*es) - sizeof(es->es_flags) - sizeof(es->es_ifd));
713 1.16 bouyer }
714 1.9 lukem safewrite(out, ecoffsymtab.ecoff_syms,
715 1.8 jonathan nsyms * sizeof(struct ecoff_extsym),
716 1.28 christos "symbol table: write");
717 1.8 jonathan if (padding)
718 1.28 christos pad16(out, padding, "symbols: padding");
719 1.8 jonathan }
720 1.8 jonathan
721 1.8 jonathan
722 1.8 jonathan
723 1.8 jonathan /*
724 1.8 jonathan * In-memory translation of ELF symbosl to ECOFF.
725 1.8 jonathan */
726 1.28 christos static void
727 1.27 tsutsui translate_syms(struct elf_syms *elfp, struct ecoff_syms *ecoffp)
728 1.8 jonathan {
729 1.6 jonathan
730 1.9 lukem int i;
731 1.9 lukem char *oldstringbase;
732 1.9 lukem char *newstrings, *nsp;
733 1.9 lukem
734 1.9 lukem int nsyms, idx;
735 1.9 lukem
736 1.9 lukem nsyms = elfp->nsymbols;
737 1.9 lukem oldstringbase = elfp->stringtab;
738 1.9 lukem
739 1.9 lukem /* Allocate space for corresponding ECOFF symbols. */
740 1.10 perry memset(ecoffp, 0, sizeof(*ecoffp));
741 1.9 lukem
742 1.9 lukem ecoffp->nsymbols = 0;
743 1.9 lukem ecoffp->ecoff_syms = malloc(sizeof(struct ecoff_extsym) * nsyms);
744 1.9 lukem
745 1.9 lukem /* we are going to be no bigger than the ELF symbol table. */
746 1.9 lukem ecoffp->stringsize = elfp->stringsize;
747 1.9 lukem ecoffp->stringtab = malloc(elfp->stringsize);
748 1.9 lukem
749 1.9 lukem newstrings = (char *) ecoffp->stringtab;
750 1.9 lukem nsp = (char *) ecoffp->stringtab;
751 1.28 christos if (newstrings == NULL)
752 1.28 christos errx(1, "No memory for new string table");
753 1.9 lukem /* Copy and translate symbols... */
754 1.9 lukem idx = 0;
755 1.9 lukem for (i = 0; i < nsyms; i++) {
756 1.9 lukem int binding, type;
757 1.9 lukem
758 1.13 drochner binding = ELF32_ST_BIND((elfp->elf_syms[i].st_info));
759 1.13 drochner type = ELF32_ST_TYPE((elfp->elf_syms[i].st_info));
760 1.9 lukem
761 1.9 lukem /* skip strange symbols */
762 1.9 lukem if (binding == 0) {
763 1.9 lukem continue;
764 1.9 lukem }
765 1.9 lukem /* Copy the symbol into the new table */
766 1.9 lukem strcpy(nsp, oldstringbase + elfp->elf_syms[i].st_name);
767 1.9 lukem ecoffp->ecoff_syms[idx].es_strindex = nsp - newstrings;
768 1.9 lukem nsp += strlen(nsp) + 1;
769 1.9 lukem
770 1.9 lukem /* translate symbol types to ECOFF XXX */
771 1.9 lukem ecoffp->ecoff_syms[idx].es_type = 1;
772 1.9 lukem ecoffp->ecoff_syms[idx].es_class = 5;
773 1.9 lukem
774 1.9 lukem /* Symbol values in executables should be compatible. */
775 1.9 lukem ecoffp->ecoff_syms[idx].es_value = elfp->elf_syms[i].st_value;
776 1.9 lukem ecoffp->ecoff_syms[idx].es_symauxindex = 0xfffff;
777 1.8 jonathan
778 1.9 lukem idx++;
779 1.8 jonathan }
780 1.8 jonathan
781 1.9 lukem ecoffp->nsymbols = idx;
782 1.9 lukem ecoffp->stringsize = nsp - newstrings;
783 1.8 jonathan }
784 1.8 jonathan /*
785 1.8 jonathan * pad to a 16-byte boundary
786 1.8 jonathan */
787 1.28 christos static void
788 1.8 jonathan pad16(int fd, int size, const char *msg)
789 1.8 jonathan {
790 1.27 tsutsui
791 1.9 lukem safewrite(fd, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", size, msg);
792 1.16 bouyer }
793 1.16 bouyer
794 1.16 bouyer /* swap a 32bit region */
795 1.28 christos static void
796 1.22 simonb bswap32_region(int32_t* p, int len)
797 1.16 bouyer {
798 1.23 tsutsui size_t i;
799 1.16 bouyer
800 1.22 simonb for (i = 0; i < len / sizeof(int32_t); i++, p++)
801 1.16 bouyer *p = bswap32(*p);
802 1.1 jonathan }
803