aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-02-08 12:26:53 +1030
committerAlan Modra <amodra@gmail.com>2014-02-09 23:25:14 +1030
commit53291d1f1601d6958248dcfb755af470521c186a (patch)
tree6c7d8b35b6792238cc852ff9e3866f154c77f8e2 /bfd
parentf9e7e5d3e6b8715d702cf0d530e8ca6cd243cd8b (diff)
downloadgdb-53291d1f1601d6958248dcfb755af470521c186a.zip
gdb-53291d1f1601d6958248dcfb755af470521c186a.tar.gz
gdb-53291d1f1601d6958248dcfb755af470521c186a.tar.bz2
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.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog14
-rw-r--r--bfd/elf-bfd.h5
-rw-r--r--bfd/elf32-ppc.c172
-rw-r--r--bfd/elflink.c11
-rw-r--r--bfd/elfxx-target.h6
5 files changed, 100 insertions, 108 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 37074c9..5b828a3 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,17 @@
+2014-02-09 Alan Modra <amodra@gmail.com>
+
+ * 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 <ro@CeBiTec.Uni-Bielefeld.DE>
* 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 0aab5fa..76cac2f 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 d13d31b..0b43b9b 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;
@@ -7097,54 +7089,6 @@ ppc_elf_relax_section (bfd *abfd,
}
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;
if (isymbuf != NULL
@@ -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 88967c8..af4f6bb 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 2e7cbca..74e1b32 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. */