This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PR11378, bugs on exit from large powerpc64 binaries
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Sun, 14 Mar 2010 17:45:13 +1030
- Subject: PR11378, bugs on exit from large powerpc64 binaries
I noticed when investigating PR11375 that the binary in question, cc1
from a bigtoc bootstrap, managed to have an _init function that was
pasted together from fragments all having different TOC pointers.
That in itself wasn't a problem since none of the fragments used the
TOC, but it would be if the startup files ever do so. Fixed via
ppc64_elf_check_init_fini.
More importantly, I noticed that _init and _fini were only seen to
make calls to other functions (which might need a valid TOC pointer)
if the first fragment had such a call. That happened to be true for
_init but not for _fini. It's possible that some odd bugs seen on
exit from large ppc64 binaries might be caused by this. Fixed by
looking at all fragments of .init/.fini in toc_adjusting_stub_needed.
bfd/
PR ld/11378
* elf64-ppc.h (ppc64_elf_check_init_fini): Declare.
* elf64-ppc.c (call_check_done): Define.
(ppc64_elf_add_symbol_hook): Substitute bfd_get_section_name macro.
(ppc64_elf_check_relocs, ppc64_elf_size_dynamic_sections): Likewise.
(ppc64_elf_finish_multitoc_partition): Remove unnecessary check.
(toc_adjusting_stub_needed): Use call_check_done rather than toc_off.
Simplify return logic. Iterate over all .init and .fini fragments
by recursion. Set makes_toc_func_call here..
(ppc64_elf_next_input_section): ..rather than here.
(check_pasted_section, ppc64_elf_check_init_fini): New functions.
ld/
PR ld/11378
* emultempl/ppc64elf.em (gld${EMULATION_NAME}_after_allocation): Call
ppc64_elf_check_init_fini and warn if .init/.fini use different TOCs.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.320
diff -u -p -w -r1.320 elf64-ppc.c
--- bfd/elf64-ppc.c 12 Mar 2010 22:31:16 -0000 1.320
+++ bfd/elf64-ppc.c 14 Mar 2010 01:45:48 -0000
@@ -3820,6 +3820,7 @@ struct ppc_link_hash_table
/* Recursion protection when determining above flag. */
#define call_check_in_progress sec_flg4
+#define call_check_done sec_flg5
/* Get the ppc64 ELF linker hash table from a link_info structure. */
@@ -4573,7 +4574,7 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
;
else if (*sec != NULL
- && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
+ && strcmp ((*sec)->name, ".opd") == 0)
isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
return TRUE;
@@ -4880,7 +4881,7 @@ ppc64_elf_check_relocs (bfd *abfd, struc
sreloc = NULL;
opd_sym_map = NULL;
- if (strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0)
+ if (strcmp (sec->name, ".opd") == 0)
{
/* Garbage collection needs some extra help with .opd sections.
We don't want to necessarily keep everything referenced by
@@ -8811,7 +8812,7 @@ ppc64_elf_size_dynamic_sections (bfd *ou
/* Strip this section if we don't need it; see the
comment below. */
}
- else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
+ else if (CONST_STRNEQ (s->name, ".rela"))
{
if (s->size != 0)
{
@@ -10125,9 +10126,6 @@ ppc64_elf_finish_multitoc_partition (str
{
struct ppc_link_hash_table *htab = ppc_hash_table (info);
- if (htab == NULL)
- return;
-
/* After the second pass, toc_curr tracks the TOC offset used
for code sections below in ppc64_elf_next_input_section. */
htab->toc_curr = TOC_BASE_OFF;
@@ -10144,10 +10142,10 @@ ppc64_elf_finish_multitoc_partition (str
static int
toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
{
- Elf_Internal_Rela *relstart, *rel;
- Elf_Internal_Sym *local_syms;
int ret;
- struct ppc_link_hash_table *htab;
+
+ /* Mark this section as checked. */
+ isec->call_check_done = 1;
/* We know none of our code bearing sections will need toc stubs. */
if ((isec->flags & SEC_LINKER_CREATED) != 0)
@@ -10159,8 +10157,12 @@ toc_adjusting_stub_needed (struct bfd_li
if (isec->output_section == NULL)
return 0;
- if (isec->reloc_count == 0)
- return 0;
+ ret = 0;
+ if (isec->reloc_count != 0)
+ {
+ Elf_Internal_Rela *relstart, *rel;
+ Elf_Internal_Sym *local_syms;
+ struct ppc_link_hash_table *htab;
relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL,
info->keep_memory);
@@ -10169,7 +10171,6 @@ toc_adjusting_stub_needed (struct bfd_li
/* Look for branches to outside of this section. */
local_syms = NULL;
- ret = 0;
htab = ppc_hash_table (info);
if (htab == NULL)
return -1;
@@ -10217,8 +10218,8 @@ toc_adjusting_stub_needed (struct bfd_li
/* Ignore other undefined symbols. */
continue;
- /* Assume branches to other sections not included in the link need
- stubs too, to cover -R and absolute syms. */
+ /* Assume branches to other sections not included in the
+ link need stubs too, to cover -R and absolute syms. */
if (sym_sec->output_section == NULL)
{
ret = 1;
@@ -10282,16 +10283,15 @@ toc_adjusting_stub_needed (struct bfd_li
break;
}
- /* If calling back to a section in the process of being tested, we
- can't say for sure that no toc adjusting stubs are needed, so
- don't return zero. */
+ /* If calling back to a section in the process of being
+ tested, we can't say for sure that no toc adjusting stubs
+ are needed, so don't return zero. */
else if (sym_sec->call_check_in_progress)
ret = 2;
/* Branches to another section that itself doesn't have any TOC
references are OK. Recursively call ourselves to check. */
- else if (sym_sec->id <= htab->top_id
- && htab->stub_group[sym_sec->id].toc_off == 0)
+ else if (!sym_sec->call_check_done)
{
int recur;
@@ -10302,36 +10302,44 @@ toc_adjusting_stub_needed (struct bfd_li
recur = toc_adjusting_stub_needed (info, sym_sec);
isec->call_check_in_progress = 0;
- if (recur < 0)
- {
- /* An error. Exit. */
- ret = -1;
- break;
- }
- else if (recur <= 1)
- {
- /* Known result. Mark as checked and set section flag. */
- htab->stub_group[sym_sec->id].toc_off = 1;
if (recur != 0)
{
- sym_sec->makes_toc_func_call = 1;
- ret = 1;
+ ret = recur;
+ if (recur != 2)
break;
}
}
- else
- {
- /* Unknown result. Continue checking. */
- ret = 2;
- }
- }
}
if (local_syms != NULL
- && (elf_symtab_hdr (isec->owner).contents != (unsigned char *) local_syms))
+ && (elf_symtab_hdr (isec->owner).contents
+ != (unsigned char *) local_syms))
free (local_syms);
if (elf_section_data (isec)->relocs != relstart)
free (relstart);
+ }
+
+ if ((ret & 1) == 0
+ && isec->map_head.s != NULL
+ && (strcmp (isec->output_section->name, ".init") == 0
+ || strcmp (isec->output_section->name, ".fini") == 0))
+ {
+ if (isec->map_head.s->has_toc_reloc
+ || isec->map_head.s->makes_toc_func_call)
+ ret = 1;
+ else if (!isec->map_head.s->call_check_done)
+ {
+ int recur;
+ isec->call_check_in_progress = 1;
+ recur = toc_adjusting_stub_needed (info, isec->map_head.s);
+ isec->call_check_in_progress = 0;
+ if (recur != 0)
+ ret = recur;
+ }
+ }
+
+ if (ret == 1)
+ isec->makes_toc_func_call = 1;
return ret;
}
@@ -10377,23 +10385,55 @@ ppc64_elf_next_input_section (struct bfd
if (elf_gp (isec->owner) != 0)
htab->toc_curr = elf_gp (isec->owner);
}
- else if (htab->stub_group[isec->id].toc_off == 0)
- {
- int ret = toc_adjusting_stub_needed (info, isec);
- if (ret < 0)
+ else if (!isec->call_check_done
+ && toc_adjusting_stub_needed (info, isec) < 0)
return FALSE;
- else
- isec->makes_toc_func_call = ret & 1;
- }
}
/* Functions that don't use the TOC can belong in any TOC group.
Use the last TOC base. This happens to make _init and _fini
- pasting work. */
+ pasting work, because the fragments generally don't use the TOC. */
htab->stub_group[isec->id].toc_off = htab->toc_curr;
return TRUE;
}
+/* Check that all .init and .fini sections use the same toc, if they
+ have toc relocs. */
+
+static bfd_boolean
+check_pasted_section (struct bfd_link_info *info, const char *name)
+{
+ asection *o = bfd_get_section_by_name (info->output_bfd, name);
+
+ if (o != NULL)
+ {
+ struct ppc_link_hash_table *htab = ppc_hash_table (info);
+ bfd_vma toc_off = 0;
+ asection *i;
+
+ for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+ if (i->has_toc_reloc)
+ {
+ if (toc_off == 0)
+ toc_off = htab->stub_group[i->id].toc_off;
+ else if (toc_off != htab->stub_group[i->id].toc_off)
+ return FALSE;
+ }
+ /* Make sure the whole pasted function uses the same toc offset. */
+ if (toc_off != 0)
+ for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+ htab->stub_group[i->id].toc_off = toc_off;
+ }
+ return TRUE;
+}
+
+bfd_boolean
+ppc64_elf_check_init_fini (struct bfd_link_info *info)
+{
+ return (check_pasted_section (info, ".init")
+ & check_pasted_section (info, ".fini"));
+}
+
/* See whether we can group stub sections together. Grouping stub
sections may result in fewer stubs. More importantly, we need to
put all .init* and .fini* stubs at the beginning of the .init or
Index: bfd/elf64-ppc.h
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.h,v
retrieving revision 1.28
diff -u -p -r1.28 elf64-ppc.h
--- bfd/elf64-ppc.h 8 Feb 2010 13:50:16 -0000 1.28
+++ bfd/elf64-ppc.h 14 Mar 2010 01:45:57 -0000
@@ -42,6 +42,8 @@ bfd_boolean ppc64_elf_layout_multitoc
(struct bfd_link_info *);
void ppc64_elf_finish_multitoc_partition
(struct bfd_link_info *);
+bfd_boolean ppc64_elf_check_init_fini
+ (struct bfd_link_info *);
bfd_boolean ppc64_elf_next_input_section
(struct bfd_link_info *, asection *);
bfd_boolean ppc64_elf_size_stubs
Index: ld/emultempl/ppc64elf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/ppc64elf.em,v
retrieving revision 1.68
diff -u -p -r1.68 ppc64elf.em
--- ld/emultempl/ppc64elf.em 8 Feb 2010 13:50:17 -0000 1.68
+++ ld/emultempl/ppc64elf.em 14 Mar 2010 01:45:57 -0000
@@ -346,6 +346,9 @@ gld${EMULATION_NAME}_after_allocation (v
lang_for_each_statement (build_section_lists);
+ if (!ppc64_elf_check_init_fini (&link_info))
+ einfo ("%P: .init/.fini fragments use differing TOC pointers\n");
+
/* Call into the BFD backend to do the real work. */
if (!ppc64_elf_size_stubs (&link_info, group_size))
einfo ("%X%P: can not size stub section: %E\n");
--
Alan Modra
Australia Development Lab, IBM