2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
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.
15 #include "vpx_config.h"
20 #include "vpx/vpx_integer.h"
27 #include <sys/types.h>
39 int log_msg(const char *fmt
, ...)
44 res
= vfprintf(stderr
, fmt
, ap
);
49 #if defined(__GNUC__) && __GNUC__
53 #include <mach-o/loader.h>
54 #include <mach-o/nlist.h>
56 int parse_macho(uint8_t *base_buf
, size_t sz
)
59 struct mach_header header
;
60 uint8_t *buf
= base_buf
;
61 int base_data_section
= 0;
63 memcpy(&header
, buf
, sizeof(struct mach_header
));
64 buf
+= sizeof(struct mach_header
);
66 if (header
.magic
!= MH_MAGIC
)
68 log_msg("Bad magic number for object file. 0x%x expected, 0x%x found.\n",
69 header
.magic
, MH_MAGIC
);
73 if (header
.cputype
!= CPU_TYPE_ARM
)
75 log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_ARM.\n");
79 if (header
.filetype
!= MH_OBJECT
)
81 log_msg("Bad filetype for object file. Currently only tested for MH_OBJECT.\n");
85 for (i
= 0; i
< header
.ncmds
; i
++)
87 struct load_command lc
;
88 struct symtab_command sc
;
89 struct segment_command seg_c
;
91 memcpy(&lc
, buf
, sizeof(struct load_command
));
93 if (lc
.cmd
== LC_SEGMENT
)
95 uint8_t *seg_buf
= buf
;
98 memcpy(&seg_c
, buf
, sizeof(struct segment_command
));
100 seg_buf
+= sizeof(struct segment_command
);
102 for (j
= 0; j
< seg_c
.nsects
; j
++)
104 memcpy(&s
, seg_buf
+ (j
* sizeof(struct section
)), sizeof(struct section
));
106 // Need to get this offset which is the start of the symbol table
107 // before matching the strings up with symbols.
108 base_data_section
= s
.offset
;
111 else if (lc
.cmd
== LC_SYMTAB
)
113 uint8_t *sym_buf
= base_buf
;
114 uint8_t *str_buf
= base_buf
;
116 if (base_data_section
!= 0)
118 memcpy(&sc
, buf
, sizeof(struct symtab_command
));
120 if (sc
.cmdsize
!= sizeof(struct symtab_command
))
121 log_msg("Can't find symbol table!\n");
123 sym_buf
+= sc
.symoff
;
124 str_buf
+= sc
.stroff
;
126 for (j
= 0; j
< sc
.nsyms
; j
++)
131 memcpy(&nl
, sym_buf
+ (j
* sizeof(struct nlist
)), sizeof(struct nlist
));
133 val
= *((int *)(base_buf
+ base_data_section
+ nl
.n_value
));
135 // Location of string is cacluated each time from the
136 // start of the string buffer. On darwin the symbols
137 // are prefixed by "_". On other platforms it is not
138 // so it needs to be removed. That is the reason for
140 printf("%-40s EQU %5d\n", str_buf
+ nl
.n_un
.n_strx
+ 1, val
);
154 int main(int argc
, char **argv
)
158 struct stat stat_buf
;
162 if (argc
< 2 || argc
> 3)
164 fprintf(stderr
, "Usage: %s [output format] <obj file>\n\n", argv
[0]);
165 fprintf(stderr
, " <obj file>\tMachO format object file to parse\n");
166 fprintf(stderr
, "Output Formats:\n");
167 fprintf(stderr
, " gas - compatible with GNU assembler\n");
168 fprintf(stderr
, " rvds - compatible with armasm\n");
174 if (!((!strcmp(argv
[1], "rvds")) || (!strcmp(argv
[1], "gas"))))
177 fd
= open(f
, O_RDONLY
);
181 perror("Unable to open file");
185 if (fstat(fd
, &stat_buf
))
191 file_buf
= malloc(stat_buf
.st_size
);
199 if (read(fd
, file_buf
, stat_buf
.st_size
) != stat_buf
.st_size
)
211 res
= parse_macho(file_buf
, stat_buf
.st_size
);
224 #define COPY_STRUCT(dst, buf, ofst, sz) do {\
225 if(ofst + sizeof((*(dst))) > sz) goto bail;\
226 memcpy(dst, buf+ofst, sizeof((*(dst))));\
229 #define ENDIAN_ASSIGN(val, memb) do {\
230 if(!elf->le_data) {log_msg("Big Endian data not supported yet!\n");goto bail;}\
234 #define ENDIAN_ASSIGN_IN_PLACE(memb) do {\
235 ENDIAN_ASSIGN(memb, memb);\
240 uint8_t *buf
; /* Buffer containing ELF data */
241 size_t sz
; /* Buffer size */
242 int le_data
; /* Data is little-endian */
246 int parse_elf32_header(elf_obj_t
*elf
)
249 /* Verify ELF32 header */
250 COPY_STRUCT(&elf
->hdr
, elf
->buf
, 0, elf
->sz
);
251 res
= elf
->hdr
.e_ident
[EI_MAG0
] == ELFMAG0
;
252 res
&= elf
->hdr
.e_ident
[EI_MAG1
] == ELFMAG1
;
253 res
&= elf
->hdr
.e_ident
[EI_MAG2
] == ELFMAG2
;
254 res
&= elf
->hdr
.e_ident
[EI_MAG3
] == ELFMAG3
;
255 res
&= elf
->hdr
.e_ident
[EI_CLASS
] == ELFCLASS32
;
256 res
&= elf
->hdr
.e_ident
[EI_DATA
] == ELFDATA2LSB
257 || elf
->hdr
.e_ident
[EI_DATA
] == ELFDATA2MSB
;
261 elf
->le_data
= elf
->hdr
.e_ident
[EI_DATA
] == ELFDATA2LSB
;
263 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_type
);
264 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_machine
);
265 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_version
);
266 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_entry
);
267 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_phoff
);
268 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_shoff
);
269 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_flags
);
270 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_ehsize
);
271 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_phentsize
);
272 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_phnum
);
273 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_shentsize
);
274 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_shnum
);
275 ENDIAN_ASSIGN_IN_PLACE(elf
->hdr
.e_shstrndx
);
281 int parse_elf32_section(elf_obj_t
*elf
, int idx
, Elf32_Shdr
*hdr
)
283 if (idx
>= elf
->hdr
.e_shnum
)
286 COPY_STRUCT(hdr
, elf
->buf
, elf
->hdr
.e_shoff
+ idx
* elf
->hdr
.e_shentsize
,
288 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_name
);
289 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_type
);
290 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_flags
);
291 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_addr
);
292 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_offset
);
293 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_size
);
294 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_link
);
295 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_info
);
296 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_addralign
);
297 ENDIAN_ASSIGN_IN_PLACE(hdr
->sh_entsize
);
303 char *parse_elf32_string_table(elf_obj_t
*elf
, int s_idx
, int idx
)
307 if (parse_elf32_section(elf
, s_idx
, &shdr
))
309 log_msg("Failed to parse ELF string table: section %d, index %d\n",
314 return (char *)(elf
->buf
+ shdr
.sh_offset
+ idx
);
317 int parse_elf32_symbol(elf_obj_t
*elf
, unsigned int ofst
, Elf32_Sym
*sym
)
319 COPY_STRUCT(sym
, elf
->buf
, ofst
, elf
->sz
);
320 ENDIAN_ASSIGN_IN_PLACE(sym
->st_name
);
321 ENDIAN_ASSIGN_IN_PLACE(sym
->st_value
);
322 ENDIAN_ASSIGN_IN_PLACE(sym
->st_size
);
323 ENDIAN_ASSIGN_IN_PLACE(sym
->st_info
);
324 ENDIAN_ASSIGN_IN_PLACE(sym
->st_other
);
325 ENDIAN_ASSIGN_IN_PLACE(sym
->st_shndx
);
331 int parse_elf32(uint8_t *buf
, size_t sz
, output_fmt_t mode
)
337 Elf32_Off strtab_off
; /* save String Table offset for later use */
339 memset(&elf
, 0, sizeof(elf
));
344 if (parse_elf32_header(&elf
))
346 log_msg("Parse error: File does not appear to be valid ELF32\n");
350 for (i
= 0; i
< elf
.hdr
.e_shnum
; i
++)
352 parse_elf32_section(&elf
, i
, &shdr
);
354 if (shdr
.sh_type
== SHT_STRTAB
)
356 char strtsb_name
[128];
358 strcpy(strtsb_name
, (char *)(elf
.buf
+ shdr
.sh_offset
+ shdr
.sh_name
));
360 if (!(strcmp(strtsb_name
, ".shstrtab")))
362 log_msg("found section: %s\n", strtsb_name
);
363 strtab_off
= shdr
.sh_offset
;
369 /* Parse all Symbol Tables */
370 for (i
= 0; i
< elf
.hdr
.e_shnum
; i
++)
373 parse_elf32_section(&elf
, i
, &shdr
);
375 if (shdr
.sh_type
== SHT_SYMTAB
)
377 for (ofst
= shdr
.sh_offset
;
378 ofst
< shdr
.sh_offset
+ shdr
.sh_size
;
379 ofst
+= shdr
.sh_entsize
)
383 parse_elf32_symbol(&elf
, ofst
, &sym
);
385 /* For all OBJECTS (data objects), extract the value from the
386 * proper data segment.
388 if (ELF32_ST_TYPE(sym
.st_info
) == STT_OBJECT
&& sym
.st_name
)
389 log_msg("found data object %s\n",
390 parse_elf32_string_table(&elf
,
394 if (ELF32_ST_TYPE(sym
.st_info
) == STT_OBJECT
399 char section_name
[128];
401 parse_elf32_section(&elf
, sym
.st_shndx
, &dhdr
);
403 /* For explanition - refer to _MSC_VER version of code */
404 strcpy(section_name
, (char *)(elf
.buf
+ strtab_off
+ dhdr
.sh_name
));
405 log_msg("Section_name: %s, Section_type: %d\n", section_name
, dhdr
.sh_type
);
407 if (!(strcmp(section_name
, ".bss")))
414 elf
.buf
+ dhdr
.sh_offset
+ sym
.st_value
,
420 log_msg("Big Endian data not supported yet!\n");
426 case OUTPUT_FMT_RVDS
:
427 printf("%-40s EQU %5d\n",
428 parse_elf32_string_table(&elf
,
434 printf(".equ %-40s, %5d\n",
435 parse_elf32_string_table(&elf
,
442 parse_elf32_string_table(&elf
,
452 if (mode
== OUTPUT_FMT_RVDS
)
457 log_msg("Parse error: File does not appear to be valid ELF32\n");
461 int main(int argc
, char **argv
)
466 struct stat stat_buf
;
470 if (argc
< 2 || argc
> 3)
472 fprintf(stderr
, "Usage: %s [output format] <obj file>\n\n", argv
[0]);
473 fprintf(stderr
, " <obj file>\tELF format object file to parse\n");
474 fprintf(stderr
, "Output Formats:\n");
475 fprintf(stderr
, " gas - compatible with GNU assembler\n");
476 fprintf(stderr
, " rvds - compatible with armasm\n");
482 if (!strcmp(argv
[1], "rvds"))
483 mode
= OUTPUT_FMT_RVDS
;
484 else if (!strcmp(argv
[1], "gas"))
485 mode
= OUTPUT_FMT_GAS
;
490 fd
= open(f
, O_RDONLY
);
494 perror("Unable to open file");
498 if (fstat(fd
, &stat_buf
))
504 file_buf
= malloc(stat_buf
.st_size
);
512 if (read(fd
, file_buf
, stat_buf
.st_size
) != stat_buf
.st_size
)
524 res
= parse_elf32(file_buf
, stat_buf
.st_size
, mode
);
525 //res = parse_coff(file_buf, stat_buf.st_size);
538 #if defined(_MSC_VER)
539 /* See "Microsoft Portable Executable and Common Object File Format Specification"
542 #define get_le32(x) ((*(x)) | (*(x+1)) << 8 |(*(x+2)) << 16 | (*(x+3)) << 24 )
543 #define get_le16(x) ((*(x)) | (*(x+1)) << 8)
545 int parse_coff(unsigned __int8
*buf
, size_t sz
)
547 unsigned int nsections
, symtab_ptr
, symtab_sz
, strtab_ptr
;
548 unsigned int sectionrawdata_ptr
;
550 unsigned __int8
*ptr
;
551 unsigned __int32 symoffset
;
554 char **sectionlist
; //this array holds all section names in their correct order.
555 //it is used to check if the symbol is in .bss or .data section.
557 nsections
= get_le16(buf
+ 2);
558 symtab_ptr
= get_le32(buf
+ 8);
559 symtab_sz
= get_le32(buf
+ 12);
560 strtab_ptr
= symtab_ptr
+ symtab_sz
* 18;
565 sectionlist
= malloc(nsections
* sizeof * sectionlist
);
567 //log_msg("COFF: Found %u symbols in %u sections.\n", symtab_sz, nsections);
570 The size of optional header is always zero for an obj file. So, the section header
571 follows the file header immediately.
574 ptr
= buf
+ 20; //section header
576 for (i
= 0; i
< nsections
; i
++)
578 char sectionname
[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
579 strncpy(sectionname
, ptr
, 8);
580 //log_msg("COFF: Parsing section %s\n",sectionname);
582 sectionlist
[i
] = malloc(strlen(sectionname
) + 1);
583 strcpy(sectionlist
[i
], sectionname
);
585 if (!strcmp(sectionname
, ".data")) sectionrawdata_ptr
= get_le32(ptr
+ 20);
590 //log_msg("COFF: Symbol table at offset %u\n", symtab_ptr);
591 //log_msg("COFF: raw data pointer ofset for section .data is %u\n", sectionrawdata_ptr);
593 fp
= fopen("vpx_asm_offsets.asm", "w");
601 /* The compiler puts the data with non-zero offset in .data section, but puts the data with
602 zero offset in .bss section. So, if the data in in .bss section, set offset=0.
603 Note from Wiki: In an object module compiled from C, the bss section contains
604 the local variables (but not functions) that were declared with the static keyword,
605 except for those with non-zero initial values. (In C, static variables are initialized
606 to zero by default.) It also contains the non-local (both extern and static) variables
607 that are also initialized to zero (either explicitly or by default).
609 //move to symbol table
610 /* COFF symbol table:
617 17 NumberOfAuxSymbols
619 ptr
= buf
+ symtab_ptr
;
621 for (i
= 0; i
< symtab_sz
; i
++)
623 __int16 section
= get_le16(ptr
+ 12); //section number
625 if (section
> 0 && ptr
[16] == 2)
627 //if(section > 0 && ptr[16] == 3 && get_le32(ptr+8)) {
631 char name
[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
632 strncpy(name
, ptr
, 8);
633 //log_msg("COFF: Parsing symbol %s\n",name);
634 fprintf(fp
, "%-40s EQU ", name
);
638 //log_msg("COFF: Parsing symbol %s\n",
639 // buf + strtab_ptr + get_le32(ptr+4));
640 fprintf(fp
, "%-40s EQU ", buf
+ strtab_ptr
+ get_le32(ptr
+ 4));
643 if (!(strcmp(sectionlist
[section
-1], ".bss")))
649 symoffset
= get_le32(buf
+ sectionrawdata_ptr
+ get_le32(ptr
+ 8));
652 //log_msg(" Section: %d\n",section);
653 //log_msg(" Class: %d\n",ptr[16]);
654 //log_msg(" Address: %u\n",get_le32(ptr+8));
655 //log_msg(" Offset: %u\n", symoffset);
657 fprintf(fp
, "%5d\n", symoffset
);
663 fprintf(fp
, " END\n");
666 for (i
= 0; i
< nsections
; i
++)
668 free(sectionlist
[i
]);
676 for (i
= 0; i
< nsections
; i
++)
678 free(sectionlist
[i
]);
686 int main(int argc
, char **argv
)
691 struct _stat stat_buf
;
692 unsigned __int8
*file_buf
;
695 if (argc
< 2 || argc
> 3)
697 fprintf(stderr
, "Usage: %s [output format] <obj file>\n\n", argv
[0]);
698 fprintf(stderr
, " <obj file>\tELF format object file to parse\n");
699 fprintf(stderr
, "Output Formats:\n");
700 fprintf(stderr
, " gas - compatible with GNU assembler\n");
701 fprintf(stderr
, " rvds - compatible with armasm\n");
707 if (!strcmp(argv
[1], "rvds"))
708 mode
= OUTPUT_FMT_RVDS
;
709 else if (!strcmp(argv
[1], "gas"))
710 mode
= OUTPUT_FMT_GAS
;
714 if (_sopen_s(&fd
, f
, _O_BINARY
, _SH_DENYNO
, _S_IREAD
| _S_IWRITE
))
716 perror("Unable to open file");
720 if (_fstat(fd
, &stat_buf
))
726 file_buf
= malloc(stat_buf
.st_size
);
734 if (_read(fd
, file_buf
, stat_buf
.st_size
) != stat_buf
.st_size
)
746 res
= parse_coff(file_buf
, stat_buf
.st_size
);