1 /* $NetBSD: elf2bb.c,v 1.3 2002/03/26 05:18:19 mhitch Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/types.h> 40 41 #include <err.h> 42 #include <fcntl.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include <sys/mman.h> /* of the machine we're running on */ 49 #include <machine/endian.h> /* of the machine we're running on */ 50 51 #include <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 caddr_t 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 113 114 progname = argv[0]; 115 116 /* insert getopt here, if needed */ 117 while ((c = getopt(argc, argv, "dFS")) != -1) 118 switch(c) { 119 case 'F': 120 sumsize = 2; 121 break; 122 case 'S': 123 /* Dynamically size second-stage boot */ 124 sumsize = 0; 125 break; 126 case 'd': 127 debug = 1; 128 break; 129 default: 130 usage(); 131 } 132 argv += optind; 133 argc -= optind; 134 135 if (argc < 2) 136 usage(); 137 138 ifd = open(argv[0], O_RDONLY, 0); 139 if (ifd < 0) 140 err(1, "Can't open %s", argv[0]); 141 142 image = mmap(0, 65536, PROT_READ, MAP_FILE|MAP_PRIVATE, ifd, 0); 143 if (image == 0) 144 err(1, "Can't mmap %s", argv[1]); 145 146 eh = (Elf32_Ehdr *)image; /* XXX endianness */ 147 148 dprintf(("%04x sections, offset %08x\n", htobe16(eh->e_shnum), htobe32(eh->e_shoff))); 149 if (htobe16(eh->e_type) != ET_REL) 150 errx(1, "%s isn't a relocatable file, type=%d\n", 151 argv[0], htobe16(eh->e_type)); 152 if (htobe16(eh->e_machine) != EM_68K) 153 errx(1, "%s isn't M68K, machine=%d\n", argv[0], 154 htobe16(eh->e_machine)); 155 156 tsz = dsz = bsz = trsz = pcrelsz = r32sz = 0; 157 sh = (Elf32_Shdr *)(image + htobe32(eh->e_shoff)); 158 shstrtab = (char *)(image + htobe32(sh[htobe16(eh->e_shstrndx)].sh_offset)); 159 symtab = NULL; /*XXX*/ 160 strtab = NULL; /*XXX*/ 161 dprintf((" name type flags addr offset size align\n")); 162 for (i = 0; i < htobe16(eh->e_shnum); ++i) { 163 u_int32_t sh_size; 164 165 dprintf( ("%2d: %08x %-16s %08x %08x %08x %08x %08x %08x\n", i, 166 htobe32(sh[i].sh_name), shstrtab + htobe32(sh[i].sh_name), 167 htobe32(sh[i].sh_type), 168 htobe32(sh[i].sh_flags), htobe32(sh[i].sh_addr), 169 htobe32(sh[i].sh_offset), htobe32(sh[i].sh_size), 170 htobe32(sh[i].sh_addralign))); 171 sh_size = (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & 172 -htobe32(sh[i].sh_addralign); 173 if (htobe32(sh[i].sh_type) == SHT_PROGBITS) { 174 if (htobe32(sh[i].sh_flags) & SHF_WRITE) 175 dsz += sh_size; 176 else 177 tsz += sh_size; 178 } else if (htobe32(sh[i].sh_type) == SHT_NOBITS && 179 htobe32(sh[i].sh_flags) == (SHF_ALLOC | SHF_WRITE)) { 180 bsz += sh_size;; 181 } else if (htobe32(sh[i].sh_type) == SHT_RELA) { 182 trsz += htobe32(sh[i].sh_size); 183 } 184 /* Check for SHT_REL? */ 185 else if (htobe32(sh[i].sh_type) == SHT_SYMTAB) { 186 symtab = (Elf32_Sym *)(image + htobe32(sh[i].sh_offset)); 187 } else if (strcmp(".strtab", shstrtab + htobe32(sh[i].sh_name)) == 0) { 188 strtab = image + htobe32(sh[i].sh_offset); 189 } 190 } 191 dprintf(("tsz = 0x%x, dsz = 0x%x, bsz = 0x%x, total 0x%x\n", 192 tsz, dsz, bsz, tsz + dsz + bsz)); 193 194 if (trsz == 0) 195 errx(1, "%s has no relocation records.\n", argv[0]); 196 197 dprintf(("%d relocs\n", trsz/12)); 198 199 if (sumsize == 0) { 200 bbsize = (tsz + dsz + bsz + 511) & ~511; 201 sumsize = bbsize / 512; 202 } 203 204 buffer = malloc(bbsize); 205 relbuf = (u_int32_t *)malloc(bbsize); 206 if (buffer == NULL || relbuf == NULL) 207 err(1, "Unable to allocate memory\n"); 208 209 /* 210 * We have one contiguous area allocated by the ROM to us. 211 */ 212 if (tsz+dsz+bsz > bbsize) 213 errx(1, "%s: resulting image too big\n", argv[0]); 214 215 memset(buffer, bbsize, 0); 216 217 /* Allocate and load loadable sections */ 218 sect_offset = (u_int32_t *)malloc(htobe16(eh->e_shnum) * sizeof(u_int32_t)); 219 for (i = 0, l = 0; i < htobe16(eh->e_shnum); ++i) { 220 if (htobe32(sh[i].sh_type) == SHT_PROGBITS || 221 htobe32(sh[i].sh_type) == SHT_NOBITS) { 222 dprintf(("vaddr 0x%04x size 0x%04x offset 0x%04x section %s\n", 223 l, htobe32(sh[i].sh_size), htobe32(sh[i].sh_offset), 224 shstrtab + htobe32(sh[i].sh_name))); 225 if (htobe32(sh[i].sh_type) == SHT_PROGBITS) 226 memcpy(buffer + l, image + htobe32(sh[i].sh_offset), 227 htobe32(sh[i].sh_size)); 228 sect_offset[i] = l; 229 l += (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & 230 -htobe32(sh[i].sh_addralign); 231 } 232 } 233 234 /* 235 * Hm. This tool REALLY should understand more than one 236 * relocator version. For now, check that the relocator at 237 * the image start does understand what we output. 238 */ 239 relver = htobe32(*(u_int32_t *)(buffer + 4)); 240 switch (relver) { 241 default: 242 errx(1, "%s: unrecognized relocator version %d\n", 243 argv[0], relver); 244 /*NOTREACHED*/ 245 246 case RELVER_RELATIVE_BYTES: 247 rpo = buffer + bbsize - 1; 248 delta = -1; 249 break; 250 251 case RELVER_RELATIVE_BYTES_FORWARD: 252 rpo = buffer + tsz + dsz; 253 delta = +1; 254 *(u_int16_t *)(buffer + 14) = htobe16(tsz + dsz); 255 break; 256 } 257 258 if (symtab == NULL) 259 errx(1, "No symbol table found\n"); 260 /* 261 * Link sections and generate relocation data 262 * Nasty: .text, .rodata, .data, .bss sections are not linked 263 * Symbol table values relative to start of sections. 264 * For each relocation entry: 265 * Symbol value needs to be calculated: value + section offset 266 * Image data adjusted to calculated value of symbol + addend 267 * Add relocation table entry for 32-bit relocatable values 268 * PC-relative entries will be absolute and don't need relocation 269 */ 270 undefsyms = 0; 271 for (i = 0; i < htobe16(eh->e_shnum); ++i) { 272 int n; 273 Elf32_Rela *ra; 274 u_int8_t *base; 275 276 if (htobe32(sh[i].sh_type) != SHT_RELA) 277 continue; 278 base = NULL; 279 if (strncmp(shstrtab + htobe32(sh[i].sh_name), ".rela", 5) != 0) 280 err(1, "bad relocation section name %s", shstrtab + 281 htobe32(sh[i].sh_name)); 282 for (n = 0; n < htobe16(eh->e_shnum); ++n) { 283 if (strcmp(shstrtab + htobe32(sh[i].sh_name) + 5, shstrtab + 284 htobe32(sh[n].sh_name)) != 0) 285 continue; 286 base = buffer + sect_offset[n]; 287 break; 288 } 289 if (base == NULL) 290 errx(1, "Can't find section for reloc %s\n", shstrtab + 291 htobe32(sh[i].sh_name)); 292 ra = (Elf32_Rela *)(image + htobe32(sh[i].sh_offset)); 293 for (n = 0; n < htobe32(sh[i].sh_size); n += sizeof(Elf32_Rela), ++ra) { 294 Elf32_Sym *s; 295 int value; 296 297 s = &symtab[ELF32_R_SYM(htobe32(ra->r_info))]; 298 if (s->st_shndx == ELF_SYM_UNDEFINED) { 299 fprintf(stderr, "Undefined symbol: %s\n", 300 strtab + s->st_name); 301 ++undefsyms; 302 } 303 value = htobe32(ra->r_addend) + eval(s, sect_offset); 304 dprintf(("reloc %04x info %04x (type %d sym %d) add 0x%x val %x\n", 305 htobe32(ra->r_offset), htobe32(ra->r_info), 306 ELF32_R_TYPE(htobe32(ra->r_info)), 307 ELF32_R_SYM(htobe32(ra->r_info)), 308 htobe32(ra->r_addend), value)); 309 switch (ELF32_R_TYPE(htobe32(ra->r_info))) { 310 case R_68K_32: 311 *((u_int32_t *)(base + htobe32(ra->r_offset))) = 312 htobe32(value); 313 relbuf[r32sz++] = (base - buffer) + htobe32(ra->r_offset); 314 break; 315 case R_68K_PC32: 316 ++pcrelsz; 317 *((int32_t *)(base + htobe32(ra->r_offset))) = 318 htobe32(value - htobe32(ra->r_offset)); 319 break; 320 case R_68K_PC16: 321 ++pcrelsz; 322 *((int16_t *)(base + htobe32(ra->r_offset))) = 323 htobe16(value - htobe32(ra->r_offset)); 324 break; 325 default: 326 errx(1, "Relocation type %d not supported", 327 ELF32_R_TYPE(htobe32(ra->r_info))); 328 } 329 } 330 } 331 dprintf(("%d PC-relative relocations, %d 32-bit relocations\n", 332 pcrelsz, r32sz)); 333 printf("%d absolute reloc%s found, ", r32sz, r32sz==1?"":"s"); 334 335 i = r32sz; 336 if (i > 1) 337 heapsort(relbuf, r32sz, 4, intcmp); 338 339 oldaddr = 0; 340 341 for (--i; i>=0; --i) { 342 dprintf(("0x%04x: ", relbuf[i])); 343 lptr = (u_int32_t *)&buffer[relbuf[i]]; 344 addrdiff = relbuf[i] - oldaddr; 345 dprintf(("(0x%04x, 0x%04x): ", *lptr, addrdiff)); 346 if (addrdiff > 255) { 347 *rpo = 0; 348 if (delta > 0) { 349 ++rpo; 350 *rpo++ = (relbuf[i] >> 8) & 0xff; 351 *rpo++ = relbuf[i] & 0xff; 352 dprintf(("%02x%02x%02x\n", 353 rpo[-3], rpo[-2], rpo[-1])); 354 } else { 355 *--rpo = relbuf[i] & 0xff; 356 *--rpo = (relbuf[i] >> 8) & 0xff; 357 --rpo; 358 dprintf(("%02x%02x%02x\n", 359 rpo[0], rpo[1], rpo[2])); 360 } 361 } else { 362 *rpo = addrdiff; 363 dprintf(("%02x\n", *rpo)); 364 rpo += delta; 365 } 366 367 oldaddr = relbuf[i]; 368 369 if (delta < 0 ? rpo <= buffer+tsz+dsz 370 : rpo >= buffer + bbsize) 371 errx(1, "Relocs don't fit."); 372 } 373 *rpo = 0; rpo += delta; 374 *rpo = 0; rpo += delta; 375 *rpo = 0; rpo += delta; 376 377 printf("using %d bytes, %d bytes remaining.\n", delta > 0 ? 378 rpo-buffer-tsz-dsz : buffer+bbsize-rpo, delta > 0 ? 379 buffer + bbsize - rpo : rpo - buffer - tsz - dsz); 380 /* 381 * RELOCs must fit into the bss area. 382 */ 383 if (delta < 0 ? rpo <= buffer+tsz+dsz 384 : rpo >= buffer + bbsize) 385 errx(1, "Relocs don't fit."); 386 387 if (undefsyms > 0) 388 errx(1, "Undefined symbols referenced"); 389 390 ((u_int32_t *)buffer)[1] = 0; 391 ((u_int32_t *)buffer)[1] = 392 htobe32((0xffffffff - chksum((u_int32_t *)buffer, sumsize * 512 / 4))); 393 394 ofd = open(argv[1], O_CREAT|O_WRONLY, 0644); 395 if (ofd < 0) 396 err(1, "Can't open %s", argv[1]); 397 398 if (write(ofd, buffer, bbsize) != bbsize) 399 err(1, "Writing output file"); 400 401 exit(0); 402 } 403 404 void 405 usage(void) 406 { 407 fprintf(stderr, "Usage: %s [-F] bootprog bootprog.bin\n", 408 progname); 409 exit(1); 410 /* NOTREACHED */ 411 } 412 413 int 414 eval(Elf32_Sym *s, u_int32_t *o) 415 { 416 int value; 417 418 value = htobe32(s->st_value); 419 if (htobe16(s->st_shndx) < 0xf000) 420 value += o[htobe16(s->st_shndx)]; 421 else 422 printf("eval: %x\n", htobe16(s->st_shndx)); 423 return value; 424 } 425