1 /* 2 * aout2hux - convert a.out/ELF executable to Human68k .x format 3 * 4 * Read two a.out/ELF format executables with different load addresses 5 * and generate Human68k .x format executable. 6 * 7 * written by Yasha (ITOH Yasufumi) 8 * public domain 9 * 10 * usage: 11 * aout2hux [ -o output.x ] a.out1 loadaddr1 a.out2 loadaddr2 12 * 13 * The input files must be static OMAGIC/NMAGIC m68k a.out executables 14 * or m68k ELF executables. 15 * Two executables must have different loading addresses. 16 * Each of the load address must be a hexadecimal number. 17 * Load address shall be multiple of 4 for as / ld of NetBSD/m68k. 18 * 19 * example: 20 * % cc -N -static -Wl,-Ttext,0 -o aout1 *.o 21 * % cc -N -static -Wl,-Ttext,10203040 -o aout2 *.o 22 * % aout2hux -o foo.x aout1 0 aout2 10203040 23 * 24 * $NetBSD: aout2hux.c,v 1.5 1999/11/19 03:54:08 itohy Exp $ 25 */ 26 27 #include <sys/types.h> 28 #ifndef NO_UNISTD 29 # include <unistd.h> 30 #endif 31 #ifndef NO_STDLIB 32 # include <stdlib.h> 33 #endif 34 #include <stdio.h> 35 #include <string.h> 36 37 #include "type_local.h" 38 #include "aout68k.h" 39 #include "hux.h" 40 41 /* fseek() offset type */ 42 typedef long foff_t; 43 44 #ifndef DEFAULT_OUTPUT_FILE 45 # define DEFAULT_OUTPUT_FILE "out.x" 46 #endif 47 48 #ifdef DEBUG 49 # define DPRINTF(x) printf x 50 #else 51 # define DPRINTF(x) 52 #endif 53 54 struct exec_info { 55 foff_t text_off; /* file offset of text section */ 56 foff_t data_off; /* file offset of data section */ 57 u_int32_t text_size; /* size of text section */ 58 u_int32_t text_pad; /* pad between text and data */ 59 u_int32_t data_size; /* size of data section */ 60 u_int32_t bss_size; /* size of bss */ 61 u_int32_t entry_addr; /* entry point address */ 62 }; 63 64 unsigned get_uint16 PROTO((be_uint16_t *be)); 65 u_int32_t get_uint32 PROTO((be_uint32_t *be)); 66 void put_uint16 PROTO((be_uint16_t *be, unsigned v)); 67 void put_uint32 PROTO((be_uint32_t *be, u_int32_t v)); 68 void *do_realloc PROTO((void *p, size_t s)); 69 70 static int open_aout __P((const char *fn, struct aout_m68k *hdr, 71 struct exec_info *inf)); 72 static int open_elf PROTO((const char *fn, FILE *fp, struct elf_m68k_hdr *hdr, 73 struct exec_info *inf)); 74 FILE *open_exec PROTO((const char *fn, struct exec_info *inf)); 75 int check_2_exec_inf PROTO((struct exec_info *inf1, struct exec_info *inf2)); 76 int aout2hux PROTO((const char *fn1, const char *fn2, 77 u_int32_t loadadr1, u_int32_t loadadr2, const char *fnx)); 78 int gethex PROTO((u_int32_t *pval, const char *str)); 79 void usage PROTO((const char *name)); 80 int main PROTO((int argc, char *argv[])); 81 82 #if !defined(bzero) && defined(__SVR4) 83 # define bzero(d, n) memset((d), 0, (n)) 84 #endif 85 86 /* 87 * read/write big-endian integer 88 */ 89 90 unsigned 91 get_uint16(be) 92 be_uint16_t *be; 93 { 94 95 return be->val[0] << 8 | be->val[1]; 96 } 97 98 u_int32_t 99 get_uint32(be) 100 be_uint32_t *be; 101 { 102 103 return be->val[0]<<24 | be->val[1]<<16 | be->val[2]<<8 | be->val[3]; 104 } 105 106 void 107 put_uint16(be, v) 108 be_uint16_t *be; 109 unsigned v; 110 { 111 112 be->val[0] = (u_int8_t) (v >> 8); 113 be->val[1] = (u_int8_t) v; 114 } 115 116 void 117 put_uint32(be, v) 118 be_uint32_t *be; 119 u_int32_t v; 120 { 121 122 be->val[0] = (u_int8_t) (v >> 24); 123 be->val[1] = (u_int8_t) (v >> 16); 124 be->val[2] = (u_int8_t) (v >> 8); 125 be->val[3] = (u_int8_t) v; 126 } 127 128 void * 129 do_realloc(p, s) 130 void *p; 131 size_t s; 132 { 133 134 p = p ? realloc(p, s) : malloc(s); /* for portability */ 135 136 if (!p) { 137 fprintf(stderr, "malloc failed\n"); 138 exit(1); 139 } 140 141 return p; 142 } 143 144 /* 145 * check a.out header 146 */ 147 static int 148 open_aout(fn, hdr, inf) 149 const char *fn; 150 struct aout_m68k *hdr; 151 struct exec_info *inf; 152 { 153 int i; 154 155 DPRINTF(("%s: is an a.out\n", fn)); 156 157 if ((i = AOUT_GET_MID(hdr)) != AOUT_MID_M68K && i != AOUT_MID_M68K4K) { 158 fprintf(stderr, "%s: wrong architecture (mid %d)\n", fn, i); 159 return 1; 160 } 161 162 /* if unsolved relocations exist, not an executable but an object */ 163 if (hdr->a_trsize.hostval || hdr->a_drsize.hostval) { 164 fprintf(stderr, "%s: not an executable (object file?)\n", fn); 165 return 1; 166 } 167 168 if (AOUT_GET_FLAGS(hdr) & (AOUT_FLAG_PIC | AOUT_FLAG_DYNAMIC)) { 169 fprintf(stderr, "%s: PIC and DYNAMIC are not supported\n", fn); 170 return 1; 171 } 172 173 inf->text_size = get_uint32(&hdr->a_text); 174 inf->data_size = get_uint32(&hdr->a_data); 175 inf->bss_size = get_uint32(&hdr->a_bss); 176 inf->entry_addr = get_uint32(&hdr->a_entry); 177 inf->text_off = sizeof(struct aout_m68k); 178 inf->data_off = sizeof(struct aout_m68k) + inf->text_size; 179 inf->text_pad = -inf->text_size & (AOUT_PAGESIZE(hdr) - 1); 180 181 return 0; 182 } 183 184 /* 185 * digest ELF structure 186 */ 187 static int 188 open_elf(fn, fp, hdr, inf) 189 const char *fn; 190 FILE *fp; 191 struct elf_m68k_hdr *hdr; 192 struct exec_info *inf; 193 { 194 int i; 195 size_t nphdr; 196 struct elf_m68k_phdr phdr[2]; 197 198 DPRINTF(("%s: is an ELF\n", fn)); 199 200 if (hdr->e_ident[EI_VERSION] != EV_CURRENT || 201 get_uint32(&hdr->e_version) != EV_CURRENT) { 202 fprintf(stderr, "%s: unknown ELF version\n", fn); 203 return 1; 204 } 205 206 if (get_uint16(&hdr->e_type) != ET_EXEC) { 207 fprintf(stderr, "%s: not an executable\n", fn); 208 return 1; 209 } 210 211 if ((i = get_uint16(&hdr->e_machine)) != EM_68K) { 212 fprintf(stderr, "%s: wrong architecture (%d)\n", fn, i); 213 return 1; 214 } 215 216 if ((i = get_uint16(&hdr->e_shentsize)) != SIZE_ELF68K_SHDR) { 217 fprintf(stderr, "%s: size shdr %d should be %d\n", fn, i, 218 SIZE_ELF68K_SHDR); 219 return 1; 220 } 221 222 if ((i = get_uint16(&hdr->e_phentsize)) != SIZE_ELF68K_PHDR) { 223 fprintf(stderr, "%s: size phdr %d should be %d\n", fn, i, 224 SIZE_ELF68K_PHDR); 225 return 1; 226 } 227 228 if ((nphdr = get_uint16(&hdr->e_phnum)) != 1 && nphdr != 2) { 229 fprintf(stderr, 230 "%s: has %d loadable segments (should be 1 or 2)\n", 231 fn, nphdr); 232 return 1; 233 } 234 235 /* Read ELF program header table. */ 236 if (fseek(fp, (foff_t) get_uint32(&hdr->e_phoff), SEEK_SET)) { 237 perror(fn); 238 return 1; 239 } 240 if (fread(phdr, sizeof phdr[0], nphdr, fp) != nphdr) { 241 fprintf(stderr, "%s: can't read ELF program header\n", fn); 242 return 1; 243 } 244 245 /* Just error checking. */ 246 for (i = 0; i < (int) nphdr; i++) { 247 if (get_uint32(&phdr[i].p_type) != PT_LOAD) { 248 fprintf(stderr, 249 "%s: program header #%d is not loadable\n", 250 fn, i); 251 return 1; 252 } 253 } 254 255 if (nphdr == 1 && (get_uint32(&phdr[0].p_flags) & PF_W)) { 256 /* 257 * Only one writable section --- probably "ld -N" executable. 258 * Find out the start of data segment. 259 */ 260 struct elf_m68k_shdr shdr; 261 int nshdr; 262 263 nshdr = get_uint16(&hdr->e_shnum); 264 265 /* section #0 always exists and reserved --- skip */ 266 if (nshdr > 1 && 267 fseek(fp, 268 (foff_t) (get_uint32(&hdr->e_shoff) + sizeof shdr), 269 SEEK_SET)) { 270 perror(fn); 271 return 1; 272 } 273 for (i = 1; i < nshdr; i++) { 274 if (fread(&shdr, sizeof shdr, 1, fp) != 1) { 275 fprintf(stderr, 276 "%s: can't read ELF section header\n", 277 fn); 278 return 1; 279 } 280 281 DPRINTF(("%s: section header #%d: flags 0x%x\n", 282 fn, i, get_uint32(&shdr.sh_flags))); 283 284 if (ELF68K_ISDATASEG(&shdr)) { 285 /* 286 * data section is found. 287 */ 288 DPRINTF(("%s: one section, data found\n", fn)); 289 inf->text_off = get_uint32(&phdr[0].p_offset); 290 inf->text_size = get_uint32(&shdr.sh_offset) - 291 inf->text_off; 292 inf->text_pad = 0; 293 inf->data_off = inf->text_off + inf->text_size; 294 inf->data_size = get_uint32(&phdr[0].p_filesz) - 295 inf->text_size; 296 inf->bss_size = get_uint32(&phdr[0].p_memsz) - 297 get_uint32(&phdr[0].p_filesz); 298 inf->entry_addr = get_uint32(&hdr->e_entry); 299 goto data_found; 300 } 301 } 302 /* 303 * No data section found --- probably text + bss. 304 */ 305 DPRINTF(("%s: one section, no data section\n", fn)); 306 inf->text_size = get_uint32(&phdr[0].p_filesz); 307 inf->data_size = 0; 308 inf->bss_size = get_uint32(&phdr[0].p_memsz) - inf->text_size; 309 inf->entry_addr = get_uint32(&hdr->e_entry); 310 inf->text_off = get_uint32(&phdr[0].p_offset); 311 inf->data_off = 0; 312 inf->text_pad = 0; 313 data_found:; 314 } else if (nphdr == 1) { 315 /* 316 * Only one non-writable section --- pure text program? 317 */ 318 DPRINTF(("%s: one RO section\n", fn)); 319 inf->text_size = get_uint32(&phdr[0].p_filesz); 320 inf->data_size = 0; 321 inf->bss_size = 0; 322 inf->entry_addr = get_uint32(&hdr->e_entry); 323 inf->text_off = get_uint32(&phdr[0].p_offset); 324 inf->data_off = 0; 325 inf->text_pad = get_uint32(&phdr[0].p_memsz) - inf->text_size; 326 } else { 327 /* 328 * two sections 329 * text + data assumed. 330 */ 331 int t = 0, d = 1, tmp; /* first guess */ 332 #define SWAP_T_D tmp = t, t = d, d = tmp 333 334 DPRINTF(("%s: two sections\n", fn)); 335 336 /* Find out text and data. */ 337 if (get_uint32(&phdr[t].p_vaddr) > get_uint32(&phdr[d].p_vaddr)) 338 SWAP_T_D; 339 340 if ((get_uint32(&phdr[t].p_flags) & PF_X) == 0 && 341 get_uint32(&phdr[d].p_flags) & PF_X) 342 SWAP_T_D; 343 344 if ((get_uint32(&phdr[d].p_flags) & PF_W) == 0 && 345 get_uint32(&phdr[t].p_flags) & PF_W) 346 SWAP_T_D; 347 #undef SWAP_T_D 348 349 /* Are the text/data sections correctly detected? */ 350 if (get_uint32(&phdr[t].p_vaddr) > 351 get_uint32(&phdr[d].p_vaddr)) { 352 fprintf(stderr, "%s: program sections not in order\n", 353 fn); 354 return 1; 355 } 356 357 if ((get_uint32(&phdr[t].p_flags) & PF_X) == 0) 358 fprintf(stderr, "%s: warning: text is not executable\n", 359 fn); 360 361 if ((get_uint32(&phdr[d].p_flags) & PF_W) == 0) 362 fprintf(stderr, "%s: warning: data is not writable\n", 363 fn); 364 365 inf->text_size = get_uint32(&phdr[t].p_filesz); 366 inf->data_size = get_uint32(&phdr[d].p_filesz); 367 inf->bss_size = get_uint32(&phdr[d].p_memsz) - inf->data_size; 368 inf->entry_addr = get_uint32(&hdr->e_entry); 369 inf->text_off = get_uint32(&phdr[t].p_offset); 370 inf->data_off = get_uint32(&phdr[d].p_offset); 371 inf->text_pad = get_uint32(&phdr[d].p_vaddr) - 372 (get_uint32(&phdr[t].p_vaddr) + inf->text_size); 373 } 374 375 return 0; 376 } 377 378 /* 379 * open an executable 380 */ 381 FILE * 382 open_exec(fn, inf) 383 const char *fn; 384 struct exec_info *inf; 385 { 386 FILE *fp; 387 int i; 388 union { 389 struct aout_m68k u_aout; 390 struct elf_m68k_hdr u_elf; 391 } buf; 392 #define hdra (&buf.u_aout) 393 #define hdre (&buf.u_elf) 394 395 if (!(fp = fopen(fn, "r"))) { 396 perror(fn); 397 return (FILE *) NULL; 398 } 399 400 /* 401 * Check for a.out. 402 */ 403 404 if (fread(hdra, sizeof(struct aout_m68k), 1, fp) != 1) { 405 fprintf(stderr, "%s: can't read a.out header\n", fn); 406 goto out; 407 } 408 409 if ((i = AOUT_GET_MAGIC(hdra)) != AOUT_OMAGIC && i != AOUT_NMAGIC) 410 goto notaout; 411 412 if (open_aout(fn, hdra, inf)) 413 goto out; 414 415 /* OK! */ 416 return fp; 417 418 notaout: 419 /* 420 * Check for ELF. 421 */ 422 423 if (hdre->e_ident[EI_MAG0] != ELFMAG0 || 424 hdre->e_ident[EI_MAG1] != ELFMAG1 || 425 hdre->e_ident[EI_MAG2] != ELFMAG2 || 426 hdre->e_ident[EI_MAG3] != ELFMAG3 || 427 hdre->e_ident[EI_CLASS] != ELFCLASS32 || 428 hdre->e_ident[EI_DATA] != ELFDATA2MSB) { 429 fprintf(stderr, 430 "%s: not an OMAGIC or NMAGIC a.out, or a 32bit BE ELF\n", 431 fn); 432 goto out; 433 } 434 435 /* ELF header is longer than a.out header. Read the rest. */ 436 if (fread(hdra + 1, 437 sizeof(struct elf_m68k_hdr) - sizeof(struct aout_m68k), 438 1, fp) != 1) { 439 fprintf(stderr, "%s: can't read ELF header\n", fn); 440 goto out; 441 } 442 443 if (open_elf(fn, fp, hdre, inf)) 444 goto out; 445 446 /* OK! */ 447 return fp; 448 449 out: fclose(fp); 450 return (FILE *) NULL; 451 #undef hdra 452 #undef hdre 453 } 454 455 /* 456 * compare two executables and check if they are compatible 457 */ 458 int 459 check_2_exec_inf(inf1, inf2) 460 struct exec_info *inf1, *inf2; 461 { 462 463 if (inf1->text_size != inf2->text_size || 464 inf1->text_pad != inf2->text_pad || 465 inf1->data_size != inf2->data_size || 466 inf1->bss_size != inf2->bss_size) 467 return -1; 468 469 return 0; 470 } 471 472 /* allocation unit (in bytes) of relocation table */ 473 #define RELTBL_CHUNK 8192 474 475 /* 476 * add an entry to the relocation table 477 */ 478 #define ADD_RELTBL(adr) \ 479 if (relsize + sizeof(struct relinf_l) > relallocsize) \ 480 reltbl = do_realloc(reltbl, relallocsize += RELTBL_CHUNK); \ 481 if ((adr) < reladdr + HUX_MINLREL) { \ 482 struct relinf_s *r = (struct relinf_s *)(reltbl + relsize); \ 483 put_uint16(&r->locoff_s, (unsigned)((adr) - reladdr)); \ 484 relsize += sizeof(struct relinf_s); \ 485 DPRINTF(("short")); \ 486 } else { \ 487 struct relinf_l *r = (struct relinf_l *)(reltbl + relsize); \ 488 put_uint16(&r->lrelmag, HUXLRELMAGIC); \ 489 put_uint32((be_uint32_t *)r->locoff_l, (adr) - reladdr); \ 490 relsize += sizeof(struct relinf_l); \ 491 DPRINTF(("long ")); \ 492 } \ 493 DPRINTF((" reloc 0x%06x", (adr))); \ 494 reladdr = (adr); 495 496 #define ERR1 { if (ferror(fpa1)) perror(fn1); \ 497 else fprintf(stderr, "%s: unexpected EOF\n", fn1); \ 498 goto out; } 499 #define ERR2 { if (ferror(fpa2)) perror(fn2); \ 500 else fprintf(stderr, "%s: unexpected EOF\n", fn2); \ 501 goto out; } 502 #define ERRC { fprintf(stderr, "files %s and %s are inconsistent\n", \ 503 fn1, fn2); \ 504 goto out; } 505 506 /* 507 * read input executables and output .x body 508 * and create relocation table 509 */ 510 #define CREATE_RELOCATION(segsize) \ 511 while (segsize > 0 || nbuf) { \ 512 if (nbuf == 0) { \ 513 if (fread(&b1.half[0], SIZE_16, 1, fpa1) != 1) \ 514 ERR1 \ 515 if (fread(&b2.half[0], SIZE_16, 1, fpa2) != 1) \ 516 ERR2 \ 517 nbuf = 1; \ 518 segsize -= SIZE_16; \ 519 } else if (nbuf == 1) { \ 520 if (segsize == 0) { \ 521 if (b1.half[0].hostval != b2.half[0].hostval) \ 522 ERRC \ 523 fwrite(&b1.half[0], SIZE_16, 1, fpx); \ 524 nbuf = 0; \ 525 addr += SIZE_16; \ 526 } else { \ 527 if (fread(&b1.half[1], SIZE_16, 1, fpa1) != 1)\ 528 ERR1 \ 529 if (fread(&b2.half[1], SIZE_16, 1, fpa2) != 1)\ 530 ERR2 \ 531 nbuf = 2; \ 532 segsize -= SIZE_16; \ 533 } \ 534 } else /* if (nbuf == 2) */ { \ 535 if (b1.hostval != b2.hostval && \ 536 get_uint32(&b1) - loadadr1 \ 537 == get_uint32(&b2) - loadadr2) {\ 538 /* do relocation */ \ 539 ADD_RELTBL(addr) \ 540 \ 541 put_uint32(&b1, get_uint32(&b1) - loadadr1); \ 542 DPRINTF((" v 0x%08x\t", get_uint32(&b1))); \ 543 fwrite(&b1, SIZE_32, 1, fpx); \ 544 nbuf = 0; \ 545 addr += SIZE_32; \ 546 } else if (b1.half[0].hostval == b2.half[0].hostval) {\ 547 fwrite(&b1.half[0], SIZE_16, 1, fpx); \ 548 addr += SIZE_16; \ 549 b1.half[0] = b1.half[1]; \ 550 b2.half[0] = b2.half[1]; \ 551 nbuf = 1; \ 552 } else \ 553 ERRC \ 554 } \ 555 } 556 557 int 558 aout2hux(fn1, fn2, loadadr1, loadadr2, fnx) 559 const char *fn1, *fn2, *fnx; 560 u_int32_t loadadr1, loadadr2; 561 { 562 int status = 1; /* the default is "failed" */ 563 FILE *fpa1 = NULL, *fpa2 = NULL; 564 struct exec_info inf1, inf2; 565 FILE *fpx = NULL; 566 struct huxhdr xhdr; 567 u_int32_t textsize, datasize, paddingsize, execoff; 568 569 /* for relocation */ 570 be_uint32_t b1, b2; 571 int nbuf; 572 u_int32_t addr; 573 574 /* for relocation table */ 575 size_t relsize, relallocsize; 576 u_int32_t reladdr; 577 char *reltbl = NULL; 578 579 580 /* 581 * check load addresses 582 */ 583 if (loadadr1 == loadadr2) { 584 fprintf(stderr, "two load addresses must be different\n"); 585 return 1; 586 } 587 588 /* 589 * open input executables and check them 590 */ 591 if (!(fpa1 = open_exec(fn1, &inf1)) || !(fpa2 = open_exec(fn2, &inf2))) 592 goto out; 593 594 /* 595 * check for consistency 596 */ 597 if (check_2_exec_inf(&inf1, &inf2)) { 598 fprintf(stderr, "files %s and %s are incompatible\n", 599 fn1, fn2); 600 goto out; 601 } 602 /* check entry address */ 603 if (inf1.entry_addr - loadadr1 != inf2.entry_addr - loadadr2) { 604 fprintf(stderr, "address of %s or %s may be incorrect\n", 605 fn1, fn2); 606 goto out; 607 } 608 609 /* 610 * get information of the executables 611 */ 612 textsize = inf1.text_size; 613 paddingsize = inf1.text_pad; 614 datasize = inf1.data_size; 615 execoff = inf1.entry_addr - loadadr1; 616 617 DPRINTF(("text: %u, data: %u, pad: %u, bss: %u, exec: %u\n", 618 textsize, datasize, paddingsize, inf1.bss_size, execoff)); 619 620 if (textsize & 1) { 621 fprintf(stderr, "text size is not even\n"); 622 goto out; 623 } 624 if (datasize & 1) { 625 fprintf(stderr, "data size is not even\n"); 626 goto out; 627 } 628 if (execoff >= textsize && 629 (execoff < textsize + paddingsize || 630 execoff >= textsize + paddingsize + datasize)) { 631 fprintf(stderr, "exec addr is not in text or data segment\n"); 632 goto out; 633 } 634 635 /* 636 * prepare for .x header 637 */ 638 bzero((void *) &xhdr, sizeof xhdr); 639 put_uint16(&xhdr.x_magic, HUXMAGIC); 640 put_uint32(&xhdr.x_entry, execoff); 641 put_uint32(&xhdr.x_text, textsize + paddingsize); 642 put_uint32(&xhdr.x_data, inf1.data_size); 643 put_uint32(&xhdr.x_bss, inf1.bss_size); 644 645 /* 646 * create output file 647 */ 648 if (!(fpx = fopen(fnx, "w")) || 649 fseek(fpx, (foff_t) sizeof xhdr, SEEK_SET)) { /* skip header */ 650 perror(fnx); 651 goto out; 652 } 653 654 addr = 0; 655 nbuf = 0; 656 657 relsize = relallocsize = 0; 658 reladdr = 0; 659 660 /* 661 * text segment 662 */ 663 if (fseek(fpa1, inf1.text_off, SEEK_SET)) { 664 perror(fn1); 665 goto out; 666 } 667 if (fseek(fpa2, inf2.text_off, SEEK_SET)) { 668 perror(fn2); 669 goto out; 670 } 671 CREATE_RELOCATION(textsize) 672 673 /* 674 * page boundary 675 */ 676 addr += paddingsize; 677 while (paddingsize--) 678 putc('\0', fpx); 679 680 /* 681 * data segment 682 */ 683 if (fseek(fpa1, inf1.data_off, SEEK_SET)) { 684 perror(fn1); 685 goto out; 686 } 687 if (fseek(fpa2, inf2.data_off, SEEK_SET)) { 688 perror(fn2); 689 goto out; 690 } 691 CREATE_RELOCATION(datasize) 692 693 /* 694 * error check of the above 695 */ 696 if (ferror(fpx)) { 697 fprintf(stderr, "%s: write failure\n", fnx); 698 goto out; 699 } 700 701 /* 702 * write relocation table 703 */ 704 if (relsize > 0) { 705 DPRINTF(("\n")); 706 if (fwrite(reltbl, 1, relsize, fpx) != relsize) { 707 perror(fnx); 708 goto out; 709 } 710 } 711 712 /* 713 * write .x header at the top of the output file 714 */ 715 put_uint32(&xhdr.x_rsize, relsize); 716 if (fseek(fpx, (foff_t) 0, SEEK_SET) || 717 fwrite(&xhdr, sizeof xhdr, 1, fpx) != 1) { 718 perror(fnx); 719 goto out; 720 } 721 722 status = 0; /* all OK */ 723 724 out: /* 725 * cleanup 726 */ 727 if (fpa1) 728 fclose(fpa1); 729 if (fpa2) 730 fclose(fpa2); 731 if (fpx) { 732 if (fclose(fpx) && status == 0) { 733 /* Alas, final flush failed! */ 734 perror(fnx); 735 status = 1; 736 } 737 if (status) 738 remove(fnx); 739 } 740 if (reltbl) 741 free(reltbl); 742 743 return status; 744 } 745 746 #ifndef NO_BIST 747 void bist PROTO((void)); 748 749 /* 750 * built-in self test 751 */ 752 void 753 bist() 754 { 755 be_uint16_t be16; 756 be_uint32_t be32; 757 be_uint32_t be32x2[2]; 758 759 be16.val[0] = 0x12; be16.val[1] = 0x34; 760 be32.val[0] = 0xfe; be32.val[1] = 0xdc; 761 be32.val[2] = 0xba; be32.val[3] = 0x98; 762 763 put_uint16(&be32x2[0].half[1], 0x4567); 764 put_uint32(&be32x2[1], 0xa9876543); 765 766 if (sizeof(u_int8_t) != 1 || sizeof(u_int16_t) != 2 || 767 sizeof(u_int32_t) != 4 || 768 SIZE_16 != 2 || SIZE_32 != 4 || sizeof be32x2 != 8 || 769 sizeof(struct relinf_s) != 2 || sizeof(struct relinf_l) != 6 || 770 SIZE_ELF68K_HDR != 52 || SIZE_ELF68K_SHDR != 40 || 771 SIZE_ELF68K_PHDR != 32 || 772 get_uint16(&be16) != 0x1234 || get_uint32(&be32) != 0xfedcba98 || 773 get_uint16(&be32x2[0].half[1]) != 0x4567 || 774 get_uint32(&be32x2[1]) != 0xa9876543) { 775 fprintf(stderr, "BIST failed\n"); 776 exit(1); 777 } 778 } 779 #endif 780 781 int 782 gethex(pval, str) 783 u_int32_t *pval; 784 const char *str; 785 { 786 const unsigned char *p = (const unsigned char *) str; 787 u_int32_t val; 788 int over; 789 790 /* skip leading "0x" if exists */ 791 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) 792 p += 2; 793 794 if (!*p) 795 goto bad; 796 797 for (val = 0, over = 0; *p; p++) { 798 int digit; 799 800 switch (*p) { 801 case '0': case '1': case '2': case '3': case '4': 802 case '5': case '6': case '7': case '8': case '9': 803 digit = *p - '0'; 804 break; 805 case 'a': case 'A': digit = 10; break; 806 case 'b': case 'B': digit = 11; break; 807 case 'c': case 'C': digit = 12; break; 808 case 'd': case 'D': digit = 13; break; 809 case 'e': case 'E': digit = 14; break; 810 case 'f': case 'F': digit = 15; break; 811 default: 812 goto bad; 813 } 814 if (val >= 0x10000000) 815 over = 1; 816 val = (val << 4) | digit; 817 } 818 819 if (over) 820 fprintf(stderr, "warning: %s: constant overflow\n", str); 821 822 *pval = val; 823 824 DPRINTF(("gethex: %s -> 0x%x\n", str, val)); 825 826 return 0; 827 828 bad: 829 fprintf(stderr, "%s: not a hexadecimal number\n", str); 830 return 1; 831 } 832 833 void 834 usage(name) 835 const char *name; 836 { 837 838 fprintf(stderr, "\ 839 usage: %s [ -o output.x ] a.out1 loadaddr1 a.out2 loadaddr2\n\n\ 840 The input files must be static OMAGIC/NMAGIC m68k a.out executables\n\ 841 or m68k ELF executables.\n\ 842 Two executables must have different loading addresses.\n\ 843 Each of the load address must be a hexadecimal number.\n\ 844 The default output filename is \"%s\".\n" ,name, DEFAULT_OUTPUT_FILE); 845 846 exit(1); 847 } 848 849 int 850 main(argc, argv) 851 int argc; 852 char *argv[]; 853 { 854 const char *outfile = DEFAULT_OUTPUT_FILE; 855 u_int32_t adr1, adr2; 856 857 #ifndef NO_BIST 858 bist(); 859 #endif 860 861 if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o' && !argv[1][2]) { 862 outfile = argv[2]; 863 argv += 2; 864 argc -= 2; 865 } 866 867 if (argc != 5) 868 usage(argv[0]); 869 870 if (gethex(&adr1, argv[2]) || gethex(&adr2, argv[4])) 871 usage(argv[0]); 872 873 return aout2hux(argv[1], argv[3], adr1, adr2, outfile); 874 } 875