1 /* 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 15 #include "vpx_config.h" 16 17 #if defined(_MSC_VER) || defined(__MINGW32__) 18 #include <io.h> 19 #include <share.h> 20 #include "vpx/vpx_integer.h" 21 #else 22 #include <stdint.h> 23 #include <unistd.h> 24 #endif 25 26 #include <string.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <fcntl.h> 30 #include <stdarg.h> 31 32 typedef enum 33 { 34 OUTPUT_FMT_PLAIN, 35 OUTPUT_FMT_RVDS, 36 OUTPUT_FMT_GAS, 37 } output_fmt_t; 38 39 int log_msg(const char *fmt, ...) 40 { 41 int res; 42 va_list ap; 43 va_start(ap, fmt); 44 res = vfprintf(stderr, fmt, ap); 45 va_end(ap); 46 return res; 47 } 48 49 #if defined(__GNUC__) && __GNUC__ 50 51 #if defined(__MACH__) 52 53 #include <mach-o/loader.h> 54 #include <mach-o/nlist.h> 55 56 int parse_macho(uint8_t *base_buf, size_t sz) 57 { 58 int i, j; 59 struct mach_header header; 60 uint8_t *buf = base_buf; 61 int base_data_section = 0; 62 int bits = 0; 63 64 /* We can read in mach_header for 32 and 64 bit architectures 65 * because it's identical to mach_header_64 except for the last 66 * element (uint32_t reserved), which we don't use. Then, when 67 * we know which architecture we're looking at, increment buf 68 * appropriately. 69 */ 70 memcpy(&header, buf, sizeof(struct mach_header)); 71 72 if (header.magic == MH_MAGIC) 73 { 74 if (header.cputype == CPU_TYPE_ARM 75 || header.cputype == CPU_TYPE_X86) 76 { 77 bits = 32; 78 buf += sizeof(struct mach_header); 79 } 80 else 81 { 82 log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_[ARM|X86].\n"); 83 goto bail; 84 } 85 } 86 else if (header.magic == MH_MAGIC_64) 87 { 88 if (header.cputype == CPU_TYPE_X86_64) 89 { 90 bits = 64; 91 buf += sizeof(struct mach_header_64); 92 } 93 else 94 { 95 log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_X86_64.\n"); 96 goto bail; 97 } 98 } 99 else 100 { 101 log_msg("Bad magic number for object file. 0x%x or 0x%x expected, 0x%x found.\n", 102 MH_MAGIC, MH_MAGIC_64, header.magic); 103 goto bail; 104 } 105 106 if (header.filetype != MH_OBJECT) 107 { 108 log_msg("Bad filetype for object file. Currently only tested for MH_OBJECT.\n"); 109 goto bail; 110 } 111 112 for (i = 0; i < header.ncmds; i++) 113 { 114 struct load_command lc; 115 116 memcpy(&lc, buf, sizeof(struct load_command)); 117 118 if (lc.cmd == LC_SEGMENT) 119 { 120 uint8_t *seg_buf = buf; 121 struct section s; 122 struct segment_command seg_c; 123 124 memcpy(&seg_c, seg_buf, sizeof(struct segment_command)); 125 seg_buf += sizeof(struct segment_command); 126 127 /* Although each section is given it's own offset, nlist.n_value 128 * references the offset of the first section. This isn't 129 * apparent without debug information because the offset of the 130 * data section is the same as the first section. However, with 131 * debug sections mixed in, the offset of the debug section 132 * increases but n_value still references the first section. 133 */ 134 if (seg_c.nsects < 1) 135 { 136 log_msg("Not enough sections\n"); 137 goto bail; 138 } 139 140 memcpy(&s, seg_buf, sizeof(struct section)); 141 base_data_section = s.offset; 142 } 143 else if (lc.cmd == LC_SEGMENT_64) 144 { 145 uint8_t *seg_buf = buf; 146 struct section_64 s; 147 struct segment_command_64 seg_c; 148 149 memcpy(&seg_c, seg_buf, sizeof(struct segment_command_64)); 150 seg_buf += sizeof(struct segment_command_64); 151 152 /* Explanation in LG_SEGMENT */ 153 if (seg_c.nsects < 1) 154 { 155 log_msg("Not enough sections\n"); 156 goto bail; 157 } 158 159 memcpy(&s, seg_buf, sizeof(struct section_64)); 160 base_data_section = s.offset; 161 } 162 else if (lc.cmd == LC_SYMTAB) 163 { 164 if (base_data_section != 0) 165 { 166 struct symtab_command sc; 167 uint8_t *sym_buf = base_buf; 168 uint8_t *str_buf = base_buf; 169 170 memcpy(&sc, buf, sizeof(struct symtab_command)); 171 172 if (sc.cmdsize != sizeof(struct symtab_command)) 173 { 174 log_msg("Can't find symbol table!\n"); 175 goto bail; 176 } 177 178 sym_buf += sc.symoff; 179 str_buf += sc.stroff; 180 181 for (j = 0; j < sc.nsyms; j++) 182 { 183 /* Location of string is cacluated each time from the 184 * start of the string buffer. On darwin the symbols 185 * are prefixed by "_", so we bump the pointer by 1. 186 * The target value is defined as an int in asm_*_offsets.c, 187 * which is 4 bytes on all targets we currently use. 188 */ 189 if (bits == 32) 190 { 191 struct nlist nl; 192 int val; 193 194 memcpy(&nl, sym_buf, sizeof(struct nlist)); 195 sym_buf += sizeof(struct nlist); 196 197 memcpy(&val, base_buf + base_data_section + nl.n_value, 198 sizeof(val)); 199 printf("%-40s EQU %5d\n", 200 str_buf + nl.n_un.n_strx + 1, val); 201 } 202 else /* if (bits == 64) */ 203 { 204 struct nlist_64 nl; 205 int val; 206 207 memcpy(&nl, sym_buf, sizeof(struct nlist_64)); 208 sym_buf += sizeof(struct nlist_64); 209 210 memcpy(&val, base_buf + base_data_section + nl.n_value, 211 sizeof(val)); 212 printf("%-40s EQU %5d\n", 213 str_buf + nl.n_un.n_strx + 1, val); 214 } 215 } 216 } 217 } 218 219 buf += lc.cmdsize; 220 } 221 222 return 0; 223 bail: 224 return 1; 225 226 } 227 228 int main(int argc, char **argv) 229 { 230 int fd; 231 char *f; 232 struct stat stat_buf; 233 uint8_t *file_buf; 234 int res; 235 236 if (argc < 2 || argc > 3) 237 { 238 fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]); 239 fprintf(stderr, " <obj file>\tMachO format object file to parse\n"); 240 fprintf(stderr, "Output Formats:\n"); 241 fprintf(stderr, " gas - compatible with GNU assembler\n"); 242 fprintf(stderr, " rvds - compatible with armasm\n"); 243 goto bail; 244 } 245 246 f = argv[2]; 247 248 if (!((!strcmp(argv[1], "rvds")) || (!strcmp(argv[1], "gas")))) 249 f = argv[1]; 250 251 fd = open(f, O_RDONLY); 252 253 if (fd < 0) 254 { 255 perror("Unable to open file"); 256 goto bail; 257 } 258 259 if (fstat(fd, &stat_buf)) 260 { 261 perror("stat"); 262 goto bail; 263 } 264 265 file_buf = malloc(stat_buf.st_size); 266 267 if (!file_buf) 268 { 269 perror("malloc"); 270 goto bail; 271 } 272 273 if (read(fd, file_buf, stat_buf.st_size) != stat_buf.st_size) 274 { 275 perror("read"); 276 goto bail; 277 } 278 279 if (close(fd)) 280 { 281 perror("close"); 282 goto bail; 283 } 284 285 res = parse_macho(file_buf, stat_buf.st_size); 286 free(file_buf); 287 288 if (!res) 289 return EXIT_SUCCESS; 290 291 bail: 292 return EXIT_FAILURE; 293 } 294 295 #elif defined(__ELF__) 296 #include "elf.h" 297 298 #define COPY_STRUCT(dst, buf, ofst, sz) do {\ 299 if(ofst + sizeof((*(dst))) > sz) goto bail;\ 300 memcpy(dst, buf+ofst, sizeof((*(dst))));\ 301 } while(0) 302 303 #define ENDIAN_ASSIGN(val, memb) do {\ 304 if(!elf->le_data) {log_msg("Big Endian data not supported yet!\n");goto bail;}\ 305 (val) = (memb);\ 306 } while(0) 307 308 #define ENDIAN_ASSIGN_IN_PLACE(memb) do {\ 309 ENDIAN_ASSIGN(memb, memb);\ 310 } while(0) 311 312 typedef struct 313 { 314 uint8_t *buf; /* Buffer containing ELF data */ 315 size_t sz; /* Buffer size */ 316 int le_data; /* Data is little-endian */ 317 unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 318 int bits; /* 32 or 64 */ 319 Elf32_Ehdr hdr32; 320 Elf64_Ehdr hdr64; 321 } elf_obj_t; 322 323 int parse_elf_header(elf_obj_t *elf) 324 { 325 int res; 326 /* Verify ELF Magic numbers */ 327 COPY_STRUCT(&elf->e_ident, elf->buf, 0, elf->sz); 328 res = elf->e_ident[EI_MAG0] == ELFMAG0; 329 res &= elf->e_ident[EI_MAG1] == ELFMAG1; 330 res &= elf->e_ident[EI_MAG2] == ELFMAG2; 331 res &= elf->e_ident[EI_MAG3] == ELFMAG3; 332 res &= elf->e_ident[EI_CLASS] == ELFCLASS32 333 || elf->e_ident[EI_CLASS] == ELFCLASS64; 334 res &= elf->e_ident[EI_DATA] == ELFDATA2LSB; 335 336 if (!res) goto bail; 337 338 elf->le_data = elf->e_ident[EI_DATA] == ELFDATA2LSB; 339 340 /* Read in relevant values */ 341 if (elf->e_ident[EI_CLASS] == ELFCLASS32) 342 { 343 elf->bits = 32; 344 COPY_STRUCT(&elf->hdr32, elf->buf, 0, elf->sz); 345 346 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_type); 347 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_machine); 348 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_version); 349 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_entry); 350 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phoff); 351 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shoff); 352 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_flags); 353 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_ehsize); 354 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phentsize); 355 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phnum); 356 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shentsize); 357 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shnum); 358 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shstrndx); 359 } 360 else /* if (elf->e_ident[EI_CLASS] == ELFCLASS64) */ 361 { 362 elf->bits = 64; 363 COPY_STRUCT(&elf->hdr64, elf->buf, 0, elf->sz); 364 365 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_type); 366 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_machine); 367 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_version); 368 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_entry); 369 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phoff); 370 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shoff); 371 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_flags); 372 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_ehsize); 373 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phentsize); 374 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phnum); 375 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shentsize); 376 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shnum); 377 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shstrndx); 378 } 379 380 return 0; 381 bail: 382 log_msg("Failed to parse ELF file header"); 383 return 1; 384 } 385 386 int parse_elf_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr32, Elf64_Shdr *hdr64) 387 { 388 if (hdr32) 389 { 390 if (idx >= elf->hdr32.e_shnum) 391 goto bail; 392 393 COPY_STRUCT(hdr32, elf->buf, elf->hdr32.e_shoff + idx * elf->hdr32.e_shentsize, 394 elf->sz); 395 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_name); 396 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_type); 397 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_flags); 398 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addr); 399 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_offset); 400 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_size); 401 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_link); 402 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_info); 403 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addralign); 404 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_entsize); 405 } 406 else /* if (hdr64) */ 407 { 408 if (idx >= elf->hdr64.e_shnum) 409 goto bail; 410 411 COPY_STRUCT(hdr64, elf->buf, elf->hdr64.e_shoff + idx * elf->hdr64.e_shentsize, 412 elf->sz); 413 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_name); 414 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_type); 415 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_flags); 416 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addr); 417 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_offset); 418 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_size); 419 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_link); 420 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_info); 421 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addralign); 422 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_entsize); 423 } 424 425 return 0; 426 bail: 427 return 1; 428 } 429 430 char *parse_elf_string_table(elf_obj_t *elf, int s_idx, int idx) 431 { 432 if (elf->bits == 32) 433 { 434 Elf32_Shdr shdr; 435 436 if (parse_elf_section(elf, s_idx, &shdr, NULL)) 437 { 438 log_msg("Failed to parse ELF string table: section %d, index %d\n", 439 s_idx, idx); 440 return ""; 441 } 442 443 return (char *)(elf->buf + shdr.sh_offset + idx); 444 } 445 else /* if (elf->bits == 64) */ 446 { 447 Elf64_Shdr shdr; 448 449 if (parse_elf_section(elf, s_idx, NULL, &shdr)) 450 { 451 log_msg("Failed to parse ELF string table: section %d, index %d\n", 452 s_idx, idx); 453 return ""; 454 } 455 456 return (char *)(elf->buf + shdr.sh_offset + idx); 457 } 458 } 459 460 int parse_elf_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym32, Elf64_Sym *sym64) 461 { 462 if (sym32) 463 { 464 COPY_STRUCT(sym32, elf->buf, ofst, elf->sz); 465 ENDIAN_ASSIGN_IN_PLACE(sym32->st_name); 466 ENDIAN_ASSIGN_IN_PLACE(sym32->st_value); 467 ENDIAN_ASSIGN_IN_PLACE(sym32->st_size); 468 ENDIAN_ASSIGN_IN_PLACE(sym32->st_info); 469 ENDIAN_ASSIGN_IN_PLACE(sym32->st_other); 470 ENDIAN_ASSIGN_IN_PLACE(sym32->st_shndx); 471 } 472 else /* if (sym64) */ 473 { 474 COPY_STRUCT(sym64, elf->buf, ofst, elf->sz); 475 ENDIAN_ASSIGN_IN_PLACE(sym64->st_name); 476 ENDIAN_ASSIGN_IN_PLACE(sym64->st_value); 477 ENDIAN_ASSIGN_IN_PLACE(sym64->st_size); 478 ENDIAN_ASSIGN_IN_PLACE(sym64->st_info); 479 ENDIAN_ASSIGN_IN_PLACE(sym64->st_other); 480 ENDIAN_ASSIGN_IN_PLACE(sym64->st_shndx); 481 } 482 return 0; 483 bail: 484 return 1; 485 } 486 487 int parse_elf(uint8_t *buf, size_t sz, output_fmt_t mode) 488 { 489 elf_obj_t elf; 490 unsigned int ofst; 491 int i; 492 Elf32_Off strtab_off32; 493 Elf64_Off strtab_off64; /* save String Table offset for later use */ 494 495 memset(&elf, 0, sizeof(elf)); 496 elf.buf = buf; 497 elf.sz = sz; 498 499 /* Parse Header */ 500 if (parse_elf_header(&elf)) 501 goto bail; 502 503 if (elf.bits == 32) 504 { 505 Elf32_Shdr shdr; 506 for (i = 0; i < elf.hdr32.e_shnum; i++) 507 { 508 parse_elf_section(&elf, i, &shdr, NULL); 509 510 if (shdr.sh_type == SHT_STRTAB) 511 { 512 char strtsb_name[128]; 513 514 strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); 515 516 if (!(strcmp(strtsb_name, ".shstrtab"))) 517 { 518 /* log_msg("found section: %s\n", strtsb_name); */ 519 strtab_off32 = shdr.sh_offset; 520 break; 521 } 522 } 523 } 524 } 525 else /* if (elf.bits == 64) */ 526 { 527 Elf64_Shdr shdr; 528 for (i = 0; i < elf.hdr64.e_shnum; i++) 529 { 530 parse_elf_section(&elf, i, NULL, &shdr); 531 532 if (shdr.sh_type == SHT_STRTAB) 533 { 534 char strtsb_name[128]; 535 536 strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); 537 538 if (!(strcmp(strtsb_name, ".shstrtab"))) 539 { 540 /* log_msg("found section: %s\n", strtsb_name); */ 541 strtab_off64 = shdr.sh_offset; 542 break; 543 } 544 } 545 } 546 } 547 548 /* Parse all Symbol Tables */ 549 if (elf.bits == 32) 550 { 551 Elf32_Shdr shdr; 552 for (i = 0; i < elf.hdr32.e_shnum; i++) 553 { 554 parse_elf_section(&elf, i, &shdr, NULL); 555 556 if (shdr.sh_type == SHT_SYMTAB) 557 { 558 for (ofst = shdr.sh_offset; 559 ofst < shdr.sh_offset + shdr.sh_size; 560 ofst += shdr.sh_entsize) 561 { 562 Elf32_Sym sym; 563 564 parse_elf_symbol(&elf, ofst, &sym, NULL); 565 566 /* For all OBJECTS (data objects), extract the value from the 567 * proper data segment. 568 */ 569 /* if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) 570 log_msg("found data object %s\n", 571 parse_elf_string_table(&elf, 572 shdr.sh_link, 573 sym.st_name)); 574 */ 575 576 if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT 577 && sym.st_size == 4) 578 { 579 Elf32_Shdr dhdr; 580 int val = 0; 581 char section_name[128]; 582 583 parse_elf_section(&elf, sym.st_shndx, &dhdr, NULL); 584 585 /* For explanition - refer to _MSC_VER version of code */ 586 strcpy(section_name, (char *)(elf.buf + strtab_off32 + dhdr.sh_name)); 587 /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */ 588 589 if (strcmp(section_name, ".bss")) 590 { 591 if (sizeof(val) != sym.st_size) 592 { 593 /* The target value is declared as an int in 594 * asm_*_offsets.c, which is 4 bytes on all 595 * targets we currently use. Complain loudly if 596 * this is not true. 597 */ 598 log_msg("Symbol size is wrong\n"); 599 goto bail; 600 } 601 602 memcpy(&val, 603 elf.buf + dhdr.sh_offset + sym.st_value, 604 sym.st_size); 605 } 606 607 if (!elf.le_data) 608 { 609 log_msg("Big Endian data not supported yet!\n"); 610 goto bail; 611 } 612 613 switch (mode) 614 { 615 case OUTPUT_FMT_RVDS: 616 printf("%-40s EQU %5d\n", 617 parse_elf_string_table(&elf, 618 shdr.sh_link, 619 sym.st_name), 620 val); 621 break; 622 case OUTPUT_FMT_GAS: 623 printf(".equ %-40s, %5d\n", 624 parse_elf_string_table(&elf, 625 shdr.sh_link, 626 sym.st_name), 627 val); 628 break; 629 default: 630 printf("%s = %d\n", 631 parse_elf_string_table(&elf, 632 shdr.sh_link, 633 sym.st_name), 634 val); 635 } 636 } 637 } 638 } 639 } 640 } 641 else /* if (elf.bits == 64) */ 642 { 643 Elf64_Shdr shdr; 644 for (i = 0; i < elf.hdr64.e_shnum; i++) 645 { 646 parse_elf_section(&elf, i, NULL, &shdr); 647 648 if (shdr.sh_type == SHT_SYMTAB) 649 { 650 for (ofst = shdr.sh_offset; 651 ofst < shdr.sh_offset + shdr.sh_size; 652 ofst += shdr.sh_entsize) 653 { 654 Elf64_Sym sym; 655 656 parse_elf_symbol(&elf, ofst, NULL, &sym); 657 658 /* For all OBJECTS (data objects), extract the value from the 659 * proper data segment. 660 */ 661 /* if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) 662 log_msg("found data object %s\n", 663 parse_elf_string_table(&elf, 664 shdr.sh_link, 665 sym.st_name)); 666 */ 667 668 if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT 669 && sym.st_size == 4) 670 { 671 Elf64_Shdr dhdr; 672 int val = 0; 673 char section_name[128]; 674 675 parse_elf_section(&elf, sym.st_shndx, NULL, &dhdr); 676 677 /* For explanition - refer to _MSC_VER version of code */ 678 strcpy(section_name, (char *)(elf.buf + strtab_off64 + dhdr.sh_name)); 679 /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */ 680 681 if ((strcmp(section_name, ".bss"))) 682 { 683 if (sizeof(val) != sym.st_size) 684 { 685 /* The target value is declared as an int in 686 * asm_*_offsets.c, which is 4 bytes on all 687 * targets we currently use. Complain loudly if 688 * this is not true. 689 */ 690 log_msg("Symbol size is wrong\n"); 691 goto bail; 692 } 693 694 memcpy(&val, 695 elf.buf + dhdr.sh_offset + sym.st_value, 696 sym.st_size); 697 } 698 699 if (!elf.le_data) 700 { 701 log_msg("Big Endian data not supported yet!\n"); 702 goto bail; 703 } 704 705 switch (mode) 706 { 707 case OUTPUT_FMT_RVDS: 708 printf("%-40s EQU %5d\n", 709 parse_elf_string_table(&elf, 710 shdr.sh_link, 711 sym.st_name), 712 val); 713 break; 714 case OUTPUT_FMT_GAS: 715 printf(".equ %-40s, %5d\n", 716 parse_elf_string_table(&elf, 717 shdr.sh_link, 718 sym.st_name), 719 val); 720 break; 721 default: 722 printf("%s = %d\n", 723 parse_elf_string_table(&elf, 724 shdr.sh_link, 725 sym.st_name), 726 val); 727 } 728 } 729 } 730 } 731 } 732 } 733 734 if (mode == OUTPUT_FMT_RVDS) 735 printf(" END\n"); 736 737 return 0; 738 bail: 739 log_msg("Parse error: File does not appear to be valid ELF32 or ELF64\n"); 740 return 1; 741 } 742 743 int main(int argc, char **argv) 744 { 745 int fd; 746 output_fmt_t mode; 747 char *f; 748 struct stat stat_buf; 749 uint8_t *file_buf; 750 int res; 751 752 if (argc < 2 || argc > 3) 753 { 754 fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]); 755 fprintf(stderr, " <obj file>\tELF format object file to parse\n"); 756 fprintf(stderr, "Output Formats:\n"); 757 fprintf(stderr, " gas - compatible with GNU assembler\n"); 758 fprintf(stderr, " rvds - compatible with armasm\n"); 759 goto bail; 760 } 761 762 f = argv[2]; 763 764 if (!strcmp(argv[1], "rvds")) 765 mode = OUTPUT_FMT_RVDS; 766 else if (!strcmp(argv[1], "gas")) 767 mode = OUTPUT_FMT_GAS; 768 else 769 f = argv[1]; 770 771 772 fd = open(f, O_RDONLY); 773 774 if (fd < 0) 775 { 776 perror("Unable to open file"); 777 goto bail; 778 } 779 780 if (fstat(fd, &stat_buf)) 781 { 782 perror("stat"); 783 goto bail; 784 } 785 786 file_buf = malloc(stat_buf.st_size); 787 788 if (!file_buf) 789 { 790 perror("malloc"); 791 goto bail; 792 } 793 794 if (read(fd, file_buf, stat_buf.st_size) != stat_buf.st_size) 795 { 796 perror("read"); 797 goto bail; 798 } 799 800 if (close(fd)) 801 { 802 perror("close"); 803 goto bail; 804 } 805 806 res = parse_elf(file_buf, stat_buf.st_size, mode); 807 free(file_buf); 808 809 if (!res) 810 return EXIT_SUCCESS; 811 812 bail: 813 return EXIT_FAILURE; 814 } 815 #endif 816 #endif 817 818 819 #if defined(_MSC_VER) || defined(__MINGW32__) 820 /* See "Microsoft Portable Executable and Common Object File Format Specification" 821 for reference. 822 */ 823 #define get_le32(x) ((*(x)) | (*(x+1)) << 8 |(*(x+2)) << 16 | (*(x+3)) << 24 ) 824 #define get_le16(x) ((*(x)) | (*(x+1)) << 8) 825 826 int parse_coff(unsigned __int8 *buf, size_t sz) 827 { 828 unsigned int nsections, symtab_ptr, symtab_sz, strtab_ptr; 829 unsigned int sectionrawdata_ptr; 830 unsigned int i; 831 unsigned __int8 *ptr; 832 unsigned __int32 symoffset; 833 834 char **sectionlist; //this array holds all section names in their correct order. 835 //it is used to check if the symbol is in .bss or .data section. 836 837 nsections = get_le16(buf + 2); 838 symtab_ptr = get_le32(buf + 8); 839 symtab_sz = get_le32(buf + 12); 840 strtab_ptr = symtab_ptr + symtab_sz * 18; 841 842 if (nsections > 96) 843 { 844 log_msg("Too many sections\n"); 845 return 1; 846 } 847 848 sectionlist = malloc(nsections * sizeof(sectionlist)); 849 850 if (sectionlist == NULL) 851 { 852 log_msg("Allocating first level of section list failed\n"); 853 return 1; 854 } 855 856 //log_msg("COFF: Found %u symbols in %u sections.\n", symtab_sz, nsections); 857 858 /* 859 The size of optional header is always zero for an obj file. So, the section header 860 follows the file header immediately. 861 */ 862 863 ptr = buf + 20; //section header 864 865 for (i = 0; i < nsections; i++) 866 { 867 char sectionname[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 868 strncpy(sectionname, ptr, 8); 869 //log_msg("COFF: Parsing section %s\n",sectionname); 870 871 sectionlist[i] = malloc(strlen(sectionname) + 1); 872 873 if (sectionlist[i] == NULL) 874 { 875 log_msg("Allocating storage for %s failed\n", sectionname); 876 goto bail; 877 } 878 strcpy(sectionlist[i], sectionname); 879 880 if (!strcmp(sectionname, ".data")) sectionrawdata_ptr = get_le32(ptr + 20); 881 882 ptr += 40; 883 } 884 885 //log_msg("COFF: Symbol table at offset %u\n", symtab_ptr); 886 //log_msg("COFF: raw data pointer ofset for section .data is %u\n", sectionrawdata_ptr); 887 888 /* The compiler puts the data with non-zero offset in .data section, but puts the data with 889 zero offset in .bss section. So, if the data in in .bss section, set offset=0. 890 Note from Wiki: In an object module compiled from C, the bss section contains 891 the local variables (but not functions) that were declared with the static keyword, 892 except for those with non-zero initial values. (In C, static variables are initialized 893 to zero by default.) It also contains the non-local (both extern and static) variables 894 that are also initialized to zero (either explicitly or by default). 895 */ 896 //move to symbol table 897 /* COFF symbol table: 898 offset field 899 0 Name(*) 900 8 Value 901 12 SectionNumber 902 14 Type 903 16 StorageClass 904 17 NumberOfAuxSymbols 905 */ 906 ptr = buf + symtab_ptr; 907 908 for (i = 0; i < symtab_sz; i++) 909 { 910 __int16 section = get_le16(ptr + 12); //section number 911 912 if (section > 0 && ptr[16] == 2) 913 { 914 //if(section > 0 && ptr[16] == 3 && get_le32(ptr+8)) { 915 916 if (get_le32(ptr)) 917 { 918 char name[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 919 strncpy(name, ptr, 8); 920 //log_msg("COFF: Parsing symbol %s\n",name); 921 /* The 64bit Windows compiler doesn't prefix with an _. 922 * Check what's there, and bump if necessary 923 */ 924 if (name[0] == '_') 925 printf("%-40s EQU ", name + 1); 926 else 927 printf("%-40s EQU ", name); 928 } 929 else 930 { 931 //log_msg("COFF: Parsing symbol %s\n", 932 // buf + strtab_ptr + get_le32(ptr+4)); 933 if ((buf + strtab_ptr + get_le32(ptr + 4))[0] == '_') 934 printf("%-40s EQU ", 935 buf + strtab_ptr + get_le32(ptr + 4) + 1); 936 else 937 printf("%-40s EQU ", buf + strtab_ptr + get_le32(ptr + 4)); 938 } 939 940 if (!(strcmp(sectionlist[section-1], ".bss"))) 941 { 942 symoffset = 0; 943 } 944 else 945 { 946 symoffset = get_le32(buf + sectionrawdata_ptr + get_le32(ptr + 8)); 947 } 948 949 //log_msg(" Section: %d\n",section); 950 //log_msg(" Class: %d\n",ptr[16]); 951 //log_msg(" Address: %u\n",get_le32(ptr+8)); 952 //log_msg(" Offset: %u\n", symoffset); 953 954 printf("%5d\n", symoffset); 955 } 956 957 ptr += 18; 958 } 959 960 printf(" END\n"); 961 962 for (i = 0; i < nsections; i++) 963 { 964 free(sectionlist[i]); 965 } 966 967 free(sectionlist); 968 969 return 0; 970 bail: 971 972 for (i = 0; i < nsections; i++) 973 { 974 free(sectionlist[i]); 975 } 976 977 free(sectionlist); 978 979 return 1; 980 } 981 982 int main(int argc, char **argv) 983 { 984 int fd; 985 output_fmt_t mode; 986 const char *f; 987 struct _stat stat_buf; 988 unsigned __int8 *file_buf; 989 int res; 990 991 if (argc < 2 || argc > 3) 992 { 993 fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]); 994 fprintf(stderr, " <obj file>\tELF format object file to parse\n"); 995 fprintf(stderr, "Output Formats:\n"); 996 fprintf(stderr, " gas - compatible with GNU assembler\n"); 997 fprintf(stderr, " rvds - compatible with armasm\n"); 998 goto bail; 999 } 1000 1001 f = argv[2]; 1002 1003 if (!strcmp(argv[1], "rvds")) 1004 mode = OUTPUT_FMT_RVDS; 1005 else if (!strcmp(argv[1], "gas")) 1006 mode = OUTPUT_FMT_GAS; 1007 else 1008 f = argv[1]; 1009 1010 fd = _sopen(f, _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE); 1011 1012 if (_fstat(fd, &stat_buf)) 1013 { 1014 perror("stat"); 1015 goto bail; 1016 } 1017 1018 file_buf = malloc(stat_buf.st_size); 1019 1020 if (!file_buf) 1021 { 1022 perror("malloc"); 1023 goto bail; 1024 } 1025 1026 if (_read(fd, file_buf, stat_buf.st_size) != stat_buf.st_size) 1027 { 1028 perror("read"); 1029 goto bail; 1030 } 1031 1032 if (_close(fd)) 1033 { 1034 perror("close"); 1035 goto bail; 1036 } 1037 1038 res = parse_coff(file_buf, stat_buf.st_size); 1039 1040 free(file_buf); 1041 1042 if (!res) 1043 return EXIT_SUCCESS; 1044 1045 bail: 1046 return EXIT_FAILURE; 1047 } 1048 #endif 1049