1 /* $NetBSD: elf2bb.c,v 1.16 2011/07/11 01:24:34 mrg 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/types.h> 37 38 #include <err.h> 39 #include <fcntl.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <sys/mman.h> /* of the machine we're running on */ 46 47 #ifndef HAVE_NBTOOL_CONFIG_H 48 #include <sys/endian.h> /* of the machine we're running on */ 49 #endif 50 51 #include <sys/exec_elf.h> /* TARGET */ 52 #ifndef R_68K_32 /* XXX host not m68k XXX */ 53 #define R_68K_32 1 54 #define R_68K_PC32 4 55 #define R_68K_PC16 5 56 #endif 57 58 #include "elf2bb.h" 59 #include "chksum.h" 60 61 void usage(void); 62 int intcmp(const void *, const void *); 63 int main(int argc, char *argv[]); 64 65 #ifdef DEBUG 66 #define dprintf(x) if (debug) printf x 67 #else 68 #define dprintf(x) 69 #endif 70 int debug; 71 72 #define BBSIZE 8192 73 74 char *progname; 75 int bbsize = BBSIZE; 76 u_int8_t *buffer; 77 u_int32_t *relbuf; 78 /* can't have more relocs than that*/ 79 80 int 81 intcmp(const void *i, const void *j) 82 { 83 int r; 84 85 r = (*(u_int32_t *)i) < (*(u_int32_t *)j); 86 87 return 2*r-1; 88 } 89 90 int 91 main(int argc, char *argv[]) 92 { 93 int ifd, ofd; 94 u_int mid, flags, magic; 95 void *image; 96 Elf32_Ehdr *eh; 97 Elf32_Shdr *sh; 98 char *shstrtab; 99 Elf32_Sym *symtab; 100 char *strtab; 101 int eval(Elf32_Sym *, u_int32_t *); 102 u_int32_t *lptr; 103 int i, l, delta; 104 u_int8_t *rpo; 105 u_int32_t oldaddr, addrdiff; 106 u_int32_t tsz, dsz, bsz, trsz, drsz, entry, relver; 107 u_int32_t pcrelsz, r32sz; 108 int sumsize = 16; 109 int c; 110 u_int32_t *sect_offset; 111 int undefsyms; 112 uint32_t tmp32; 113 uint16_t tmp16; 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 sumsize = 0; 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 == 0) 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", htobe16(eh->e_shnum), htobe32(eh->e_shoff))); 150 if (htobe16(eh->e_type) != ET_REL) 151 errx(1, "%s isn't a relocatable file, type=%d", 152 argv[0], htobe16(eh->e_type)); 153 if (htobe16(eh->e_machine) != EM_68K) 154 errx(1, "%s isn't M68K, machine=%d", argv[0], 155 htobe16(eh->e_machine)); 156 157 /* Calculate sizes from section headers. */ 158 tsz = dsz = bsz = trsz = pcrelsz = r32sz = 0; 159 sh = (Elf32_Shdr *)(image + htobe32(eh->e_shoff)); 160 shstrtab = (char *)(image + htobe32(sh[htobe16(eh->e_shstrndx)].sh_offset)); 161 symtab = NULL; /*XXX*/ 162 strtab = NULL; /*XXX*/ 163 dprintf((" name type flags addr offset size align\n")); 164 for (i = 0; i < htobe16(eh->e_shnum); ++i) { 165 u_int32_t sh_size; 166 167 dprintf( ("%2d: %08x %-16s %08x %08x %08x %08x %08x %08x\n", i, 168 htobe32(sh[i].sh_name), shstrtab + htobe32(sh[i].sh_name), 169 htobe32(sh[i].sh_type), 170 htobe32(sh[i].sh_flags), htobe32(sh[i].sh_addr), 171 htobe32(sh[i].sh_offset), htobe32(sh[i].sh_size), 172 htobe32(sh[i].sh_addralign))); 173 sh_size = (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & 174 -htobe32(sh[i].sh_addralign); 175 /* If section allocates memory, add to text, data, or bss size. */ 176 if (htobe32(sh[i].sh_flags) & SHF_ALLOC) { 177 if (htobe32(sh[i].sh_type) == SHT_PROGBITS) { 178 if (htobe32(sh[i].sh_flags) & SHF_WRITE) 179 dsz += sh_size; 180 else 181 tsz += sh_size; 182 } else 183 bsz += sh_size; 184 /* If it's relocations, add to relocation count */ 185 } else if (htobe32(sh[i].sh_type) == SHT_RELA) { 186 trsz += htobe32(sh[i].sh_size); 187 } 188 /* Check for SHT_REL? */ 189 /* Get symbol table location. */ 190 else if (htobe32(sh[i].sh_type) == SHT_SYMTAB) { 191 symtab = (Elf32_Sym *)(image + htobe32(sh[i].sh_offset)); 192 } else if (strcmp(".strtab", shstrtab + htobe32(sh[i].sh_name)) == 0) { 193 strtab = image + htobe32(sh[i].sh_offset); 194 } 195 } 196 dprintf(("tsz = 0x%x, dsz = 0x%x, bsz = 0x%x, total 0x%x\n", 197 tsz, dsz, bsz, tsz + dsz + bsz)); 198 199 if (trsz == 0) 200 errx(1, "%s has no relocation records.", argv[0]); 201 202 dprintf(("%d relocs\n", trsz/12)); 203 204 if (sumsize == 0) { 205 /* 206 * XXX overly cautious, but this guarantees that 16bit 207 * pc offsets and our relocs always work. 208 */ 209 bbsize = 32768; 210 if (bbsize < (tsz + dsz + bsz)) { 211 errx(1, "%s: too big (%d < (%d + %d + %d))", 212 argv[0], bbsize, tsz, dsz, bsz); 213 } 214 sumsize = bbsize / 512; 215 } 216 217 buffer = malloc(bbsize); 218 relbuf = (u_int32_t *)malloc(bbsize); 219 if (buffer == NULL || relbuf == NULL) 220 err(1, "Unable to allocate memory\n"); 221 222 /* 223 * We have one contiguous area allocated by the ROM to us. 224 */ 225 if (tsz+dsz+bsz > bbsize) 226 errx(1, "%s: resulting image too big %d+%d+%d=%d", argv[0], 227 tsz, dsz, bsz, tsz + dsz + bsz); 228 229 memset(buffer, 0, bbsize); 230 231 /* Allocate and load loadable sections */ 232 sect_offset = (u_int32_t *)malloc(htobe16(eh->e_shnum) * sizeof(u_int32_t)); 233 for (i = 0, l = 0; i < htobe16(eh->e_shnum); ++i) { 234 if (htobe32(sh[i].sh_flags) & SHF_ALLOC) { 235 dprintf(("vaddr 0x%04x size 0x%04x offset 0x%04x section %s\n", 236 l, htobe32(sh[i].sh_size), htobe32(sh[i].sh_offset), 237 shstrtab + htobe32(sh[i].sh_name))); 238 if (htobe32(sh[i].sh_type) == SHT_PROGBITS) 239 memcpy(buffer + l, image + htobe32(sh[i].sh_offset), 240 htobe32(sh[i].sh_size)); 241 sect_offset[i] = l; 242 l += (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & 243 -htobe32(sh[i].sh_addralign); 244 } 245 } 246 247 /* 248 * Hm. This tool REALLY should understand more than one 249 * relocator version. For now, check that the relocator at 250 * the image start does understand what we output. 251 */ 252 relver = htobe32(*(u_int32_t *)(buffer + 4)); 253 switch (relver) { 254 default: 255 errx(1, "%s: unrecognized relocator version %d", 256 argv[0], relver); 257 /*NOTREACHED*/ 258 259 case RELVER_RELATIVE_BYTES: 260 rpo = buffer + bbsize - 1; 261 delta = -1; 262 break; 263 264 case RELVER_RELATIVE_BYTES_FORWARD: 265 rpo = buffer + tsz + dsz; 266 delta = +1; 267 *(u_int16_t *)(buffer + 14) = htobe16(tsz + dsz); 268 break; 269 } 270 271 if (symtab == NULL) 272 errx(1, "No symbol table found"); 273 /* 274 * Link sections and generate relocation data 275 * Nasty: .text, .rodata, .data, .bss sections are not linked 276 * Symbol table values relative to start of sections. 277 * For each relocation entry: 278 * Symbol value needs to be calculated: value + section offset 279 * Image data adjusted to calculated value of symbol + addend 280 * Add relocation table entry for 32-bit relocatable values 281 * PC-relative entries will be absolute and don't need relocation 282 */ 283 undefsyms = 0; 284 for (i = 0; i < htobe16(eh->e_shnum); ++i) { 285 int n; 286 Elf32_Rela *ra; 287 u_int8_t *base; 288 289 if (htobe32(sh[i].sh_type) != SHT_RELA) 290 continue; 291 base = NULL; 292 if (strncmp(shstrtab + htobe32(sh[i].sh_name), ".rela", 5) != 0) 293 err(1, "bad relocation section name %s", shstrtab + 294 htobe32(sh[i].sh_name)); 295 for (n = 0; n < htobe16(eh->e_shnum); ++n) { 296 if (strcmp(shstrtab + htobe32(sh[i].sh_name) + 5, shstrtab + 297 htobe32(sh[n].sh_name)) != 0) 298 continue; 299 base = buffer + sect_offset[n]; 300 break; 301 } 302 if (base == NULL) 303 errx(1, "Can't find section for reloc %s", shstrtab + 304 htobe32(sh[i].sh_name)); 305 ra = (Elf32_Rela *)(image + htobe32(sh[i].sh_offset)); 306 for (n = 0; n < htobe32(sh[i].sh_size); n += sizeof(Elf32_Rela), ++ra) { 307 Elf32_Sym *s; 308 int value; 309 310 s = &symtab[ELF32_R_SYM(htobe32(ra->r_info))]; 311 if (s->st_shndx == ELF_SYM_UNDEFINED) { 312 fprintf(stderr, "Undefined symbol: %s\n", 313 strtab + s->st_name); 314 ++undefsyms; 315 } 316 value = htobe32(ra->r_addend) + eval(s, sect_offset); 317 dprintf(("reloc %04x info %04x (type %d sym %d) add 0x%x val %x\n", 318 htobe32(ra->r_offset), htobe32(ra->r_info), 319 ELF32_R_TYPE(htobe32(ra->r_info)), 320 ELF32_R_SYM(htobe32(ra->r_info)), 321 htobe32(ra->r_addend), value)); 322 switch (ELF32_R_TYPE(htobe32(ra->r_info))) { 323 case R_68K_32: 324 tmp32 = htobe32(value); 325 memcpy(base + htobe32(ra->r_offset), &tmp32, 326 sizeof(tmp32)); 327 relbuf[r32sz++] = (base - buffer) + htobe32(ra->r_offset); 328 break; 329 case R_68K_PC32: 330 ++pcrelsz; 331 tmp32 = htobe32(value - htobe32(ra->r_offset)); 332 memcpy(base + htobe32(ra->r_offset), &tmp32, 333 sizeof(tmp32)); 334 break; 335 case R_68K_PC16: 336 ++pcrelsz; 337 value -= htobe32(ra->r_offset); 338 if (value < -0x8000 || value > 0x7fff) 339 errx(1, "PC-relative offset out of range: %x\n", 340 value); 341 tmp16 = htobe16(value); 342 memcpy(base + htobe32(ra->r_offset), &tmp16, 343 sizeof(tmp16)); 344 break; 345 default: 346 errx(1, "Relocation type %d not supported", 347 ELF32_R_TYPE(htobe32(ra->r_info))); 348 } 349 } 350 } 351 dprintf(("%d PC-relative relocations, %d 32-bit relocations\n", 352 pcrelsz, r32sz)); 353 printf("%d absolute reloc%s found, ", r32sz, r32sz==1?"":"s"); 354 355 i = r32sz; 356 if (i > 1) 357 heapsort(relbuf, r32sz, 4, intcmp); 358 359 oldaddr = 0; 360 361 for (--i; i>=0; --i) { 362 dprintf(("0x%04x: ", relbuf[i])); 363 lptr = (u_int32_t *)&buffer[relbuf[i]]; 364 addrdiff = relbuf[i] - oldaddr; 365 dprintf(("(0x%04x, 0x%04x): ", *lptr, addrdiff)); 366 if (addrdiff > 255) { 367 *rpo = 0; 368 if (delta > 0) { 369 ++rpo; 370 *rpo++ = (relbuf[i] >> 8) & 0xff; 371 *rpo++ = relbuf[i] & 0xff; 372 dprintf(("%02x%02x%02x\n", 373 rpo[-3], rpo[-2], rpo[-1])); 374 } else { 375 *--rpo = relbuf[i] & 0xff; 376 *--rpo = (relbuf[i] >> 8) & 0xff; 377 --rpo; 378 dprintf(("%02x%02x%02x\n", 379 rpo[0], rpo[1], rpo[2])); 380 } 381 } else { 382 *rpo = addrdiff; 383 dprintf(("%02x\n", *rpo)); 384 rpo += delta; 385 } 386 387 oldaddr = relbuf[i]; 388 389 if (delta < 0 ? rpo <= buffer+tsz+dsz 390 : rpo >= buffer + bbsize) 391 errx(1, "Relocs don't fit."); 392 } 393 *rpo = 0; rpo += delta; 394 *rpo = 0; rpo += delta; 395 *rpo = 0; rpo += delta; 396 397 printf("using %d bytes, %d bytes remaining.\n", delta > 0 ? 398 rpo-buffer-tsz-dsz : buffer+bbsize-rpo, delta > 0 ? 399 buffer + bbsize - rpo : rpo - buffer - tsz - dsz); 400 /* 401 * RELOCs must fit into the bss area. 402 */ 403 if (delta < 0 ? rpo <= buffer+tsz+dsz 404 : rpo >= buffer + bbsize) 405 errx(1, "Relocs don't fit."); 406 407 if (undefsyms > 0) 408 errx(1, "Undefined symbols referenced"); 409 410 ((u_int32_t *)buffer)[1] = 0; 411 ((u_int32_t *)buffer)[1] = 412 htobe32((0xffffffff - chksum((u_int32_t *)buffer, sumsize * 512 / 4))); 413 414 ofd = open(argv[1], O_CREAT|O_WRONLY, 0644); 415 if (ofd < 0) 416 err(1, "Can't open %s", argv[1]); 417 418 if (write(ofd, buffer, bbsize) != bbsize) 419 err(1, "Writing output file"); 420 421 exit(0); 422 } 423 424 void 425 usage(void) 426 { 427 fprintf(stderr, "Usage: %s [-F] bootprog bootprog.bin\n", 428 progname); 429 exit(1); 430 /* NOTREACHED */ 431 } 432 433 int 434 eval(Elf32_Sym *s, u_int32_t *o) 435 { 436 int value; 437 438 value = htobe32(s->st_value); 439 if (htobe16(s->st_shndx) < 0xf000) 440 value += o[htobe16(s->st_shndx)]; 441 else 442 printf("eval: %x\n", htobe16(s->st_shndx)); 443 return value; 444 } 445