1 /* $NetBSD: elf2bb.c,v 1.8 2003/10/26 20:57:37 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", 151 argv[0], htobe16(eh->e_type)); 152 if (htobe16(eh->e_machine) != EM_68K) 153 errx(1, "%s isn't M68K, machine=%d", argv[0], 154 htobe16(eh->e_machine)); 155 156 /* Calculate sizes from section headers. */ 157 tsz = dsz = bsz = trsz = pcrelsz = r32sz = 0; 158 sh = (Elf32_Shdr *)(image + htobe32(eh->e_shoff)); 159 shstrtab = (char *)(image + htobe32(sh[htobe16(eh->e_shstrndx)].sh_offset)); 160 symtab = NULL; /*XXX*/ 161 strtab = NULL; /*XXX*/ 162 dprintf((" name type flags addr offset size align\n")); 163 for (i = 0; i < htobe16(eh->e_shnum); ++i) { 164 u_int32_t sh_size; 165 166 dprintf( ("%2d: %08x %-16s %08x %08x %08x %08x %08x %08x\n", i, 167 htobe32(sh[i].sh_name), shstrtab + htobe32(sh[i].sh_name), 168 htobe32(sh[i].sh_type), 169 htobe32(sh[i].sh_flags), htobe32(sh[i].sh_addr), 170 htobe32(sh[i].sh_offset), htobe32(sh[i].sh_size), 171 htobe32(sh[i].sh_addralign))); 172 sh_size = (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & 173 -htobe32(sh[i].sh_addralign); 174 /* If section allocates memory, add to text, data, or bss size. */ 175 if (htobe32(sh[i].sh_flags) & SHF_ALLOC) { 176 if (htobe32(sh[i].sh_type) == SHT_PROGBITS) { 177 if (htobe32(sh[i].sh_flags) & SHF_WRITE) 178 dsz += sh_size; 179 else 180 tsz += sh_size; 181 } else 182 bsz += sh_size; 183 /* If it's relocations, add to relocation count */ 184 } else if (htobe32(sh[i].sh_type) == SHT_RELA) { 185 trsz += htobe32(sh[i].sh_size); 186 } 187 /* Check for SHT_REL? */ 188 /* Get symbol table location. */ 189 else if (htobe32(sh[i].sh_type) == SHT_SYMTAB) { 190 symtab = (Elf32_Sym *)(image + htobe32(sh[i].sh_offset)); 191 } else if (strcmp(".strtab", shstrtab + htobe32(sh[i].sh_name)) == 0) { 192 strtab = image + htobe32(sh[i].sh_offset); 193 } 194 } 195 dprintf(("tsz = 0x%x, dsz = 0x%x, bsz = 0x%x, total 0x%x\n", 196 tsz, dsz, bsz, tsz + dsz + bsz)); 197 198 if (trsz == 0) 199 errx(1, "%s has no relocation records.", argv[0]); 200 201 dprintf(("%d relocs\n", trsz/12)); 202 203 if (sumsize == 0) { 204 bbsize = (tsz + dsz + bsz + 511) & ~511; 205 sumsize = bbsize / 512; 206 } 207 208 buffer = malloc(bbsize); 209 relbuf = (u_int32_t *)malloc(bbsize); 210 if (buffer == NULL || relbuf == NULL) 211 err(1, "Unable to allocate memory\n"); 212 213 /* 214 * We have one contiguous area allocated by the ROM to us. 215 */ 216 if (tsz+dsz+bsz > bbsize) 217 errx(1, "%s: resulting image too big %d+%d+%d=%d", argv[0], 218 tsz, dsz, bsz, tsz + dsz + bsz); 219 220 memset(buffer, 0, bbsize); 221 222 /* Allocate and load loadable sections */ 223 sect_offset = (u_int32_t *)malloc(htobe16(eh->e_shnum) * sizeof(u_int32_t)); 224 for (i = 0, l = 0; i < htobe16(eh->e_shnum); ++i) { 225 if (htobe32(sh[i].sh_flags) & SHF_ALLOC) { 226 dprintf(("vaddr 0x%04x size 0x%04x offset 0x%04x section %s\n", 227 l, htobe32(sh[i].sh_size), htobe32(sh[i].sh_offset), 228 shstrtab + htobe32(sh[i].sh_name))); 229 if (htobe32(sh[i].sh_type) == SHT_PROGBITS) 230 memcpy(buffer + l, image + htobe32(sh[i].sh_offset), 231 htobe32(sh[i].sh_size)); 232 sect_offset[i] = l; 233 l += (htobe32(sh[i].sh_size) + htobe32(sh[i].sh_addralign) - 1) & 234 -htobe32(sh[i].sh_addralign); 235 } 236 } 237 238 /* 239 * Hm. This tool REALLY should understand more than one 240 * relocator version. For now, check that the relocator at 241 * the image start does understand what we output. 242 */ 243 relver = htobe32(*(u_int32_t *)(buffer + 4)); 244 switch (relver) { 245 default: 246 errx(1, "%s: unrecognized relocator version %d", 247 argv[0], relver); 248 /*NOTREACHED*/ 249 250 case RELVER_RELATIVE_BYTES: 251 rpo = buffer + bbsize - 1; 252 delta = -1; 253 break; 254 255 case RELVER_RELATIVE_BYTES_FORWARD: 256 rpo = buffer + tsz + dsz; 257 delta = +1; 258 *(u_int16_t *)(buffer + 14) = htobe16(tsz + dsz); 259 break; 260 } 261 262 if (symtab == NULL) 263 errx(1, "No symbol table found"); 264 /* 265 * Link sections and generate relocation data 266 * Nasty: .text, .rodata, .data, .bss sections are not linked 267 * Symbol table values relative to start of sections. 268 * For each relocation entry: 269 * Symbol value needs to be calculated: value + section offset 270 * Image data adjusted to calculated value of symbol + addend 271 * Add relocation table entry for 32-bit relocatable values 272 * PC-relative entries will be absolute and don't need relocation 273 */ 274 undefsyms = 0; 275 for (i = 0; i < htobe16(eh->e_shnum); ++i) { 276 int n; 277 Elf32_Rela *ra; 278 u_int8_t *base; 279 280 if (htobe32(sh[i].sh_type) != SHT_RELA) 281 continue; 282 base = NULL; 283 if (strncmp(shstrtab + htobe32(sh[i].sh_name), ".rela", 5) != 0) 284 err(1, "bad relocation section name %s", shstrtab + 285 htobe32(sh[i].sh_name)); 286 for (n = 0; n < htobe16(eh->e_shnum); ++n) { 287 if (strcmp(shstrtab + htobe32(sh[i].sh_name) + 5, shstrtab + 288 htobe32(sh[n].sh_name)) != 0) 289 continue; 290 base = buffer + sect_offset[n]; 291 break; 292 } 293 if (base == NULL) 294 errx(1, "Can't find section for reloc %s", shstrtab + 295 htobe32(sh[i].sh_name)); 296 ra = (Elf32_Rela *)(image + htobe32(sh[i].sh_offset)); 297 for (n = 0; n < htobe32(sh[i].sh_size); n += sizeof(Elf32_Rela), ++ra) { 298 Elf32_Sym *s; 299 int value; 300 301 s = &symtab[ELF32_R_SYM(htobe32(ra->r_info))]; 302 if (s->st_shndx == ELF_SYM_UNDEFINED) { 303 fprintf(stderr, "Undefined symbol: %s\n", 304 strtab + s->st_name); 305 ++undefsyms; 306 } 307 value = htobe32(ra->r_addend) + eval(s, sect_offset); 308 dprintf(("reloc %04x info %04x (type %d sym %d) add 0x%x val %x\n", 309 htobe32(ra->r_offset), htobe32(ra->r_info), 310 ELF32_R_TYPE(htobe32(ra->r_info)), 311 ELF32_R_SYM(htobe32(ra->r_info)), 312 htobe32(ra->r_addend), value)); 313 switch (ELF32_R_TYPE(htobe32(ra->r_info))) { 314 case R_68K_32: 315 *((u_int32_t *)(base + htobe32(ra->r_offset))) = 316 htobe32(value); 317 relbuf[r32sz++] = (base - buffer) + htobe32(ra->r_offset); 318 break; 319 case R_68K_PC32: 320 ++pcrelsz; 321 *((int32_t *)(base + htobe32(ra->r_offset))) = 322 htobe32(value - htobe32(ra->r_offset)); 323 break; 324 case R_68K_PC16: 325 ++pcrelsz; 326 value -= htobe32(ra->r_offset); 327 if (value < -0x8000 || value > 0x7fff) 328 errx(1, "PC-relative offset out of range: %x\n", 329 value); 330 *((int16_t *)(base + htobe32(ra->r_offset))) = 331 htobe16(value); 332 break; 333 default: 334 errx(1, "Relocation type %d not supported", 335 ELF32_R_TYPE(htobe32(ra->r_info))); 336 } 337 } 338 } 339 dprintf(("%d PC-relative relocations, %d 32-bit relocations\n", 340 pcrelsz, r32sz)); 341 printf("%d absolute reloc%s found, ", r32sz, r32sz==1?"":"s"); 342 343 i = r32sz; 344 if (i > 1) 345 heapsort(relbuf, r32sz, 4, intcmp); 346 347 oldaddr = 0; 348 349 for (--i; i>=0; --i) { 350 dprintf(("0x%04x: ", relbuf[i])); 351 lptr = (u_int32_t *)&buffer[relbuf[i]]; 352 addrdiff = relbuf[i] - oldaddr; 353 dprintf(("(0x%04x, 0x%04x): ", *lptr, addrdiff)); 354 if (addrdiff > 255) { 355 *rpo = 0; 356 if (delta > 0) { 357 ++rpo; 358 *rpo++ = (relbuf[i] >> 8) & 0xff; 359 *rpo++ = relbuf[i] & 0xff; 360 dprintf(("%02x%02x%02x\n", 361 rpo[-3], rpo[-2], rpo[-1])); 362 } else { 363 *--rpo = relbuf[i] & 0xff; 364 *--rpo = (relbuf[i] >> 8) & 0xff; 365 --rpo; 366 dprintf(("%02x%02x%02x\n", 367 rpo[0], rpo[1], rpo[2])); 368 } 369 } else { 370 *rpo = addrdiff; 371 dprintf(("%02x\n", *rpo)); 372 rpo += delta; 373 } 374 375 oldaddr = relbuf[i]; 376 377 if (delta < 0 ? rpo <= buffer+tsz+dsz 378 : rpo >= buffer + bbsize) 379 errx(1, "Relocs don't fit."); 380 } 381 *rpo = 0; rpo += delta; 382 *rpo = 0; rpo += delta; 383 *rpo = 0; rpo += delta; 384 385 printf("using %d bytes, %d bytes remaining.\n", delta > 0 ? 386 rpo-buffer-tsz-dsz : buffer+bbsize-rpo, delta > 0 ? 387 buffer + bbsize - rpo : rpo - buffer - tsz - dsz); 388 /* 389 * RELOCs must fit into the bss area. 390 */ 391 if (delta < 0 ? rpo <= buffer+tsz+dsz 392 : rpo >= buffer + bbsize) 393 errx(1, "Relocs don't fit."); 394 395 if (undefsyms > 0) 396 errx(1, "Undefined symbols referenced"); 397 398 ((u_int32_t *)buffer)[1] = 0; 399 ((u_int32_t *)buffer)[1] = 400 htobe32((0xffffffff - chksum((u_int32_t *)buffer, sumsize * 512 / 4))); 401 402 ofd = open(argv[1], O_CREAT|O_WRONLY, 0644); 403 if (ofd < 0) 404 err(1, "Can't open %s", argv[1]); 405 406 if (write(ofd, buffer, bbsize) != bbsize) 407 err(1, "Writing output file"); 408 409 exit(0); 410 } 411 412 void 413 usage(void) 414 { 415 fprintf(stderr, "Usage: %s [-F] bootprog bootprog.bin\n", 416 progname); 417 exit(1); 418 /* NOTREACHED */ 419 } 420 421 int 422 eval(Elf32_Sym *s, u_int32_t *o) 423 { 424 int value; 425 426 value = htobe32(s->st_value); 427 if (htobe16(s->st_shndx) < 0xf000) 428 value += o[htobe16(s->st_shndx)]; 429 else 430 printf("eval: %x\n", htobe16(s->st_shndx)); 431 return value; 432 } 433