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.
This commit is contained in:
Alan Modra
2010-03-14 07:05:36 +00:00
parent 005c61b77b
commit 70cc837dbe
5 changed files with 236 additions and 171 deletions

View File

@ -1,3 +1,17 @@
2010-03-14 Alan Modra <amodra@gmail.com>
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.
2010-03-13 Alan Modra <amodra@gmail.com> 2010-03-13 Alan Modra <amodra@gmail.com>
PR ld/11375 PR ld/11375

View File

@ -3820,6 +3820,7 @@ struct ppc_link_hash_table
/* Recursion protection when determining above flag. */ /* Recursion protection when determining above flag. */
#define call_check_in_progress sec_flg4 #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. */ /* 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 (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
; ;
else if (*sec != NULL 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); isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
return TRUE; return TRUE;
@ -4880,7 +4881,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
sreloc = NULL; sreloc = NULL;
opd_sym_map = 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. /* Garbage collection needs some extra help with .opd sections.
We don't want to necessarily keep everything referenced by We don't want to necessarily keep everything referenced by
@ -8811,7 +8812,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
/* Strip this section if we don't need it; see the /* Strip this section if we don't need it; see the
comment below. */ comment below. */
} }
else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) else if (CONST_STRNEQ (s->name, ".rela"))
{ {
if (s->size != 0) if (s->size != 0)
{ {
@ -10125,9 +10126,6 @@ ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info)
{ {
struct ppc_link_hash_table *htab = ppc_hash_table (info); 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 /* After the second pass, toc_curr tracks the TOC offset used
for code sections below in ppc64_elf_next_input_section. */ for code sections below in ppc64_elf_next_input_section. */
htab->toc_curr = TOC_BASE_OFF; htab->toc_curr = TOC_BASE_OFF;
@ -10144,10 +10142,10 @@ ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info)
static int static int
toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
{ {
Elf_Internal_Rela *relstart, *rel;
Elf_Internal_Sym *local_syms;
int ret; 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. */ /* We know none of our code bearing sections will need toc stubs. */
if ((isec->flags & SEC_LINKER_CREATED) != 0) if ((isec->flags & SEC_LINKER_CREATED) != 0)
@ -10159,8 +10157,12 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
if (isec->output_section == NULL) if (isec->output_section == NULL)
return 0; return 0;
if (isec->reloc_count == 0) ret = 0;
return 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, relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL,
info->keep_memory); info->keep_memory);
@ -10169,7 +10171,6 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
/* Look for branches to outside of this section. */ /* Look for branches to outside of this section. */
local_syms = NULL; local_syms = NULL;
ret = 0;
htab = ppc_hash_table (info); htab = ppc_hash_table (info);
if (htab == NULL) if (htab == NULL)
return -1; return -1;
@ -10217,8 +10218,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
/* Ignore other undefined symbols. */ /* Ignore other undefined symbols. */
continue; continue;
/* Assume branches to other sections not included in the link need /* Assume branches to other sections not included in the
stubs too, to cover -R and absolute syms. */ link need stubs too, to cover -R and absolute syms. */
if (sym_sec->output_section == NULL) if (sym_sec->output_section == NULL)
{ {
ret = 1; ret = 1;
@ -10282,16 +10283,15 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
break; break;
} }
/* If calling back to a section in the process of being tested, we /* If calling back to a section in the process of being
can't say for sure that no toc adjusting stubs are needed, so tested, we can't say for sure that no toc adjusting stubs
don't return zero. */ are needed, so don't return zero. */
else if (sym_sec->call_check_in_progress) else if (sym_sec->call_check_in_progress)
ret = 2; ret = 2;
/* Branches to another section that itself doesn't have any TOC /* Branches to another section that itself doesn't have any TOC
references are OK. Recursively call ourselves to check. */ references are OK. Recursively call ourselves to check. */
else if (sym_sec->id <= htab->top_id else if (!sym_sec->call_check_done)
&& htab->stub_group[sym_sec->id].toc_off == 0)
{ {
int recur; int recur;
@ -10302,36 +10302,44 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
recur = toc_adjusting_stub_needed (info, sym_sec); recur = toc_adjusting_stub_needed (info, sym_sec);
isec->call_check_in_progress = 0; 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) if (recur != 0)
{ {
sym_sec->makes_toc_func_call = 1; ret = recur;
ret = 1; if (recur != 2)
break; break;
} }
} }
else
{
/* Unknown result. Continue checking. */
ret = 2;
}
}
} }
if (local_syms != NULL 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); free (local_syms);
if (elf_section_data (isec)->relocs != relstart) if (elf_section_data (isec)->relocs != relstart)
free (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; return ret;
} }
@ -10377,23 +10385,55 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
if (elf_gp (isec->owner) != 0) if (elf_gp (isec->owner) != 0)
htab->toc_curr = elf_gp (isec->owner); htab->toc_curr = elf_gp (isec->owner);
} }
else if (htab->stub_group[isec->id].toc_off == 0) else if (!isec->call_check_done
{ && toc_adjusting_stub_needed (info, isec) < 0)
int ret = toc_adjusting_stub_needed (info, isec);
if (ret < 0)
return FALSE; return FALSE;
else
isec->makes_toc_func_call = ret & 1;
}
} }
/* Functions that don't use the TOC can belong in any TOC group. /* 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 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; htab->stub_group[isec->id].toc_off = htab->toc_curr;
return TRUE; 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 /* See whether we can group stub sections together. Grouping stub
sections may result in fewer stubs. More importantly, we need to sections may result in fewer stubs. More importantly, we need to
put all .init* and .fini* stubs at the beginning of the .init or put all .init* and .fini* stubs at the beginning of the .init or

View File

@ -42,6 +42,8 @@ bfd_boolean ppc64_elf_layout_multitoc
(struct bfd_link_info *); (struct bfd_link_info *);
void ppc64_elf_finish_multitoc_partition void ppc64_elf_finish_multitoc_partition
(struct bfd_link_info *); (struct bfd_link_info *);
bfd_boolean ppc64_elf_check_init_fini
(struct bfd_link_info *);
bfd_boolean ppc64_elf_next_input_section bfd_boolean ppc64_elf_next_input_section
(struct bfd_link_info *, asection *); (struct bfd_link_info *, asection *);
bfd_boolean ppc64_elf_size_stubs bfd_boolean ppc64_elf_size_stubs

View File

@ -1,3 +1,9 @@
2010-03-14 Alan Modra <amodra@gmail.com>
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.
2010-03-11 George Gensure <werkt0@gmail.com> 2010-03-11 George Gensure <werkt0@gmail.com>
PR ld/11367 PR ld/11367

View File

@ -346,6 +346,9 @@ gld${EMULATION_NAME}_after_allocation (void)
lang_for_each_statement (build_section_lists); 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. */ /* Call into the BFD backend to do the real work. */
if (!ppc64_elf_size_stubs (&link_info, group_size)) if (!ppc64_elf_size_stubs (&link_info, group_size))
einfo ("%X%P: can not size stub section: %E\n"); einfo ("%X%P: can not size stub section: %E\n");