From 60f2e42e00083accdcdbdda399534082bf309d1e Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Mon, 9 Nov 2015 23:49:02 -0800 Subject: [PATCH] Fix performance regression on x86 with ld -r Similar fix to "commit c316a17c40e44e8798b34ff84130904f2e7a53de". * elf32-i386.c (elf_i386_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. * elf64-x86-64.c (elf_x86_64_relocate_section): Likewise. --- bfd/ChangeLog | 8 ++++++++ bfd/elf32-i386.c | 49 ++++++++++++++++++++++++++++++++++++++++++---- bfd/elf64-x86-64.c | 49 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 98 insertions(+), 8 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index d46bbe092bc..d7000cbf03a 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2015-11-09 H.J. Lu + + * elf32-i386.c (elf_i386_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. + * elf64-x86-64.c (elf_x86_64_relocate_section): Likewise. + 2015-11-10 Alan Modra * elf64-ppc.c (ppc64_elf_relocate_section): Use read and write diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 98d2b495535..6c353e9af84 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -3599,6 +3599,7 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_vma *local_got_offsets; bfd_vma *local_tlsdesc_gotents; Elf_Internal_Rela *rel; + Elf_Internal_Rela *wrel; Elf_Internal_Rela *relend; bfd_boolean is_vxworks_tls; unsigned plt_entry_size; @@ -3623,9 +3624,9 @@ elf_i386_relocate_section (bfd *output_bfd, plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); - rel = relocs; + rel = wrel = relocs; relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) + for (; rel < relend; wrel++, rel++) { unsigned int r_type; reloc_howto_type *howto; @@ -3772,8 +3773,22 @@ elf_i386_relocate_section (bfd *output_bfd, } if (sec != NULL && discarded_section (sec)) - 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 + 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; @@ -4365,6 +4380,7 @@ r_386_got32: contents + roff); /* Skip R_386_PC32/R_386_PLT32. */ rel++; + wrel++; continue; } else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC) @@ -4704,6 +4720,7 @@ r_386_got32: contents + roff + 8); /* Skip R_386_PLT32. */ rel++; + wrel++; continue; } else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC) @@ -4801,6 +4818,7 @@ r_386_got32: "\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11); /* Skip R_386_PC32/R_386_PLT32. */ rel++; + wrel++; continue; } @@ -4942,6 +4960,29 @@ check_relocation_error: return FALSE; } } + + 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; } return TRUE; diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index deaee91a8d3..8e62d3d6aa6 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -3866,6 +3866,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, bfd_vma *local_got_offsets; bfd_vma *local_tlsdesc_gotents; Elf_Internal_Rela *rel; + Elf_Internal_Rela *wrel; Elf_Internal_Rela *relend; const unsigned int plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); @@ -3881,9 +3882,9 @@ elf_x86_64_relocate_section (bfd *output_bfd, elf_x86_64_set_tls_module_base (info); - rel = relocs; + rel = wrel = relocs; relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) + for (; rel < relend; wrel++, rel++) { unsigned int r_type; reloc_howto_type *howto; @@ -3961,8 +3962,22 @@ elf_x86_64_relocate_section (bfd *output_bfd, } if (sec != NULL && discarded_section (sec)) - 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 + 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; @@ -4782,6 +4797,7 @@ direct: contents + roff + 8 + largepic); /* Skip R_X86_64_PC32/R_X86_64_PLT32/R_X86_64_PLTOFF64. */ rel++; + wrel++; continue; } else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC) @@ -5064,6 +5080,7 @@ direct: contents + roff + 8 + largepic); /* Skip R_X86_64_PLT32/R_X86_64_PLTOFF64. */ rel++; + wrel++; continue; } else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC) @@ -5148,6 +5165,7 @@ direct: "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12); /* Skip R_X86_64_PC32/R_X86_64_PLT32/R_X86_64_PLTOFF64. */ rel++; + wrel++; continue; } @@ -5264,6 +5282,29 @@ check_relocation_error: return FALSE; } } + + 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; } return TRUE; -- 2.30.2