From 53291d1f1601d6958248dcfb755af470521c186a Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 8 Feb 2014 12:26:53 +1030 Subject: [PATCH] powerpc relax_section and section contents cache This patch provides a means for backend relax_section support to increase the size of a section without needing to reallocate section contents. This helps reduce memory usage when the added space does not need to be written in relax_section, as is the case for powerpc. Writing the stubs later means a few tweaks are needed in the powerpc relocate_section function, but also removes some code duplication since the extra ld -r relocs can be written there too. * elf-bfd.h (struct elf_backend_data): Add caches_rawsize. * elfxx-target.h (elf_backend_caches_rawsize): Define. (elfNN_bed): Init new field. * elflink.c (elf_link_input_bfd): Handle caches_rawsize. * elf32-ppc.c (shared_stub_entry): Zero addi offset. (ppc_elf_relax_section): Don't reallocate section here, write stubs, or write out relocs for ld -r here.. (ppc_elf_relocate_section): ..instead write stubs here, and use existing code to write out relocs for ld -r. Fix offset adjustment on reloc for little-endian. (elf_backend_caches_rawsize): Define. --- bfd/ChangeLog | 14 ++++ bfd/elf-bfd.h | 5 ++ bfd/elf32-ppc.c | 172 +++++++++++++++++---------------------------- bfd/elflink.c | 11 ++- bfd/elfxx-target.h | 6 +- 5 files changed, 100 insertions(+), 108 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 37074c9071d..5b828a3b2b1 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2014-02-09 Alan Modra + + * elf-bfd.h (struct elf_backend_data): Add caches_rawsize. + * elfxx-target.h (elf_backend_caches_rawsize): Define. + (elfNN_bed): Init new field. + * elflink.c (elf_link_input_bfd): Handle caches_rawsize. + * elf32-ppc.c (shared_stub_entry): Zero addi offset. + (ppc_elf_relax_section): Don't reallocate section here, write + stubs, or write out relocs for ld -r here.. + (ppc_elf_relocate_section): ..instead write stubs here, and use + existing code to write out relocs for ld -r. Fix offset + adjustment on reloc for little-endian. + (elf_backend_caches_rawsize): Define. + 2014-02-07 Rainer Orth * cache.c (bfd_cache_max_open): Cast RLIM_INFINITY to rlim_t. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 0aab5fa065a..76cac2febea 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1342,6 +1342,11 @@ struct elf_backend_data other file in the link needs to have a .note.GNU-stack section for a PT_GNU_STACK segment to be created. */ unsigned default_execstack : 1; + + /* True if elf_section_data(sec)->this_hdr.contents is sec->rawsize + in length rather than sec->size in length, if sec->rawsize is + non-zero and smaller than sec->size. */ + unsigned caches_rawsize : 1; }; /* Information about reloc sections associated with a bfd_elf_section_data diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index d13d31b4ece..0b43b9b9a87 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -6623,7 +6623,7 @@ static const int shared_stub_entry[] = 0x429f0005, /* bcl 20, 31, .Lxxx */ 0x7d8802a6, /* mflr 12 */ 0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */ - 0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */ + 0x398c0000, /* addi 12, 12, (xxx-.Lxxx)@l */ 0x7c0803a6, /* mtlr 0 */ 0x7d8903a6, /* mtctr 12 */ 0x4e800420, /* bctr */ @@ -6645,10 +6645,7 @@ struct ppc_elf_relax_info /* This function implements long branch trampolines, and the ppc476 icache bug workaround. Any section needing trampolines or patch space for the workaround has its size extended so that we can - add trampolines at the end of the section. FIXME: We write out - trampoline templates here and later modify them in - relocate_section. We'd save a realloc if we left writing the - templates to relocate_section. */ + add trampolines at the end of the section. */ static bfd_boolean ppc_elf_relax_section (bfd *abfd, @@ -6704,12 +6701,14 @@ ppc_elf_relax_section (bfd *abfd, isec->rawsize = isec->size; trampbase = isec->size; + BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE + || isec->sec_info_type == SEC_INFO_TYPE_TARGET); + isec->sec_info_type = SEC_INFO_TYPE_TARGET; + if (htab->params->ppc476_workaround) { if (elf_section_data (isec)->sec_info == NULL) { - BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE); - isec->sec_info_type = SEC_INFO_TYPE_TARGET; elf_section_data (isec)->sec_info = bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info)); if (elf_section_data (isec)->sec_info == NULL) @@ -7082,13 +7081,6 @@ ppc_elf_relax_section (bfd *abfd, { relax_info->workaround_size = newsize; workaround_change = TRUE; - if (contents == NULL) - { - if (elf_section_data (isec)->this_hdr.contents != NULL) - contents = elf_section_data (isec)->this_hdr.contents; - else if (!bfd_malloc_and_get_section (abfd, isec, &contents)) - goto error_return; - } } /* Ensure relocate_section is called. */ isec->flags |= SEC_RELOC; @@ -7096,54 +7088,6 @@ ppc_elf_relax_section (bfd *abfd, newsize = trampoff + relax_info->workaround_size; } - if (changes || workaround_change) - { - contents = bfd_realloc_or_free (contents, newsize); - if (contents == NULL) - goto error_return; - - /* Branch around the trampolines. */ - if (maybe_pasted) - { - bfd_vma val = B + newsize - isec->rawsize; - bfd_put_32 (abfd, val, contents + isec->rawsize); - } - } - - /* Write out the trampolines. */ - if (changes) - { - const int *stub; - bfd_byte *dest; - int i, size; - - dest = contents + trampbase; - if (maybe_pasted && trampbase == isec->rawsize) - dest += 4; - - if (link_info->shared) - { - stub = shared_stub_entry; - size = ARRAY_SIZE (shared_stub_entry); - } - else - { - stub = stub_entry; - size = ARRAY_SIZE (stub_entry); - } - - i = 0; - while (dest < contents + trampoff) - { - bfd_put_32 (abfd, stub[i], dest); - i++; - if (i == size) - i = 0; - dest += 4; - } - BFD_ASSERT (i == 0); - } - if (changes || workaround_change) isec->size = newsize; @@ -7162,7 +7106,7 @@ ppc_elf_relax_section (bfd *abfd, if (contents != NULL && elf_section_data (isec)->this_hdr.contents != contents) { - if (!changes && !workaround_change && !link_info->keep_memory) + if (!changes && !link_info->keep_memory) free (contents); else { @@ -7202,27 +7146,6 @@ ppc_elf_relax_section (bfd *abfd, free (internal_relocs); *again = changes != 0 || workaround_change; - if (!*again && link_info->relocatable && htab->params->branch_trampolines) - { - /* Convert the internal relax relocs to external form. */ - for (irel = internal_relocs; irel < irelend; irel++) - if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX) - { - unsigned long r_symndx = ELF32_R_SYM (irel->r_info); - - /* Rewrite the reloc and convert one of the trailing nop - relocs to describe this relocation. */ - BFD_ASSERT (ELF32_R_TYPE (irelend[-1].r_info) == R_PPC_NONE); - /* The relocs are at the bottom 2 bytes */ - irel[0].r_offset += 2; - memmove (irel + 1, irel, (irelend - irel - 1) * sizeof (*irel)); - irel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); - irel[1].r_offset += 4; - irel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); - irel++; - } - } - return TRUE; error_return: @@ -7639,7 +7562,10 @@ ppc_elf_relocate_section (bfd *output_bfd, addend specifies the GOT pointer offset within .got2. */ rel->r_addend += got2->output_offset; } - continue; + if (r_type != R_PPC_RELAX_PLT + && r_type != R_PPC_RELAX_PLTREL24 + && r_type != R_PPC_RELAX) + continue; } /* TLS optimizations. Replace instruction sequences and relocs @@ -8554,36 +8480,59 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Fall thru */ case R_PPC_RELAX: - if (info->shared) - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset - 4); - { - unsigned long t0; - unsigned long t1; + const int *stub; + size_t size; + size_t insn_offset = rel->r_offset; + unsigned int insn; - t0 = bfd_get_32 (output_bfd, contents + rel->r_offset); - t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4); - - /* We're clearing the bits for R_PPC_ADDR16_HA - and R_PPC_ADDR16_LO here. */ - t0 &= ~0xffff; - t1 &= ~0xffff; + if (info->shared) + { + relocation -= (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset - 4); + stub = shared_stub_entry; + bfd_put_32 (output_bfd, stub[0], contents + insn_offset - 12); + bfd_put_32 (output_bfd, stub[1], contents + insn_offset - 8); + bfd_put_32 (output_bfd, stub[2], contents + insn_offset - 4); + stub += 3; + size = ARRAY_SIZE (shared_stub_entry) - 3; + } + else + { + stub = stub_entry; + size = ARRAY_SIZE (stub_entry); + } - /* t0 is HA, t1 is LO */ relocation += addend; - t0 |= ((relocation + 0x8000) >> 16) & 0xffff; - t1 |= relocation & 0xffff; - - bfd_put_32 (output_bfd, t0, contents + rel->r_offset); - bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4); + if (info->relocatable) + relocation = 0; + + /* First insn is HA, second is LO. */ + insn = *stub++; + insn |= ((relocation + 0x8000) >> 16) & 0xffff; + bfd_put_32 (output_bfd, insn, contents + insn_offset); + insn_offset += 4; + + insn = *stub++; + insn |= relocation & 0xffff; + bfd_put_32 (output_bfd, insn, contents + insn_offset); + insn_offset += 4; + size -= 2; + + while (size != 0) + { + insn = *stub++; + --size; + bfd_put_32 (output_bfd, insn, contents + insn_offset); + insn_offset += 4; + } /* Rewrite the reloc and convert one of the trailing nop 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 += 2; + 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; @@ -9174,6 +9123,16 @@ ppc_elf_relocate_section (bfd *output_bfd, fprintf (stderr, "\n"); #endif + if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET + && input_section->size != input_section->rawsize + && (strcmp (input_section->output_section->name, ".init") == 0 + || strcmp (input_section->output_section->name, ".fini") == 0)) + { + /* Branch around the trampolines. */ + unsigned int insn = B + input_section->size - input_section->rawsize; + bfd_put_32 (input_bfd, insn, contents + input_section->rawsize); + } + if (htab->params->ppc476_workaround && input_section->sec_info_type == SEC_INFO_TYPE_TARGET) { @@ -10137,6 +10096,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_can_gc_sections 1 #define elf_backend_can_refcount 1 #define elf_backend_rela_normal 1 +#define elf_backend_caches_rawsize 1 #define bfd_elf32_mkobject ppc_elf_mkobject #define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data diff --git a/bfd/elflink.c b/bfd/elflink.c index 88967c835fa..af4f6bb190d 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -9549,7 +9549,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) file, so the contents field will not have been set by any of the routines which work on output files. */ if (elf_section_data (o)->this_hdr.contents != NULL) - contents = elf_section_data (o)->this_hdr.contents; + { + contents = elf_section_data (o)->this_hdr.contents; + if (bed->caches_rawsize + && o->rawsize != 0 + && o->rawsize < o->size) + { + memcpy (flinfo->contents, contents, o->rawsize); + contents = flinfo->contents; + } + } else { contents = flinfo->contents; diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index 2e7cbca3489..74e1b32b2da 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -109,6 +109,9 @@ #ifndef elf_backend_default_execstack #define elf_backend_default_execstack 1 #endif +#ifndef elf_backend_caches_rawsize +#define elf_backend_caches_rawsize 0 +#endif #ifndef elf_backend_stack_align #define elf_backend_stack_align 16 #endif @@ -794,7 +797,8 @@ static struct elf_backend_data elfNN_bed = elf_backend_want_got_sym, elf_backend_want_dynbss, elf_backend_want_p_paddr_set_to_zero, - elf_backend_default_execstack + elf_backend_default_execstack, + elf_backend_caches_rawsize }; /* Forward declaration for use when initialising alternative_target field. */ -- 2.30.2