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/elf32-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/elf32-ppc.c')
-rw-r--r-- | bfd/elf32-ppc.c | 122 |
1 files changed, 83 insertions, 39 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 708076d..5c26077 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -7650,6 +7650,7 @@ ppc_elf_relocate_section (bfd *output_bfd, struct elf_link_hash_entry **sym_hashes; struct ppc_elf_link_hash_table *htab; Elf_Internal_Rela *rel; + Elf_Internal_Rela *wrel; Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; asection *got2; @@ -7685,9 +7686,9 @@ ppc_elf_relocate_section (bfd *output_bfd, ".tls_vars")); if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET) relax_info = elf_section_data (input_section)->sec_info; - rel = relocs; + rel = wrel = relocs; relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) + for (; rel < relend; wrel++, rel++) { enum elf_ppc_reloc_type r_type; bfd_vma addend; @@ -7706,6 +7707,7 @@ ppc_elf_relocate_section (bfd *output_bfd, struct plt_entry **ifunc; struct reloc_howto_struct alt_howto; + again: r_type = ELF32_R_TYPE (rel->r_info); sym = NULL; sec = NULL; @@ -7742,8 +7744,22 @@ ppc_elf_relocate_section (bfd *output_bfd, howto = NULL; if (r_type < R_PPC_max) howto = ppc_elf_howto_table[r_type]; - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); + + _bfd_clear_contents (howto, 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)) @@ -7759,7 +7775,7 @@ ppc_elf_relocate_section (bfd *output_bfd, if (r_type != R_PPC_RELAX_PLT && r_type != R_PPC_RELAX_PLTREL24 && r_type != R_PPC_RELAX) - continue; + goto copy_reloc; } /* TLS optimizations. Replace instruction sequences and relocs @@ -7802,10 +7818,12 @@ ppc_elf_relocate_section (bfd *output_bfd, { bfd_vma insn; - 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 |= 0x3c020000; /* addis 0,2,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_PPC_TPREL16_HA; rel->r_info = ELF32_R_INFO (r_symndx, r_type); } @@ -7941,8 +7959,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { /* We changed the symbol on an LD reloc. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } } break; @@ -8000,8 +8017,7 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Zap the reloc on the _tls_get_addr call too. */ BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset); rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); - rel--; - continue; + goto again; } break; } @@ -8080,9 +8096,9 @@ ppc_elf_relocate_section (bfd *output_bfd, got_addr = (htab->got->output_section->vma + htab->got->output_offset + (h->got.offset & ~1)); - rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA); - rel->r_addend = got_addr; - rel->r_offset = (p - contents) + d_offset; + wrel->r_offset = (p - contents) + d_offset; + wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA); + wrel->r_addend = got_addr; insn &= ~0xffff; insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff; bfd_put_32 (output_bfd, insn, p); @@ -8100,9 +8116,10 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Use one of the spare relocs, so --emit-relocs output is reasonable. */ memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); - rel++; + wrel++, rel++; + rel->r_offset = wrel[-1].r_offset + 4; rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO); - rel->r_offset += 4; + rel->r_addend = wrel[-1].r_addend; /* Continue on as if we had a got reloc, to output dynamic reloc. */ @@ -8236,7 +8253,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; case R_PPC_NONE: case R_PPC_TLS: @@ -8245,7 +8262,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_EMB_MRKREF: case R_PPC_GNU_VTINHERIT: case R_PPC_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 @@ -8496,7 +8513,7 @@ ppc_elf_relocate_section (bfd *output_bfd, /* If here for a picfixup, we're done. */ if (r_type != ELF32_R_TYPE (rel->r_info)) - continue; + goto copy_reloc; relocation = (htab->got->output_section->vma + htab->got->output_offset @@ -8529,7 +8546,7 @@ ppc_elf_relocate_section (bfd *output_bfd, rel->r_offset, TRUE)) return FALSE; - continue; + goto copy_reloc; } break; @@ -8768,7 +8785,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); if (skip == -1) - continue; + goto copy_reloc; /* This reloc will be computed at runtime. We clear the memory so that it contains predictable value. */ @@ -8861,12 +8878,13 @@ ppc_elf_relocate_section (bfd *output_bfd, relocs to describe this relocation. */ BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE); /* The relocs are at the bottom 2 bytes */ - rel[0].r_offset += d_offset; - memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); - rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); - rel[1].r_offset += 4; - rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); - rel++; + wrel->r_offset = rel->r_offset + d_offset; + wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); + wrel->r_addend = rel->r_addend; + memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel)); + wrel++, rel++; + wrel->r_offset += 4; + wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); } continue; @@ -9014,37 +9032,37 @@ ppc_elf_relocate_section (bfd *output_bfd, relocation = relocation + addend; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16a_type); - continue; + goto copy_reloc; case R_PPC_VLE_LO16D: relocation = relocation + addend; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16d_type); - continue; + goto copy_reloc; case R_PPC_VLE_HI16A: relocation = (relocation + addend) >> 16; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16a_type); - continue; + goto copy_reloc; case R_PPC_VLE_HI16D: relocation = (relocation + addend) >> 16; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16d_type); - continue; + goto copy_reloc; case R_PPC_VLE_HA16A: relocation = (relocation + addend + 0x8000) >> 16; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16a_type); - continue; + goto copy_reloc; case R_PPC_VLE_HA16D: relocation = (relocation + addend + 0x8000) >> 16; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16d_type); - continue; + goto copy_reloc; /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ case R_PPC_EMB_SDA21: @@ -9093,7 +9111,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; } if (sda != NULL) @@ -9131,7 +9149,7 @@ ppc_elf_relocate_section (bfd *output_bfd, if (r_type == R_PPC_VLE_SDA21 && ((relocation + 0x80000) & 0xffffffff) > 0x100000) goto overflow; - continue; + goto copy_reloc; } else if (r_type == R_PPC_EMB_SDA21 || r_type == R_PPC_VLE_SDA21 @@ -9187,7 +9205,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; } if (sda != NULL) @@ -9234,7 +9252,7 @@ ppc_elf_relocate_section (bfd *output_bfd, value, split16d_type); } } - continue; + goto copy_reloc; /* Relocate against the beginning of the section. */ case R_PPC_SECTOFF: @@ -9282,7 +9300,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_invalid_operation); ret = FALSE; - continue; + goto copy_reloc; } /* Do any further special processing. */ @@ -9342,7 +9360,8 @@ ppc_elf_relocate_section (bfd *output_bfd, that make up part of the insn opcode. */ unsigned int insn, mask, lobit; - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); mask = 0; if (is_insn_ds_form (insn)) mask = 3; @@ -9452,6 +9471,31 @@ ppc_elf_relocate_section (bfd *output_bfd, ret = FALSE; } } + 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; + wrel++; + } + relend = wrel; + rel_hdr = _bfd_elf_single_rel_hdr (input_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + input_section->reloc_count -= deleted; } #ifdef DEBUG |