1 /* $NetBSD: elf2bb.c,v 1.15 2008/04/28 20:23:13 martin 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 err(1, "%s: too big.", argv[0]); 212 } 213 sumsize = bbsize / 512; 214 } 215 216 buffer = malloc(bbsize); 217 relbuf = (u_int32_t *)malloc(bbsize); 218 if (buffer == NULL || relbuf == NULL) 219 err(1, "Unable to allocate memory\n"); 220 221 /* 222 * We have one contiguous area allocated by the ROM to us. 223 */ 224 if (tsz+dsz+bsz > bbsize) 225 errx(1, "%s: resulting image too big %d+%d+%d=%d", argv[0], 226 tsz, dsz, bsz, tsz + dsz + bsz); 227 228 memset(buffer, 0, bbsize); 229 230 /* Allocate and load loadable sections */ 231 sect_offset = (u_int32_t *)malloc(htobe16(eh->e_shnum) * sizeof(u_int32_t)); 232 for (i = 0, l = 0; i < htobe16(eh->e_shnum); ++i) { 233 if (htobe32(sh[i].sh_flags) & SHF_ALLOC) { 234 dprintf(("vaddr 0x%04x size 0x%04x offset 0x%04x section %s\n", 235 l, htobe32(sh[i].sh_size), htobe32(sh[i].sh_offset), 236 shstrtab + htobe32(sh[i].sh_name))); 237 if (htobe32(sh[i].sh_type) == SHT_PROGBITS) 238 memcpy(buffer + l, image + htobe32(sh[i].sh_offset), 239 htobe32(sh[i].sh_size)); 240 sect_offset[i] = l; 241 l += (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & 242 -htobe32(sh[i].sh_addralign); 243 } 244 } 245 246 /* 247 * Hm. This tool REALLY should understand more than one 248 * relocator version. For now, check that the relocator at 249 * the image start does understand what we output. 250 */ 251 relver = htobe32(*(u_int32_t *)(buffer + 4)); 252 switch (relver) { 253 default: 254 errx(1, "%s: unrecognized relocator version %d", 255 argv[0], relver); 256 /*NOTREACHED*/ 257 258 case RELVER_RELATIVE_BYTES: 259 rpo = buffer + bbsize - 1; 260 delta = -1; 261 break; 262 263 case RELVER_RELATIVE_BYTES_FORWARD: 264 rpo = buffer + tsz + dsz; 265 delta = +1; 266 *(u_int16_t *)(buffer + 14) = htobe16(tsz + dsz); 267 break; 268 } 269 270 if (symtab == NULL) 271 errx(1, "No symbol table found"); 272 /* 273 * Link sections and generate relocation data 274 * Nasty: .text, .rodata, .data, .bss sections are not linked 275 * Symbol table values relative to start of sections. 276 * For each relocation entry: 277 * Symbol value needs to be calculated: value + section offset 278 * Image data adjusted to calculated value of symbol + addend 279 * Add relocation table entry for 32-bit relocatable values 280 * PC-relative entries will be absolute and don't need relocation 281 */ 282 undefsyms = 0; 283 for (i = 0; i < htobe16(eh->e_shnum); ++i) { 284 int n; 285 Elf32_Rela *ra; 286 u_int8_t *base; 287 288 if (htobe32(sh[i].sh_type) != SHT_RELA) 289 continue; 290 base = NULL; 291 if (strncmp(shstrtab + htobe32(sh[i].sh_name), ".rela", 5) != 0) 292 err(1, "bad relocation section name %s", shstrtab + 293 htobe32(sh[i].sh_name)); 294 for (n = 0; n < htobe16(eh->e_shnum); ++n) { 295 if (strcmp(shstrtab + htobe32(sh[i].sh_name) + 5, shstrtab + 296 htobe32(sh[n].sh_name)) != 0) 297 continue; 298 base = buffer + sect_offset[n]; 299 break; 300 } 301 if (base == NULL) 302 errx(1, "Can't find section for reloc %s", shstrtab + 303 htobe32(sh[i].sh_name)); 304 ra = (Elf32_Rela *)(image + htobe32(sh[i].sh_offset)); 305 for (n = 0; n < htobe32(sh[i].sh_size); n += sizeof(Elf32_Rela), ++ra) { 306 Elf32_Sym *s; 307 int value; 308 309 s = &symtab[ELF32_R_SYM(htobe32(ra->r_info))]; 310 if (s->st_shndx == ELF_SYM_UNDEFINED) { 311 fprintf(stderr, "Undefined symbol: %s\n", 312 strtab + s->st_name); 313 ++undefsyms; 314 } 315 value = htobe32(ra->r_addend) + eval(s, sect_offset); 316 dprintf(("reloc %04x info %04x (type %d sym %d) add 0x%x val %x\n", 317 htobe32(ra->r_offset), htobe32(ra->r_info), 318 ELF32_R_TYPE(htobe32(ra->r_info)), 319 ELF32_R_SYM(htobe32(ra->r_info)), 320 htobe32(ra->r_addend), value)); 321 switch (ELF32_R_TYPE(htobe32(ra->r_info))) { 322 case R_68K_32: 323 tmp32 = htobe32(value); 324 memcpy(base + htobe32(ra->r_offset), &tmp32, 325 sizeof(tmp32)); 326 relbuf[r32sz++] = (base - buffer) + htobe32(ra->r_offset); 327 break; 328 case R_68K_PC32: 329 ++pcrelsz; 330 tmp32 = htobe32(value - htobe32(ra->r_offset)); 331 memcpy(base + htobe32(ra->r_offset), &tmp32, 332 sizeof(tmp32)); 333 break; 334 case R_68K_PC16: 335 ++pcrelsz; 336 value -= htobe32(ra->r_offset); 337 if (value < -0x8000 || value > 0x7fff) 338 errx(1, "PC-relative offset out of range: %x\n", 339 value); 340 tmp16 = htobe16(value); 341 memcpy(base + htobe32(ra->r_offset), &tmp16, 342 sizeof(tmp16)); 343 break; 344 default: 345 errx(1, "Relocation type %d not supported", 346 ELF32_R_TYPE(htobe32(ra->r_info))); 347 } 348 } 349 } 350 dprintf(("%d PC-relative relocations, %d 32-bit relocations\n", 351 pcrelsz, r32sz)); 352 printf("%d absolute reloc%s found, ", r32sz, r32sz==1?"":"s"); 353 354 i = r32sz; 355 if (i > 1) 356 heapsort(relbuf, r32sz, 4, intcmp); 357 358 oldaddr = 0; 359 360 for (--i; i>=0; --i) { 361 dprintf(("0x%04x: ", relbuf[i])); 362 lptr = (u_int32_t *)&buffer[relbuf[i]]; 363 addrdiff = relbuf[i] - oldaddr; 364 dprintf(("(0x%04x, 0x%04x): ", *lptr, addrdiff)); 365 if (addrdiff > 255) { 366 *rpo = 0; 367 if (delta > 0) { 368 ++rpo; 369 *rpo++ = (relbuf[i] >> 8) & 0xff; 370 *rpo++ = relbuf[i] & 0xff; 371 dprintf(("%02x%02x%02x\n", 372 rpo[-3], rpo[-2], rpo[-1])); 373 } else { 374 *--rpo = relbuf[i] & 0xff; 375 *--rpo = (relbuf[i] >> 8) & 0xff; 376 --rpo; 377 dprintf(("%02x%02x%02x\n", 378 rpo[0], rpo[1], rpo[2])); 379 } 380 } else { 381 *rpo = addrdiff; 382 dprintf(("%02x\n", *rpo)); 383 rpo += delta; 384 } 385 386 oldaddr = relbuf[i]; 387 388 if (delta < 0 ? rpo <= buffer+tsz+dsz 389 : rpo >= buffer + bbsize) 390 errx(1, "Relocs don't fit."); 391 } 392 *rpo = 0; rpo += delta; 393 *rpo = 0; rpo += delta; 394 *rpo = 0; rpo += delta; 395 396 printf("using %d bytes, %d bytes remaining.\n", delta > 0 ? 397 rpo-buffer-tsz-dsz : buffer+bbsize-rpo, delta > 0 ? 398 buffer + bbsize - rpo : rpo - buffer - tsz - dsz); 399 /* 400 * RELOCs must fit into the bss area. 401 */ 402 if (delta < 0 ? rpo <= buffer+tsz+dsz 403 : rpo >= buffer + bbsize) 404 errx(1, "Relocs don't fit."); 405 406 if (undefsyms > 0) 407 errx(1, "Undefined symbols referenced"); 408 409 ((u_int32_t *)buffer)[1] = 0; 410 ((u_int32_t *)buffer)[1] = 411 htobe32((0xffffffff - chksum((u_int32_t *)buffer, sumsize * 512 / 4))); 412 413 ofd = open(argv[1], O_CREAT|O_WRONLY, 0644); 414 if (ofd < 0) 415 err(1, "Can't open %s", argv[1]); 416 417 if (write(ofd, buffer, bbsize) != bbsize) 418 err(1, "Writing output file"); 419 420 exit(0); 421 } 422 423 void 424 usage(void) 425 { 426 fprintf(stderr, "Usage: %s [-F] bootprog bootprog.bin\n", 427 progname); 428 exit(1); 429 /* NOTREACHED */ 430 } 431 432 int 433 eval(Elf32_Sym *s, u_int32_t *o) 434 { 435 int value; 436 437 value = htobe32(s->st_value); 438 if (htobe16(s->st_shndx) < 0xf000) 439 value += o[htobe16(s->st_shndx)]; 440 else 441 printf("eval: %x\n", htobe16(s->st_shndx)); 442 return value; 443 } 444