1 /* $NetBSD: elf2bb.c,v 1.30 2022/04/29 07:12:42 rin Exp $ */
2
3 /*-
4 * Copyright (c) 1996,2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ignatios Souvatzis.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35
36 #include <sys/param.h>
37 #include <sys/types.h>
38
39 #include <err.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #include <sys/mman.h> /* of the machine we're running on */
47
48 #ifndef HAVE_NBTOOL_CONFIG_H
49 #include <sys/endian.h> /* of the machine we're running on */
50 #endif
51
52 #include <sys/exec_elf.h> /* TARGET */
53 #ifndef R_68K_32 /* XXX host not m68k XXX */
54 #define R_68K_32 1
55 #define R_68K_PC32 4
56 #define R_68K_PC16 5
57 #endif
58
59 #include "elf2bb.h"
60 #include "chksum.h"
61
62 static void usage(void);
63 static int intcmp(const void *, const void *);
64 static int eval(Elf32_Sym *, uint32_t *);
65
66 #ifdef DEBUG
67 #define dprintf(x) if (debug) printf x
68 #else
69 #define dprintf(x)
70 #endif
71 int debug;
72
73 #define BBSIZE 8192
74
75 char *progname;
76 int bbsize = BBSIZE;
77 uint8_t *buffer;
78 uint32_t *relbuf;
79 /* can't have more relocs than that */
80
81 static int
intcmp(const void * i,const void * j)82 intcmp(const void *i, const void *j)
83 {
84 int r;
85
86 r = (*(uint32_t *)i) < (*(uint32_t *)j);
87
88 return 2 * r - 1;
89 }
90
91 int
main(int argc,char * argv[])92 main(int argc, char *argv[])
93 {
94 int ifd, ofd;
95 void *image;
96 Elf32_Ehdr *eh;
97 Elf32_Shdr *sh;
98 char *shstrtab;
99 Elf32_Sym *symtab;
100 char *strtab;
101 uint32_t *lptr;
102 int i, l, delta;
103 uint8_t *rpo;
104 uint32_t oldaddr, addrdiff;
105 uint32_t tsz, dsz, bsz, trsz, relver;
106 uint32_t pcrelsz, r32sz;
107 int sumsize = 16;
108 int c;
109 uint32_t *sect_offset;
110 int undefsyms;
111 uint32_t tmp32;
112 uint16_t tmp16;
113 int Sflag = 0;
114
115 progname = argv[0];
116
117 /* insert getopt here, if needed */
118 while ((c = getopt(argc, argv, "dFS")) != -1)
119 switch(c) {
120 case 'F':
121 sumsize = 2;
122 break;
123 case 'S':
124 /* Dynamically size second-stage boot */
125 Sflag = 1;
126 break;
127 case 'd':
128 debug = 1;
129 break;
130 default:
131 usage();
132 }
133 argv += optind;
134 argc -= optind;
135
136 if (argc < 2)
137 usage();
138
139 ifd = open(argv[0], O_RDONLY, 0);
140 if (ifd < 0)
141 err(1, "Can't open %s", argv[0]);
142
143 image = mmap(0, 65536, PROT_READ, MAP_FILE|MAP_PRIVATE, ifd, 0);
144 if (image == MAP_FAILED)
145 err(1, "Can't mmap %s", argv[1]);
146
147 eh = (Elf32_Ehdr *)image; /* XXX endianness */
148
149 dprintf(("%04x sections, offset %08x\n", be16toh(eh->e_shnum),
150 be32toh(eh->e_shoff)));
151 if (be16toh(eh->e_type) != ET_REL)
152 errx(1, "%s isn't a relocatable file, type=%d",
153 argv[0], be16toh(eh->e_type));
154 if (be16toh(eh->e_machine) != EM_68K)
155 errx(1, "%s isn't M68K, machine=%d", argv[0],
156 be16toh(eh->e_machine));
157
158 /* Calculate sizes from section headers. */
159 tsz = dsz = bsz = trsz = 0;
160 sh = (Elf32_Shdr *)(image + be32toh(eh->e_shoff));
161 shstrtab = (char *)(image +
162 be32toh(sh[be16toh(eh->e_shstrndx)].sh_offset));
163 symtab = NULL; /* XXX */
164 strtab = NULL; /* XXX */
165 dprintf((" name type flags"
166 " addr offset size align\n"));
167 for (i = 0; i < be16toh(eh->e_shnum); ++i) {
168 uint32_t sh_size;
169
170 dprintf(("%2d: %08x %-16s %08x %08x %08x %08x %08x %08x\n", i,
171 be32toh(sh[i].sh_name), shstrtab + be32toh(sh[i].sh_name),
172 be32toh(sh[i].sh_type), be32toh(sh[i].sh_flags),
173 be32toh(sh[i].sh_addr), be32toh(sh[i].sh_offset),
174 be32toh(sh[i].sh_size), be32toh(sh[i].sh_addralign)));
175 sh_size = (be32toh(sh[i].sh_size) +
176 be32toh(sh[i].sh_addralign) - 1) &
177 (- be32toh(sh[i].sh_addralign));
178 /*
179 * If section allocates memory, add to text, data,
180 * or bss size.
181 */
182 if (be32toh(sh[i].sh_flags) & SHF_ALLOC) {
183 if (be32toh(sh[i].sh_type) == SHT_PROGBITS) {
184 if (be32toh(sh[i].sh_flags) & SHF_WRITE)
185 dsz += sh_size;
186 else
187 tsz += sh_size;
188 } else
189 bsz += sh_size;
190 /* If it's relocations, add to relocation count */
191 } else if (be32toh(sh[i].sh_type) == SHT_RELA) {
192 trsz += be32toh(sh[i].sh_size);
193 }
194 /* Check for SHT_REL? */
195 /* Get symbol table location. */
196 else if (be32toh(sh[i].sh_type) == SHT_SYMTAB) {
197 symtab = (Elf32_Sym *)(image +
198 be32toh(sh[i].sh_offset));
199 } else if (strcmp(".strtab", shstrtab +
200 be32toh(sh[i].sh_name)) == 0) {
201 strtab = image + be32toh(sh[i].sh_offset);
202 }
203 }
204 dprintf(("tsz = 0x%x, dsz = 0x%x, bsz = 0x%x, total 0x%x\n",
205 tsz, dsz, bsz, tsz + dsz + bsz));
206
207 if (trsz == 0)
208 errx(1, "%s has no relocation records.", argv[0]);
209
210 dprintf(("%d relocs\n", trsz / 12));
211
212 if (Sflag) {
213 /*
214 * For second-stage boot, there's no limit for binary size,
215 * and we dynamically scale it. However, it should be small
216 * enough so that
217 *
218 * (1) all R_68K_PC16 symbols get relocated, and
219 *
220 * (2) all values in our relocation table for R_68K_32
221 * symbols fit within 16-bit integer.
222 *
223 * Both will be checked by codes below.
224 *
225 * At the moment, (2) is satisfied with sufficient margin.
226 * But if it is not the case in the future, format for
227 * relocation table should be modified.
228 */
229 bbsize = roundup(tsz + dsz, 512);
230 sumsize = bbsize / 512;
231 } else {
232 /*
233 * We have one contiguous area allocated by the ROM to us.
234 */
235 if (tsz + dsz + bsz > bbsize)
236 errx(1, "%s: resulting image too big %d+%d+%d=%d",
237 argv[0], tsz, dsz, bsz, tsz + dsz + bsz);
238 }
239
240 buffer = NULL;
241 relbuf = NULL;
242
243 retry:
244 pcrelsz = r32sz = 0;
245
246 buffer = realloc(buffer, bbsize);
247 relbuf = realloc(relbuf, bbsize);
248 if (buffer == NULL || relbuf == NULL)
249 err(1, "Unable to allocate memory\n");
250
251 memset(buffer, 0, bbsize);
252
253 /* Allocate and load loadable sections */
254 sect_offset = malloc(be16toh(eh->e_shnum) * sizeof(uint32_t));
255 for (i = 0, l = 0; i < be16toh(eh->e_shnum); ++i) {
256 if (be32toh(sh[i].sh_flags) & SHF_ALLOC) {
257 dprintf(("vaddr 0x%04x size 0x%04x offset 0x%04x section %s\n",
258 l, be32toh(sh[i].sh_size), be32toh(sh[i].sh_offset),
259 shstrtab + be32toh(sh[i].sh_name)));
260 if (be32toh(sh[i].sh_type) == SHT_PROGBITS)
261 memcpy(buffer + l,
262 image + be32toh(sh[i].sh_offset),
263 be32toh(sh[i].sh_size));
264 sect_offset[i] = l;
265 l += (be32toh(sh[i].sh_size) +
266 be32toh(sh[i].sh_addralign) - 1) &
267 (- be32toh(sh[i].sh_addralign));
268 }
269 }
270
271 /*
272 * Hm. This tool REALLY should understand more than one
273 * relocator version. For now, check that the relocator at
274 * the image start does understand what we output.
275 */
276 relver = be32toh(*(uint32_t *)(buffer + 4));
277 switch (relver) {
278 default:
279 errx(1, "%s: unrecognized relocator version %d",
280 argv[0], relver);
281 /* NOTREACHED */
282
283 case RELVER_RELATIVE_BYTES:
284 rpo = buffer + bbsize - 1;
285 delta = -1;
286 break;
287
288 case RELVER_RELATIVE_BYTES_FORWARD:
289 rpo = buffer + tsz + dsz;
290 delta = +1;
291 *(uint16_t *)(buffer + 14) /* reltab */ = htobe16(tsz + dsz);
292 break;
293 }
294
295 if (symtab == NULL)
296 errx(1, "No symbol table found");
297 /*
298 * Link sections and generate relocation data
299 * Nasty: .text, .rodata, .data, .bss sections are not linked
300 * Symbol table values relative to start of sections.
301 * For each relocation entry:
302 * Symbol value needs to be calculated: value + section offset
303 * Image data adjusted to calculated value of symbol + addend
304 * Add relocation table entry for 32-bit relocatable values
305 * PC-relative entries will be absolute and don't need relocation
306 */
307 undefsyms = 0;
308 for (i = 0; i < be16toh(eh->e_shnum); ++i) {
309 int n;
310 Elf32_Rela *ra;
311 uint8_t *base;
312
313 if (be32toh(sh[i].sh_type) != SHT_RELA)
314 continue;
315 base = NULL;
316 if (strncmp(shstrtab + be32toh(sh[i].sh_name), ".rela", 5) != 0)
317 err(1, "bad relocation section name %s",
318 shstrtab + be32toh(sh[i].sh_name));
319 for (n = 0; n < be16toh(eh->e_shnum); ++n) {
320 if (strcmp(shstrtab + be32toh(sh[i].sh_name) + 5,
321 shstrtab + be32toh(sh[n].sh_name)) != 0)
322 continue;
323 base = buffer + sect_offset[n];
324 break;
325 }
326 if (base == NULL)
327 errx(1, "Can't find section for reloc %s",
328 shstrtab + be32toh(sh[i].sh_name));
329 ra = (Elf32_Rela *)(image + be32toh(sh[i].sh_offset));
330 for (n = 0; n < be32toh(sh[i].sh_size);
331 n += sizeof(Elf32_Rela), ++ra) {
332 Elf32_Sym *s;
333 int value;
334
335 s = &symtab[ELF32_R_SYM(be32toh(ra->r_info))];
336 if (s->st_shndx == ELF_SYM_UNDEFINED) {
337 fprintf(stderr, "Undefined symbol: %s\n",
338 strtab + be32toh(s->st_name));
339 ++undefsyms;
340 }
341 value = be32toh(ra->r_addend) + eval(s, sect_offset);
342 dprintf(("reloc %04x info %04x (type %d sym %d) add 0x%x val %x\n",
343 be32toh(ra->r_offset), be32toh(ra->r_info),
344 ELF32_R_TYPE(be32toh(ra->r_info)),
345 ELF32_R_SYM(be32toh(ra->r_info)),
346 be32toh(ra->r_addend), value));
347 switch (ELF32_R_TYPE(be32toh(ra->r_info))) {
348 case R_68K_32:
349 tmp32 = htobe32(value);
350 memcpy(base + be32toh(ra->r_offset), &tmp32,
351 sizeof(tmp32));
352 relbuf[r32sz++] = (base - buffer) +
353 be32toh(ra->r_offset);
354 break;
355 case R_68K_PC32:
356 ++pcrelsz;
357 tmp32 = htobe32(value - be32toh(ra->r_offset));
358 memcpy(base + be32toh(ra->r_offset), &tmp32,
359 sizeof(tmp32));
360 break;
361 case R_68K_PC16:
362 ++pcrelsz;
363 value -= be32toh(ra->r_offset);
364 if (value < -0x8000 || value > 0x7fff)
365 errx(1, "PC-relative offset out of range: %x\n",
366 value);
367 tmp16 = htobe16(value);
368 memcpy(base + be32toh(ra->r_offset), &tmp16,
369 sizeof(tmp16));
370 break;
371 default:
372 errx(1, "Relocation type %d not supported",
373 ELF32_R_TYPE(be32toh(ra->r_info)));
374 }
375 }
376 }
377 dprintf(("%d PC-relative relocations, %d 32-bit relocations\n",
378 pcrelsz, r32sz));
379 printf("%d absolute reloc%s found, ", r32sz, r32sz == 1 ? "" : "s");
380
381 i = r32sz;
382 if (i > 1)
383 heapsort(relbuf, r32sz, 4, intcmp);
384
385 oldaddr = 0;
386
387 for (--i; i >= 0; --i) {
388 dprintf(("0x%04x: ", relbuf[i]));
389 lptr = (uint32_t *)&buffer[relbuf[i]];
390 addrdiff = relbuf[i] - oldaddr;
391 dprintf(("(0x%04x, 0x%04x): ", *lptr, addrdiff));
392 if (addrdiff > 0xffff) {
393 errx(1, "addrdiff overflows: relbuf = 0x%08x, "
394 "oldaddr = 0x%08x, abort.\n", relbuf[i], oldaddr);
395 } else if (addrdiff > 0xff) {
396 *rpo = 0;
397 tmp16 = htobe16(addrdiff);
398 if (delta > 0) {
399 ++rpo;
400 memcpy(rpo, &tmp16, sizeof(tmp16));
401 rpo += sizeof(tmp16);
402 dprintf(("%02x%02x%02x\n",
403 rpo[-3], rpo[-2], rpo[-1]));
404 } else {
405 rpo -= sizeof(tmp16);
406 memcpy(rpo, &tmp16, sizeof(tmp16));
407 --rpo;
408 dprintf(("%02x%02x%02x\n",
409 rpo[0], rpo[1], rpo[2]));
410 }
411 } else {
412 *rpo = addrdiff;
413 dprintf(("%02x\n", *rpo));
414 rpo += delta;
415 }
416
417 oldaddr = relbuf[i];
418
419 if (delta < 0 ?
420 rpo <= buffer + tsz + dsz : rpo >= buffer + bbsize) {
421 printf("relocs don't fit, ");
422 if (Sflag) {
423 printf("retry.\n");
424 bbsize += 512;
425 sumsize++;
426 goto retry;
427 } else
428 errx(1, "abort.");
429 }
430 }
431 *rpo = 0; rpo += delta;
432 *rpo = 0; rpo += delta;
433 *rpo = 0; rpo += delta;
434
435 printf("using %td bytes, %td bytes remaining.\n",
436 delta > 0 ? rpo - buffer - tsz - dsz : buffer + bbsize - rpo,
437 delta > 0 ? buffer + bbsize - rpo : rpo - buffer - tsz - dsz);
438 /*
439 * RELOCs must fit into the bss area.
440 */
441 if (delta < 0 ?
442 rpo <= buffer + tsz + dsz : rpo >= buffer + bbsize) {
443 printf("relocs don't fit, ");
444 if (Sflag) {
445 printf("retry.\n");
446 bbsize += 512;
447 sumsize++;
448 goto retry;
449 } else
450 errx(1, "abort.");
451 }
452
453 if (undefsyms > 0)
454 errx(1, "Undefined symbols referenced");
455
456 ((uint32_t *)buffer)[1] = 0;
457 ((uint32_t *)buffer)[1] = htobe32((0xffffffff -
458 chksum((uint32_t *)buffer, sumsize * 512 / 4)));
459
460 ofd = open(argv[1], O_CREAT|O_WRONLY, 0644);
461 if (ofd < 0)
462 err(1, "Can't open %s", argv[1]);
463
464 if (write(ofd, buffer, bbsize) != bbsize)
465 err(1, "Writing output file");
466
467 exit(0);
468 }
469
470 static void
usage(void)471 usage(void)
472 {
473 fprintf(stderr, "Usage: %s [-F] bootprog bootprog.bin\n",
474 progname);
475 exit(1);
476 /* NOTREACHED */
477 }
478
479 static int
eval(Elf32_Sym * s,uint32_t * o)480 eval(Elf32_Sym *s, uint32_t *o)
481 {
482 int value;
483
484 value = be32toh(s->st_value);
485 if (be16toh(s->st_shndx) < 0xf000)
486 value += o[be16toh(s->st_shndx)];
487 else
488 printf("eval: %x\n", be16toh(s->st_shndx));
489 return value;
490 }
491