diff options
author | DJ Delorie <dj@redhat.com> | 2006-08-14 20:05:00 +0000 |
---|---|---|
committer | DJ Delorie <dj@redhat.com> | 2006-08-14 20:05:00 +0000 |
commit | eb13e63f9480a38e2f2c60d9db624c0b1ce106f6 (patch) | |
tree | 522560f3a9915593605d3e4af304e2cbfec6f93c /bfd/elf-m10300.c | |
parent | b59eed791185545a2ccb2eef9e4e70b758a7e639 (diff) | |
download | gdb-eb13e63f9480a38e2f2c60d9db624c0b1ce106f6.zip gdb-eb13e63f9480a38e2f2c60d9db624c0b1ce106f6.tar.gz gdb-eb13e63f9480a38e2f2c60d9db624c0b1ce106f6.tar.bz2 |
* elf-m10300.c (elf32_mn10300_link_hash_entry): Add value.
(elf32_mn10300_count_hash_table_entries): New.
(elf32_mn10300_list_hash_table_entries): New.
(sort_by_value): New.
(mn10300_elf_relax_section): Don't skip data sections; restrict
code-specific tests to code-specific areas so that potential
indirect calls can be detected. Check for multiple local symbols
at the same address and merge their flags.
(elf32_mn10300_link_hash_newfunc): Initialize value.
Diffstat (limited to 'bfd/elf-m10300.c')
-rw-r--r-- | bfd/elf-m10300.c | 107 |
1 files changed, 95 insertions, 12 deletions
diff --git a/bfd/elf-m10300.c b/bfd/elf-m10300.c index 509f2a1..a8f4836 100644 --- a/bfd/elf-m10300.c +++ b/bfd/elf-m10300.c @@ -85,6 +85,9 @@ struct elf32_mn10300_link_hash_entry { prologue deleted. */ #define MN10300_DELETED_PROLOGUE_BYTES 0x2 unsigned char flags; + + /* Calculated value. */ + bfd_vma value; }; /* We derive a hash table from the main elf linker hash table so @@ -1602,6 +1605,42 @@ elf32_mn10300_finish_hash_table_entry (gen_entry, in_args) return TRUE; } +/* Used to count hash table entries. */ +static bfd_boolean +elf32_mn10300_count_hash_table_entries (struct bfd_hash_entry *gen_entry ATTRIBUTE_UNUSED, + PTR in_args) +{ + int *count = (int *)in_args; + + (*count) ++; + return TRUE; +} + +/* Used to enumerate hash table entries into a linear array. */ +static bfd_boolean +elf32_mn10300_list_hash_table_entries (struct bfd_hash_entry *gen_entry, + PTR in_args) +{ + struct bfd_hash_entry ***ptr = (struct bfd_hash_entry ***) in_args; + + **ptr = gen_entry; + (*ptr) ++; + return TRUE; +} + +/* Used to sort the array created by the above. */ +static int +sort_by_value (const void *va, const void *vb) +{ + struct elf32_mn10300_link_hash_entry *a + = *(struct elf32_mn10300_link_hash_entry **)va; + struct elf32_mn10300_link_hash_entry *b + = *(struct elf32_mn10300_link_hash_entry **)vb; + + return a->value - b->value; +} + + /* This function handles relaxing for the mn10300. There are quite a few relaxing opportunities available on the mn10300: @@ -1697,9 +1736,10 @@ mn10300_elf_relax_section (abfd, sec, link_info, again) char *new_name; /* If there's nothing to do in this section, skip it. */ - if (! (((section->flags & SEC_RELOC) != 0 - && section->reloc_count != 0) - || (section->flags & SEC_CODE) != 0)) + if (! ((section->flags & SEC_RELOC) != 0 + && section->reloc_count != 0)) + continue; + if ((section->flags & SEC_ALLOC) == 0) continue; /* Get cached copy of section contents if it exists. */ @@ -1802,13 +1842,17 @@ mn10300_elf_relax_section (abfd, sec, link_info, again) elf_sym_hashes (input_bfd)[r_index]; } - /* If this is not a "call" instruction, then we - should convert "call" instructions to "calls" - instructions. */ - code = bfd_get_8 (input_bfd, - contents + irel->r_offset - 1); - if (code != 0xdd && code != 0xcd) - hash->flags |= MN10300_CONVERT_CALL_TO_CALLS; + sym_name = hash->root.root.root.string; + if ((section->flags & SEC_CODE) != 0) + { + /* If this is not a "call" instruction, then we + should convert "call" instructions to "calls" + instructions. */ + code = bfd_get_8 (input_bfd, + contents + irel->r_offset - 1); + if (code != 0xdd && code != 0xcd) + hash->flags |= MN10300_CONVERT_CALL_TO_CALLS; + } /* If this is a jump/call, then bump the direct_calls counter. Else force "call" to @@ -1901,6 +1945,7 @@ mn10300_elf_relax_section (abfd, sec, link_info, again) free (new_name); compute_function_info (input_bfd, hash, isym->st_value, contents); + hash->value = isym->st_value; } } @@ -1962,6 +2007,44 @@ mn10300_elf_relax_section (abfd, sec, link_info, again) elf32_mn10300_finish_hash_table_entry, link_info); + { + /* This section of code collects all our local symbols, sorts + them by value, and looks for multiple symbols referring to + the same address. For those symbols, the flags are merged. + At this point, the only flag that can be set is + MN10300_CONVERT_CALL_TO_CALLS, so we simply OR the flags + together. */ + int static_count = 0, i; + struct elf32_mn10300_link_hash_entry **entries; + struct elf32_mn10300_link_hash_entry **ptr; + + elf32_mn10300_link_hash_traverse (hash_table->static_hash_table, + elf32_mn10300_count_hash_table_entries, + &static_count); + + entries = (struct elf32_mn10300_link_hash_entry **) + bfd_malloc (static_count * sizeof (struct elf32_mn10300_link_hash_entry *)); + + ptr = entries; + elf32_mn10300_link_hash_traverse (hash_table->static_hash_table, + elf32_mn10300_list_hash_table_entries, + &ptr); + + qsort (entries, static_count, sizeof(entries[0]), sort_by_value); + + for (i=0; i<static_count-1; i++) + if (entries[i]->value && entries[i]->value == entries[i+1]->value) + { + int v = entries[i]->flags; + int j; + for (j=i+1; j<static_count && entries[j]->value == entries[i]->value; j++) + v |= entries[j]->flags; + for (j=i; j<static_count && entries[j]->value == entries[i]->value; j++) + entries[j]->flags = v; + i = j-1; + } + } + /* All entries in the hash table are fully initialized. */ hash_table->flags |= MN10300_HASH_ENTRIES_INITIALIZED; @@ -2795,8 +2878,7 @@ mn10300_elf_relax_section (abfd, sec, link_info, again) into a 16bit immediate, displacement or absolute address. */ if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_32 || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOT32 - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTOFF32 - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTPC32) + || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTOFF32) { bfd_vma value = symval; @@ -3677,6 +3759,7 @@ elf32_mn10300_link_hash_newfunc (entry, table, string) ret->movm_args = 0; ret->movm_stack_size = 0; ret->flags = 0; + ret->value = 0; } return (struct bfd_hash_entry *) ret; |