diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2007-12-06 14:21:47 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2007-12-06 15:06:50 +0000 |
commit | f0a0555723491e4246ec07136f443daea2b55bba (patch) | |
tree | 1443a0e07dbc0bb35eb81e92647bfc8f8e949547 /src/minibfd | |
parent | 6934720f91c82666e6437792ffb34eaa08ea65da (diff) |
Eliminate the strcmp entirely for field lookup.
Diffstat (limited to 'src/minibfd')
-rw-r--r-- | src/minibfd/binparser.c | 65 | ||||
-rw-r--r-- | src/minibfd/binparser.h | 43 | ||||
-rw-r--r-- | src/minibfd/elfparser.c | 219 |
3 files changed, 151 insertions, 176 deletions
diff --git a/src/minibfd/binparser.c b/src/minibfd/binparser.c index 352a0b6..44bf0a6 100644 --- a/src/minibfd/binparser.c +++ b/src/minibfd/binparser.c @@ -26,7 +26,6 @@ typedef struct _field Field; struct _field { - char name[BIN_MAX_NAME]; guint offset; /* from beginning of struct */ guint width; BinType type; @@ -72,21 +71,8 @@ bin_parser_get_length (BinParser *parser) return parser->length; } -static guint64 -align (guint64 offset, int alignment) -{ - /* Note that we can speed this up by assuming alignment' - * is a power of two, since - * - * offset % alignment == offset & (alignemnt - 1) - * - */ - - if (offset % alignment != 0) - offset += (alignment - (offset % alignment)); - - return offset; -} +#define align(offset__, alignment__) \ + ((offset__ + alignment__ - 1) &~ (alignment__ - 1)) static int get_align (const BinField *field) @@ -97,22 +83,15 @@ get_align (const BinField *field) return field->n_bytes; } -static int -field_strcmp (const void *A, const void *B) -{ - const Field *a = A, *b = B; - return strcmp (a->name, b->name); -} - BinRecord * bin_parser_create_record (BinParser *parser, const BinField *fields) { BinRecord *record; - int i, n_fields; + guint i, n_fields; guint offset; n_fields = 0; - while (fields[n_fields].name[0] != '\0') + while (fields[n_fields].index != -1) n_fields++; record = g_malloc (sizeof (BinRecord) + n_fields * sizeof (Field)); @@ -121,23 +100,19 @@ bin_parser_create_record (BinParser *parser, const BinField *fields) record->n_fields = n_fields; for (i = 0; i < n_fields; ++i) { const BinField *bin_field = &fields[i]; - Field *field = &record->fields[i]; + Field *field; offset = align (offset, get_align (bin_field)); - strncpy (field->name, bin_field->name, BIN_MAX_NAME - 1); + field = &record->fields[bin_field->index]; field->offset = offset; field->type = bin_field->type; field->width = bin_field->n_bytes; - offset += record->fields[i].width; + offset += field->width; } - record->size = align (record->fields[n_fields-1].offset + - record->fields[n_fields-1].width, - record->fields[0].width); - - qsort (record->fields, n_fields, sizeof (Field), field_strcmp); + record->size = align (offset, get_align (fields)); record->next = parser->records; parser->records = record; @@ -295,35 +270,15 @@ bin_parser_get_string (BinParser *parser) } -static const Field * -get_field (BinRecord *format, const gchar *name) -{ - guint first = 0, last = format->n_fields; - while (last - first > 1) { - gint cmp; - guint mid = (first + last) / 2; - cmp = strcmp (name, format->fields[mid].name); - if (cmp < 0) - last = mid; - else if (cmp > 0) - first = mid; - else - return &format->fields[mid]; - - } - return &format->fields[first]; -} - guint64 bin_parser_get_uint_field (BinParser *parser, BinRecord *record, - const char *name) + int field_ident) { - const Field *field = get_field (record, name); + const Field *field = &record->fields[field_ident]; const guchar *pos; pos = parser->data + parser->offset + field->offset; - if (pos > parser->data + parser->length) { /* FIXME: generate error */ return 0; diff --git a/src/minibfd/binparser.h b/src/minibfd/binparser.h index 68c32da..ea84afe 100644 --- a/src/minibfd/binparser.h +++ b/src/minibfd/binparser.h @@ -58,8 +58,6 @@ typedef struct _bin_field BinField; * */ -#define BIN_MAX_NAME 52 - typedef enum { BIN_LITTLE_ENDIAN, BIN_BIG_ENDIAN, @@ -73,7 +71,7 @@ typedef enum { } BinType; struct _bin_field { - const char name[BIN_MAX_NAME]; + short index; char type; char n_bytes; /* number of bytes in the type */ }; @@ -105,12 +103,49 @@ gboolean bin_parser_error (BinParser *parser); void bin_parser_clear_error (BinParser *parser); const gchar * bin_parser_get_error_msg (BinParser *parser); +/* field idents */ +enum { + e_ident = 0, + e_type, + e_machine, + e_version, + e_entry, + e_phoff, + e_shoff, + e_flags, + e_ehsize, + e_phentsize, + e_phnum, + e_shentsize, + e_shnum, + e_shstrndx +}; +enum { + sh_name = 0, + sh_type, + sh_flags, + sh_addr, + sh_offset, + sh_size, + sh_link, + sh_info, + sh_addralign, + sh_entsize +}; +enum { + st_name = 0, + st_info, + st_other, + st_shndx, + st_value, + st_size +}; BinRecord * bin_parser_create_record (BinParser *parser, const BinField *fields); gsize bin_record_get_size (BinRecord *record); guint64 bin_parser_get_uint_field (BinParser *parser, BinRecord *record, - const char *field); + int field_ident); /* Move current offset */ gsize bin_parser_get_offset (BinParser *parser); diff --git a/src/minibfd/elfparser.c b/src/minibfd/elfparser.c index 6b174e2..2ae1660 100644 --- a/src/minibfd/elfparser.c +++ b/src/minibfd/elfparser.c @@ -69,14 +69,14 @@ get_formats (gboolean is_64, static const char * get_string_indirect (BinParser *parser, BinRecord *record, - const char *name, + int field_ident, gsize str_table) { const char *result = NULL; gsize index; bin_parser_save (parser); { - index = bin_parser_get_uint_field (parser, record, name); + index = bin_parser_get_uint_field (parser, record, field_ident); bin_parser_set_offset (parser, str_table + index); @@ -94,20 +94,20 @@ section_init (Section *section, { guint64 flags; - section->name = get_string_indirect (parser, record, "sh_name", name_table); - section->size = bin_parser_get_uint_field (parser, record, "sh_size"); - section->offset = bin_parser_get_uint_field (parser, record, "sh_offset"); + section->name = get_string_indirect (parser, record, sh_name, name_table); + section->size = bin_parser_get_uint_field (parser, record, sh_size); + section->offset = bin_parser_get_uint_field (parser, record, sh_offset); - flags = bin_parser_get_uint_field (parser, record, "sh_flags"); + flags = bin_parser_get_uint_field (parser, record, sh_flags); section->allocated = !!(flags & SHF_ALLOC); if (section->allocated) { section->load_address = bin_parser_get_uint_field ( - parser, record, "sh_addr"); + parser, record, sh_addr); } else section->load_address = 0; - section->type = bin_parser_get_uint_field (parser, record, "sh_type"); + section->type = bin_parser_get_uint_field (parser, record, sh_type); } static const Section * @@ -154,9 +154,7 @@ elf_parser_new_from_data (const guchar *data, gsize length) header = bin_parser_create_record (&bin_parser, elf_header); bin_parser_set_offset (&bin_parser, 0); - n_sections = bin_parser_get_uint_field (&bin_parser, - header, - "e_shnum"); + n_sections = bin_parser_get_uint_field (&bin_parser, header, e_shnum); parser = g_malloc (sizeof (ElfParser) + sizeof (Section) * n_sections); parser->parser = bin_parser; @@ -170,10 +168,10 @@ elf_parser_new_from_data (const guchar *data, gsize length) /* Read section headers */ section_names_idx = bin_parser_get_uint_field (&bin_parser, header, - "e_shstrndx"); + e_shstrndx); section_headers = bin_parser_get_uint_field (&bin_parser, header, - "e_shoff"); + e_shoff); bin_parser_set_offset (&bin_parser, section_headers); bin_parser_save (&bin_parser); { @@ -183,7 +181,7 @@ elf_parser_new_from_data (const guchar *data, gsize length) section_names = bin_parser_get_uint_field (&bin_parser, parser->shn_entry, - "sh_offset"); + sh_offset); } bin_parser_restore (&bin_parser); parser->n_sections = n_sections; @@ -357,9 +355,9 @@ read_table (ElfParser *parser, gulong offset; info = bin_parser_get_uint_field ( - &parser->parser, parser->sym_format, "st_info"); + &parser->parser, parser->sym_format, st_info); addr = bin_parser_get_uint_field ( - &parser->parser, parser->sym_format, "st_value"); + &parser->parser, parser->sym_format, st_value); offset = bin_parser_get_offset (&parser->parser); if (addr != 0 && @@ -370,9 +368,7 @@ read_table (ElfParser *parser, { parser->symbols[n_functions].address = addr; parser->symbols[n_functions].offset = offset; - n_functions++; - } bin_parser_seek_record (&parser->parser, parser->sym_format, 1); @@ -388,21 +384,21 @@ read_table (ElfParser *parser, static void read_symbols (ElfParser *parser) { - const Section *symtab = find_section (parser, ".symtab", SHT_SYMTAB); - const Section *strtab = find_section (parser, ".strtab", SHT_STRTAB); - const Section *dynsym = find_section (parser, ".dynsym", SHT_DYNSYM); - const Section *dynstr = find_section (parser, ".dynstr", SHT_STRTAB); + const Section *symtab, *strtab; - if (symtab && strtab) { - read_table (parser, symtab, strtab); - } - else if (dynsym && dynstr) { - read_table (parser, dynsym, dynstr); - } else { - /* To make sure parser->symbols is non-NULL */ - parser->n_symbols = 0; - parser->symbols = g_new (ElfSym, 1); - } + symtab = find_section (parser, ".symtab", SHT_SYMTAB); + strtab = find_section (parser, ".strtab", SHT_STRTAB); + if (symtab != NULL && strtab != NULL) + return read_table (parser, symtab, strtab); + + symtab = find_section (parser, ".dynsym", SHT_SYMTAB); + strtab = find_section (parser, ".dynstr", SHT_STRTAB); + if (symtab != NULL && strtab != NULL) + return read_table (parser, symtab, strtab); + + /* To make sure parser->symbols is non-NULL */ + parser->n_symbols = 0; + parser->symbols = g_new (ElfSym, 1); } static ElfSym * @@ -410,11 +406,11 @@ do_lookup (ElfSym *symbols, gulong address, int first, int last) { do { if (address >= symbols[last].address) { - return &(symbols[last]); + return &symbols[last]; } else if (last - first < 3) { while (last >= first) { if (address >= symbols[last].address) - return &(symbols[last]); + return &symbols[last]; last--; } @@ -432,8 +428,7 @@ do_lookup (ElfSym *symbols, gulong address, int first, int last) /* Address should be given in 'offset into text segment' */ const ElfSym * -elf_parser_lookup_symbol (ElfParser *parser, - gulong address) +elf_parser_lookup_symbol (ElfParser *parser, gulong address) { const ElfSym *result; @@ -448,15 +443,13 @@ elf_parser_lookup_symbol (ElfParser *parser, address += parser->text_section->load_address; result = do_lookup (parser->symbols, address, 0, parser->n_symbols - 1); - if (result) { gulong size; bin_parser_set_offset (&parser->parser, result->offset); size = bin_parser_get_uint_field ( - &parser->parser, parser->sym_format, "st_size"); - + &parser->parser, parser->sym_format, st_size); if (size > 0 && result->address + size <= address) result = NULL; } @@ -518,7 +511,7 @@ elf_parser_get_sym_name (ElfParser *parser, const ElfSym *sym) bin_parser_set_offset (&parser->parser, sym->offset); result = get_string_indirect (&parser->parser, parser->sym_format, - "st_name", parser->sym_strings); + st_name, parser->sym_strings); return result; } @@ -539,22 +532,17 @@ parse_elf_signature (const guchar *data, gboolean *is_be) { /* FIXME: this function should be able to return an error */ - if (length < EI_NIDENT) - { + if (length < EI_NIDENT) { /* FIXME set error */ return FALSE; } - if (data[EI_CLASS] != ELFCLASS32 && - data[EI_CLASS] != ELFCLASS64) - { + if (data[EI_CLASS] != ELFCLASS32 && data[EI_CLASS] != ELFCLASS64) { /* FIXME set error */ return FALSE; } - if (data[EI_DATA] != ELFDATA2LSB && - data[EI_DATA] != ELFDATA2MSB) - { + if (data[EI_DATA] != ELFDATA2LSB && data[EI_DATA] != ELFDATA2MSB) { /* FIXME set error */ return FALSE; } @@ -575,87 +563,84 @@ get_formats (gboolean is_64, const BinField **sym_format) { static const BinField elf64_header[] = { - { "e_ident", BIN_UNINTERPRETED, EI_NIDENT }, - { "e_type", BIN_UINT, 2 }, - { "e_machine", BIN_UINT, 2 }, - { "e_version", BIN_UINT, 4 }, - { "e_entry", BIN_UINT, 8 }, - { "e_phoff", BIN_UINT, 8 }, - { "e_shoff", BIN_UINT, 8 }, - { "e_flags", BIN_UINT, 4 }, - { "e_ehsize", BIN_UINT, 2 }, - { "e_phentsize", BIN_UINT, 2 }, - { "e_phnum", BIN_UINT, 2 }, - { "e_shentsize", BIN_UINT, 2 }, - { "e_shnum", BIN_UINT, 2 }, - { "e_shstrndx", BIN_UINT, 2 }, - { "" }, + { e_ident, BIN_UNINTERPRETED, EI_NIDENT }, + { e_type, BIN_UINT, 2 }, + { e_machine, BIN_UINT, 2 }, + { e_version, BIN_UINT, 4 }, + { e_entry, BIN_UINT, 8 }, + { e_phoff, BIN_UINT, 8 }, + { e_shoff, BIN_UINT, 8 }, + { e_flags, BIN_UINT, 4 }, + { e_ehsize, BIN_UINT, 2 }, + { e_phentsize, BIN_UINT, 2 }, + { e_phnum, BIN_UINT, 2 }, + { e_shentsize, BIN_UINT, 2 }, + { e_shnum, BIN_UINT, 2 }, + { e_shstrndx, BIN_UINT, 2 }, + { -1 }, }; - static const BinField elf32_header[] = { - { "e_ident", BIN_UNINTERPRETED, EI_NIDENT }, - { "e_type", BIN_UINT, 2 }, - { "e_machine", BIN_UINT, 2 }, - { "e_version", BIN_UINT, 4 }, - { "e_entry", BIN_UINT, 4 }, - { "e_phoff", BIN_UINT, 4 }, - { "e_shoff", BIN_UINT, 4 }, - { "e_flags", BIN_UINT, 4 }, - { "e_ehsize", BIN_UINT, 2 }, - { "e_phentsize", BIN_UINT, 2 }, - { "e_phnum", BIN_UINT, 2 }, - { "e_shentsize", BIN_UINT, 2 }, - { "e_shnum", BIN_UINT, 2 }, - { "e_shstrndx", BIN_UINT, 2 }, - { "" }, + { e_ident, BIN_UNINTERPRETED, EI_NIDENT }, + { e_type, BIN_UINT, 2 }, + { e_machine, BIN_UINT, 2 }, + { e_version, BIN_UINT, 4 }, + { e_entry, BIN_UINT, 4 }, + { e_phoff, BIN_UINT, 4 }, + { e_shoff, BIN_UINT, 4 }, + { e_flags, BIN_UINT, 4 }, + { e_ehsize, BIN_UINT, 2 }, + { e_phentsize, BIN_UINT, 2 }, + { e_phnum, BIN_UINT, 2 }, + { e_shentsize, BIN_UINT, 2 }, + { e_shnum, BIN_UINT, 2 }, + { e_shstrndx, BIN_UINT, 2 }, + { -1 }, }; static const BinField shn64_entry[] = { - { "sh_name", BIN_UINT, 4 }, - { "sh_type", BIN_UINT, 4 }, - { "sh_flags", BIN_UINT, 8 }, - { "sh_addr", BIN_UINT, 8 }, - { "sh_offset", BIN_UINT, 8 }, - { "sh_size", BIN_UINT, 8 }, - { "sh_link", BIN_UINT, 4 }, - { "sh_info", BIN_UINT, 4 }, - { "sh_addralign", BIN_UINT, 8 }, - { "sh_entsize", BIN_UINT, 8 }, - { "" } + { sh_name, BIN_UINT, 4 }, + { sh_type, BIN_UINT, 4 }, + { sh_flags, BIN_UINT, 8 }, + { sh_addr, BIN_UINT, 8 }, + { sh_offset, BIN_UINT, 8 }, + { sh_size, BIN_UINT, 8 }, + { sh_link, BIN_UINT, 4 }, + { sh_info, BIN_UINT, 4 }, + { sh_addralign, BIN_UINT, 8 }, + { sh_entsize, BIN_UINT, 8 }, + { -1 } }; - static const BinField shn32_entry[] = { - { "sh_name", BIN_UINT, 4 }, - { "sh_type", BIN_UINT, 4 }, - { "sh_flags", BIN_UINT, 4 }, - { "sh_addr", BIN_UINT, 4 }, - { "sh_offset", BIN_UINT, 4 }, - { "sh_size", BIN_UINT, 4 }, - { "sh_link", BIN_UINT, 4 }, - { "sh_info", BIN_UINT, 4 }, - { "sh_addralign", BIN_UINT, 4 }, - { "sh_entsize", BIN_UINT, 4 }, - { "" } + { sh_name, BIN_UINT, 4 }, + { sh_type, BIN_UINT, 4 }, + { sh_flags, BIN_UINT, 4 }, + { sh_addr, BIN_UINT, 4 }, + { sh_offset, BIN_UINT, 4 }, + { sh_size, BIN_UINT, 4 }, + { sh_link, BIN_UINT, 4 }, + { sh_info, BIN_UINT, 4 }, + { sh_addralign, BIN_UINT, 4 }, + { sh_entsize, BIN_UINT, 4 }, + { -1 } }; static const BinField sym64_format[] = { - { "st_name", BIN_UINT, 4 }, - { "st_info", BIN_UINT, 1 }, - { "st_other", BIN_UINT, 1 }, - { "st_shndx", BIN_UINT, 2 }, - { "st_value", BIN_UINT, 8 }, - { "st_size", BIN_UINT, 8 }, - { "" } + { st_name, BIN_UINT, 4 }, + { st_info, BIN_UINT, 1 }, + { st_other, BIN_UINT, 1 }, + { st_shndx, BIN_UINT, 2 }, + { st_value, BIN_UINT, 8 }, + { st_size, BIN_UINT, 8 }, + { -1 } }; - static const BinField sym32_format[] = { - { "st_name", BIN_UINT, 4 }, - { "st_value", BIN_UINT, 4 }, - { "st_size", BIN_UINT, 4 }, - { "st_info", BIN_UINT, 1 }, - { "st_other", BIN_UINT, 1 }, - { "st_shndx", BIN_UINT, 2 }, - { "" }, + { st_name, BIN_UINT, 4 }, + { st_value, BIN_UINT, 4 }, + { st_size, BIN_UINT, 4 }, + { st_info, BIN_UINT, 1 }, + { st_other, BIN_UINT, 1 }, + { st_shndx, BIN_UINT, 2 }, + { -1 }, }; if (is_64) { |