This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PowerPC64 ld vs. "allyesconfig" linux kernel
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Date: Tue, 23 Oct 2007 22:22:45 +0930
- Subject: PowerPC64 ld vs. "allyesconfig" linux kernel
This patch fixes a couple of linker bugs found when building a current
"allyesconfig" powerpc64 linux kernel. Such a kernel is rather large
and requires the "plt_branch" style of long branch stubs to stitch it
all together. With --emit-relocs, ld hits linker segfaults due to
emitting more relocs than the correct original count used to size the
reloc buffer. The kernel also well exceeds the 64k TOC limit,
requiring the linker to insert toc pointer adjusting stubs between
(some) calls, and ld managed to put .fixup for one input file in a
different toc group to .text in that file.
* elf64-ppc.c (ppc_build_one_stub): Don't duplicate relocs
emitted for ".brlt" entries.
(toc_adjusting_stub_needed): Don't treat ".fixup" specially here..
(ppc64_elf_next_input_section): ..instead do so here.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.268
diff -u -p -r1.268 elf64-ppc.c
--- bfd/elf64-ppc.c 26 Sep 2007 13:45:32 -0000 1.268
+++ bfd/elf64-ppc.c 23 Oct 2007 11:00:04 -0000
@@ -8387,49 +8387,57 @@ ppc_build_one_stub (struct bfd_hash_entr
bfd_put_64 (htab->brlt->owner, off,
htab->brlt->contents + br_entry->offset);
- if (htab->relbrlt != NULL)
- {
- /* Create a reloc for the branch lookup table entry. */
- Elf_Internal_Rela rela;
- bfd_byte *rl;
-
- rela.r_offset = (br_entry->offset
- + htab->brlt->output_offset
- + htab->brlt->output_section->vma);
- rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
- rela.r_addend = off;
-
- rl = htab->relbrlt->contents;
- rl += htab->relbrlt->reloc_count++ * sizeof (Elf64_External_Rela);
- bfd_elf64_swap_reloca_out (htab->relbrlt->owner, &rela, rl);
- }
- else if (info->emitrelocations)
+ if (br_entry->iter == htab->stub_iteration)
{
- Elf_Internal_Rela *relocs, *r;
- struct bfd_elf_section_data *elfsec_data;
+ br_entry->iter = 0;
+
+ if (htab->relbrlt != NULL)
+ {
+ /* Create a reloc for the branch lookup table entry. */
+ Elf_Internal_Rela rela;
+ bfd_byte *rl;
+
+ rela.r_offset = (br_entry->offset
+ + htab->brlt->output_offset
+ + htab->brlt->output_section->vma);
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+ rela.r_addend = off;
+
+ rl = htab->relbrlt->contents;
+ rl += (htab->relbrlt->reloc_count++
+ * sizeof (Elf64_External_Rela));
+ bfd_elf64_swap_reloca_out (htab->relbrlt->owner, &rela, rl);
+ }
+ else if (info->emitrelocations)
+ {
+ Elf_Internal_Rela *relocs, *r;
+ struct bfd_elf_section_data *elfsec_data;
- elfsec_data = elf_section_data (htab->brlt);
- relocs = elfsec_data->relocs;
- if (relocs == NULL)
- {
- bfd_size_type relsize;
- relsize = htab->brlt->reloc_count * sizeof (*relocs);
- relocs = bfd_alloc (htab->brlt->owner, relsize);
+ elfsec_data = elf_section_data (htab->brlt);
+ relocs = elfsec_data->relocs;
if (relocs == NULL)
- return FALSE;
- elfsec_data->relocs = relocs;
- elfsec_data->rel_hdr.sh_size = (stub_entry->stub_sec->reloc_count
- * sizeof (Elf64_External_Rela));
- elfsec_data->rel_hdr.sh_entsize = sizeof (Elf64_External_Rela);
- htab->brlt->reloc_count = 0;
- }
- r = relocs + htab->brlt->reloc_count;
- htab->brlt->reloc_count += 1;
- r->r_offset = (br_entry->offset
- + htab->brlt->output_offset
- + htab->brlt->output_section->vma);
- r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
- r->r_addend = off;
+ {
+ bfd_size_type relsize;
+ relsize = htab->brlt->reloc_count * sizeof (*relocs);
+ relocs = bfd_alloc (htab->brlt->owner, relsize);
+ if (relocs == NULL)
+ return FALSE;
+ elfsec_data->relocs = relocs;
+ elfsec_data->rel_hdr.sh_size
+ = (stub_entry->stub_sec->reloc_count
+ * sizeof (Elf64_External_Rela));
+ elfsec_data->rel_hdr.sh_entsize
+ = sizeof (Elf64_External_Rela);
+ htab->brlt->reloc_count = 0;
+ }
+ r = relocs + htab->brlt->reloc_count;
+ htab->brlt->reloc_count += 1;
+ r->r_offset = (br_entry->offset
+ + htab->brlt->output_offset
+ + htab->brlt->output_section->vma);
+ r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+ r->r_addend = off;
+ }
}
off = (br_entry->offset
@@ -8865,11 +8873,6 @@ toc_adjusting_stub_needed (struct bfd_li
if (isec->output_section == NULL)
return 0;
- /* Hack for linux kernel. .fixup contains branches, but only back to
- the function that hit an exception. */
- if (strcmp (isec->name, ".fixup") == 0)
- return 0;
-
if (isec->reloc_count == 0)
return 0;
@@ -9074,8 +9077,13 @@ ppc64_elf_next_input_section (struct bfd
/* If a code section has a function that uses the TOC then we need
to use the right TOC (obviously). Also, make sure that .opd gets
the correct TOC value for R_PPC64_TOC relocs that don't have or
- can't find their function symbol (shouldn't ever happen now). */
- if (isec->has_toc_reloc || (isec->flags & SEC_CODE) == 0)
+ can't find their function symbol (shouldn't ever happen now).
+ Also specially treat .fixup for the linux kernel. .fixup
+ contains branches, but only back to the function that hit an
+ exception. */
+ if (isec->has_toc_reloc
+ || (isec->flags & SEC_CODE) == 0
+ || strcmp (isec->name, ".fixup") == 0)
{
if (elf_gp (isec->owner) != 0)
htab->toc_curr = elf_gp (isec->owner);
--
Alan Modra
Australia Development Lab, IBM