diff options
author | Alan Modra <amodra@gmail.com> | 2015-11-09 15:03:29 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2015-11-10 17:14:41 +1030 |
commit | c316a17c40e44e8798b34ff84130904f2e7a53de (patch) | |
tree | c63c9eb998140c10abb05c3533f64dc99b6b9c88 /bfd/elf64-ppc.c | |
parent | 1057567ea711d80f9937653179b06507827d5819 (diff) | |
download | gdb-c316a17c40e44e8798b34ff84130904f2e7a53de.zip gdb-c316a17c40e44e8798b34ff84130904f2e7a53de.tar.gz gdb-c316a17c40e44e8798b34ff84130904f2e7a53de.tar.bz2 |
Fix performance regression due to ld -r memmove
The idea here is that instead of using memmove to shuffle the relocs
array every time one is deleted, to add a "wrel" pointer and copy from
rel[0] to wrel[0] as we go.
* elf64-ppc.c (ppc64_elf_relocate_section): Use read and write
pointers to reloc array, rather than memmove when deleting a
reloc. Don't use RELOC_AGAINST_DISCARDED_SECTION. Adjust
reloc counts at end of loop.
* elf32-ppc.c (ppc_elf_relocate_section): Likewise.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 96 |
1 files changed, 66 insertions, 30 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 0a85ab8..f491a09 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -13162,6 +13162,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; Elf_Internal_Rela *rel; + Elf_Internal_Rela *wrel; Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; bfd_byte *loc; @@ -13193,9 +13194,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, sym_hashes = elf_sym_hashes (input_bfd); is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd; - rel = relocs; + rel = wrel = relocs; relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) + for (; rel < relend; wrel++, rel++) { enum elf_ppc64_reloc_type r_type; bfd_vma addend; @@ -13219,10 +13220,13 @@ ppc64_elf_relocate_section (bfd *output_bfd, struct ppc_stub_hash_entry *stub_entry; bfd_vma max_br_offset; bfd_vma from; - const Elf_Internal_Rela orig_rel = *rel; + Elf_Internal_Rela orig_rel; reloc_howto_type *howto; struct reloc_howto_struct alt_howto; + again: + orig_rel = *rel; + r_type = ELF64_R_TYPE (rel->r_info); r_symndx = ELF64_R_SYM (rel->r_info); @@ -13230,10 +13234,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, symbol of the previous ADDR64 reloc. The symbol gives us the proper TOC base to use. */ if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC) - && rel != relocs - && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64 + && wrel != relocs + && ELF64_R_TYPE (wrel[-1].r_info) == R_PPC64_ADDR64 && is_opd) - r_symndx = ELF64_R_SYM (rel[-1].r_info); + r_symndx = ELF64_R_SYM (wrel[-1].r_info); sym = NULL; sec = NULL; @@ -13314,13 +13318,27 @@ ppc64_elf_relocate_section (bfd *output_bfd, h = (struct ppc_link_hash_entry *) h_elf; if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, - ppc64_elf_howto_table[r_type], 0, - contents); + { + _bfd_clear_contents (ppc64_elf_howto_table[r_type], + input_bfd, input_section, + contents + rel->r_offset); + wrel->r_offset = rel->r_offset; + wrel->r_info = 0; + wrel->r_addend = 0; + + /* For ld -r, remove relocations in debug sections against + sections defined in discarded sections. Not done for + non-debug to preserve relocs in .eh_frame which the + eh_frame editing code expects to be present. */ + if (bfd_link_relocatable (info) + && (input_section->flags & SEC_DEBUGGING)) + wrel--; + + continue; + } if (bfd_link_relocatable (info)) - continue; + goto copy_reloc; if (h != NULL && &h->elf == htab->elf.hgot) { @@ -13480,10 +13498,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, && (tls_mask & TLS_TPREL) == 0) { toctprel: - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); insn &= 31 << 21; insn |= 0x3c0d0000; /* addis 0,13,0 */ - bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); + bfd_put_32 (output_bfd, insn, + contents + rel->r_offset - d_offset); r_type = R_PPC64_TPREL16_HA; if (toc_symndx != 0) { @@ -13491,8 +13511,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend = toc_addend; /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } else rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -13518,8 +13537,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend = toc_addend; /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } else rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -13658,8 +13676,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } } break; @@ -13703,10 +13720,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } bfd_put_32 (output_bfd, insn2, contents + offset); if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0) - { - rel--; - continue; - } + goto again; } break; @@ -13748,8 +13762,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn2 = NOP; } bfd_put_32 (output_bfd, insn2, contents + offset); - rel--; - continue; + goto again; } break; @@ -14091,7 +14104,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, && addend == 0) { bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); - continue; + goto copy_reloc; } break; } @@ -14107,7 +14120,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; case R_PPC64_NONE: case R_PPC64_TLS: @@ -14116,7 +14129,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TOCSAVE: case R_PPC64_GNU_VTINHERIT: case R_PPC64_GNU_VTENTRY: - continue; + goto copy_reloc; /* GOT16 relocations. Like an ADDR16 using the symbol's address in the GOT as relocation value instead of the @@ -14752,7 +14765,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_invalid_operation); ret = FALSE; - continue; + goto copy_reloc; } /* Multi-instruction sequences that access the TOC can be @@ -14901,7 +14914,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, mask + 1); bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; } break; } @@ -15000,6 +15013,29 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (more_info != NULL) free (more_info); } + copy_reloc: + if (wrel != rel) + *wrel = *rel; + } + + if (wrel != rel) + { + Elf_Internal_Shdr *rel_hdr; + size_t deleted = rel - wrel; + + rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + if (rel_hdr->sh_size == 0) + { + /* It is too late to remove an empty reloc section. Leave + one NONE reloc. + ??? What is wrong with an empty section??? */ + rel_hdr->sh_size = rel_hdr->sh_entsize; + deleted -= 1; + } + rel_hdr = _bfd_elf_single_rel_hdr (input_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + input_section->reloc_count -= deleted; } /* If we're emitting relocations, then shortly after this function |