diff options
-rw-r--r-- | bfd/ChangeLog | 12 | ||||
-rw-r--r-- | bfd/elf-m10300.c | 81 |
2 files changed, 79 insertions, 14 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index be08948dfb3..6a7fe8dcb9c 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2007-11-13 Nick Clifton <nickc@redhat.com> + + * elf-m10300.c (mn10300_elf_final_link_relocate): Prevent the + accidental termination of DWARF location list entries. + (mn10300_elf_relax_delete_bytes): Stop deletion if an align reloc + is encountered that is larger than or not a mutliple of the number + of bytes being deleted. + When adjusting symbols, any symbols inside the region being + deleted must be moved to the end of the region. + Move align relocs forward if there is room for them after the + deletion of the region. + 2007-11-13 Alan Modra <amodra@bigpond.net.au> PR 5233 diff --git a/bfd/elf-m10300.c b/bfd/elf-m10300.c index 7c51498aa1e..9a75b7c7676 100644 --- a/bfd/elf-m10300.c +++ b/bfd/elf-m10300.c @@ -1039,6 +1039,17 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto, case R_MN10300_16: case R_MN10300_8: value -= sym_diff_value; + /* If we are computing a 32-bit value for the location lists + and the result is 0 then we add one to the value. A zero + value can result because of linker relaxation deleteing + prologue instructions and using a value of 1 (for the begin + and end offsets in the location list entry) results in a + nul entry which does not prevent the following entries from + being parsed. */ + if (r_type == R_MN10300_32 + && value == 0 + && strcmp (input_section->name, ".debug_loc") == 0) + value = 1; sym_diff_section = NULL; is_sym_diff_reloc = TRUE; break; @@ -1856,17 +1867,23 @@ mn10300_elf_relax_delete_bytes (bfd *abfd, --irelend; /* The deletion must stop at the next ALIGN reloc for an aligment - power larger than the number of bytes we are deleting. */ + power larger than, or not a multiple of, the number of bytes we + are deleting. */ for (; irel < irelend; irel++) - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN - && irel->r_offset > addr - && irel->r_offset < toaddr - && count < (1 << irel->r_addend)) - { - irelalign = irel; - toaddr = irel->r_offset; - break; - } + { + int alignment = 1 << irel->r_addend; + + if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN + && irel->r_offset > addr + && irel->r_offset < toaddr + && (count < alignment + || alignment % count != 0)) + { + irelalign = irel; + toaddr = irel->r_offset; + break; + } + } } /* Actually delete the bytes. */ @@ -1898,11 +1915,17 @@ mn10300_elf_relax_delete_bytes (bfd *abfd, { /* Get the new reloc address. */ if ((irel->r_offset > addr - && irel->r_offset < toaddr)) + && irel->r_offset < toaddr) + || (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN + && irel->r_offset == toaddr)) irel->r_offset -= count; } - /* Adjust the local symbols defined in this section. */ + /* Adjust the local symbols in the section, reducing their value + by the number of bytes deleted. Note - symbols within the deleted + region are moved to the address of the start of the region, which + actually means that they will address the byte beyond the end of + the region once the deletion has been completed. */ symtab_hdr = &elf_tdata (abfd)->symtab_hdr; isym = (Elf_Internal_Sym *) symtab_hdr->contents; for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) @@ -1910,7 +1933,12 @@ mn10300_elf_relax_delete_bytes (bfd *abfd, if (isym->st_shndx == sec_shndx && isym->st_value > addr && isym->st_value < toaddr) - isym->st_value -= count; + { + if (isym->st_value < addr + count) + isym->st_value = addr; + else + isym->st_value -= count; + } /* Adjust the function symbol's size as well. */ else if (isym->st_shndx == sec_shndx && ELF_ST_TYPE (isym->st_info) == STT_FUNC @@ -1933,7 +1961,12 @@ mn10300_elf_relax_delete_bytes (bfd *abfd, && sym_hash->root.u.def.section == sec && sym_hash->root.u.def.value > addr && sym_hash->root.u.def.value < toaddr) - sym_hash->root.u.def.value -= count; + { + if (sym_hash->root.u.def.value < addr + count) + sym_hash->root.u.def.value = addr; + else + sym_hash->root.u.def.value -= count; + } /* Adjust the function symbol's size as well. */ else if (sym_hash->root.type == bfd_link_hash_defined && sym_hash->root.u.def.section == sec @@ -1943,6 +1976,26 @@ mn10300_elf_relax_delete_bytes (bfd *abfd, sym_hash->size -= count; } + /* See if we can move the ALIGN reloc forward. + We have adjusted r_offset for it already. */ + if (irelalign != NULL) + { + bfd_vma alignto, alignaddr; + + if ((int) irelalign->r_addend > 0) + { + /* This is the old address. */ + alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_addend); + /* This is where the align points to now. */ + alignaddr = BFD_ALIGN (irelalign->r_offset, + 1 << irelalign->r_addend); + if (alignaddr < alignto) + /* Tail recursion. */ + return mn10300_elf_relax_delete_bytes (abfd, sec, alignaddr, + (int) (alignto - alignaddr)); + } + } + return TRUE; } |