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 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 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 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 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