Index PowerPC64 linker generated .eh_frame in .eh_frame_hdr

I noticed recently that .eh_frame FDEs generated by the linker for
call stubs and .glink weren't being indexed in .eh_frame_hdr, due to
bfd_elf_discard_info being run before the linker generated .eh_frame
sections were available for parsing.  This patch moves code around in
elf64-ppc.c and ppc64elf.em to avoid that problem.

Another problem fixed here is that --gc-sections parses .eh_frame
early, and the existing machinery allows only one go at parsing the
.eh_frame sections.  That resulted in the linker generated .eh_frame
CIEs not being merged and no .eh_frame_hdr index entries for those
FDEs.  It turns out that all the info from parsing .eh_frame is
attached to the section, so order of parsing isn't important, and
after parsing sec_info_type being set will prevent a section being
parsed again.  At least, when parsing doesn't hit an error.  So there
isn't really any need for "parsed_eh_frame".  "merge_cies" is also
redundant, which means _bfd_elf_{begin,end}_eh_frame_parsing can also
disappear.

bfd/
	* elf-bfd.h (struct eh_frame_hdr_info): Delete merge_cies and
	parsed_eh_frames.
	(_bfd_elf_begin_eh_frame_parsing): Delete.
	(_bfd_elf_end_eh_frame_parsing): Delete.
	* elf-eh-frame.c (_bfd_elf_begin_eh_frame_parsing): Delete.
	(_bfd_elf_end_eh_frame_parsing): Delete.
	(_bfd_elf_parse_eh_frame): Don't test parsed_eh_frame.  Test
	!info->relocatable in place of merge_cies.
	* elflink.c (bfd_elf_gc_sections, bfd_elf_discard_info): Adjust.
	* elf64-ppc.c (glink_eh_frame_cie): Pad to multiple of 8.
	(ppc64_elf_size_stubs): Likewise pad stub FDE.
	(ppc64_elf_build_stubs): Move code setting glink .eh_frame to..
	(ppc64_elf_size_stubs): ..here and..
	(ppc64_elf_finish_dynamic_sections): ..here.
ld/
	* emultempl/ppc64elf.em (gld${EMULATION_NAME}_after_allocation): Call
	bfd_elf_discard_info after generating glink .eh_frame.  Delete
	redundant test on ppc64_elf_setup_section_lists status.
This commit is contained in:
Alan Modra 2014-08-22 09:07:35 +09:30
parent 7f85237141
commit da44f4e546
7 changed files with 210 additions and 183 deletions

View file

@ -1,3 +1,20 @@
2014-08-22 Alan Modra <amodra@gmail.com>
* elf-bfd.h (struct eh_frame_hdr_info): Delete merge_cies and
parsed_eh_frames.
(_bfd_elf_begin_eh_frame_parsing): Delete.
(_bfd_elf_end_eh_frame_parsing): Delete.
* elf-eh-frame.c (_bfd_elf_begin_eh_frame_parsing): Delete.
(_bfd_elf_end_eh_frame_parsing): Delete.
(_bfd_elf_parse_eh_frame): Don't test parsed_eh_frame. Test
!info->relocatable in place of merge_cies.
* elflink.c (bfd_elf_gc_sections, bfd_elf_discard_info): Adjust.
* elf64-ppc.c (glink_eh_frame_cie): Pad to multiple of 8.
(ppc64_elf_size_stubs): Likewise pad stub FDE.
(ppc64_elf_build_stubs): Move code setting glink .eh_frame to..
(ppc64_elf_size_stubs): ..here and..
(ppc64_elf_finish_dynamic_sections): ..here.
2014-08-21 Maciej W. Rozycki <macro@codesourcery.com>
* elf64-ppc.h (ppc64_elf_set_toc): Fix indentation.

View file

@ -383,10 +383,6 @@ struct eh_frame_hdr_info
asection *hdr_sec;
unsigned int fde_count, array_count;
struct eh_frame_array_ent *array;
/* TRUE if we should try to merge CIEs between input sections. */
bfd_boolean merge_cies;
/* TRUE if all .eh_frames have been parsd. */
bfd_boolean parsed_eh_frames;
/* TRUE if .eh_frame_hdr should contain the sorted search table.
We build it if we successfully read all .eh_frame input sections
and recognize them. */
@ -1968,13 +1964,8 @@ extern bfd_boolean _bfd_elf_strtab_emit
extern void _bfd_elf_strtab_finalize
(struct elf_strtab_hash *);
extern void _bfd_elf_begin_eh_frame_parsing
(struct bfd_link_info *info);
extern void _bfd_elf_parse_eh_frame
(bfd *, struct bfd_link_info *, asection *, struct elf_reloc_cookie *);
extern void _bfd_elf_end_eh_frame_parsing
(struct bfd_link_info *info);
extern bfd_boolean _bfd_elf_discard_section_eh_frame
(bfd *, struct bfd_link_info *, asection *,
bfd_boolean (*) (bfd_vma, void *), struct elf_reloc_cookie *);

View file

@ -452,18 +452,6 @@ make_pc_relative (unsigned char encoding, unsigned int ptr_size)
return encoding | DW_EH_PE_pcrel;
}
/* Called before calling _bfd_elf_parse_eh_frame on every input bfd's
.eh_frame section. */
void
_bfd_elf_begin_eh_frame_parsing (struct bfd_link_info *info)
{
struct eh_frame_hdr_info *hdr_info;
hdr_info = &elf_hash_table (info)->eh_info;
hdr_info->merge_cies = !info->relocatable;
}
/* Try to parse .eh_frame section SEC, which belongs to ABFD. Store the
information in the section's sec_info field on success. COOKIE
describes the relocations in SEC. */
@ -494,8 +482,6 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
htab = elf_hash_table (info);
hdr_info = &htab->eh_info;
if (hdr_info->parsed_eh_frames)
return;
if (sec->size == 0
|| sec->sec_info_type != SEC_INFO_TYPE_NONE)
@ -777,7 +763,8 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
buf += initial_insn_length;
ENSURE_NO_RELOCS (buf);
if (hdr_info->merge_cies)
if (!info->relocatable)
/* Keep info for merging cies. */
this_inf->u.cie.u.full_cie = cie;
this_inf->u.cie.per_encoding_relative
= (cie->per_encoding & 0x70) == DW_EH_PE_pcrel;
@ -911,8 +898,9 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
elf_section_data (sec)->sec_info = sec_info;
sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME;
if (hdr_info->merge_cies)
if (!info->relocatable)
{
/* Keep info for merging cies. */
sec_info->cies = local_cies;
local_cies = NULL;
}
@ -933,17 +921,6 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
#undef REQUIRE
}
/* Finish a pass over all .eh_frame sections. */
void
_bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info)
{
struct eh_frame_hdr_info *hdr_info;
hdr_info = &elf_hash_table (info)->eh_info;
hdr_info->parsed_eh_frames = TRUE;
}
/* Mark all relocations against CIE or FDE ENT, which occurs in
.eh_frame section SEC. COOKIE describes the relocations in SEC;
its "rel" field can be changed freely. */

View file

@ -11894,7 +11894,8 @@ static const unsigned char glink_eh_frame_cie[] =
65, /* RA reg. */
1, /* Augmentation size. */
DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */
DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */
DW_CFA_def_cfa, 1, 0, /* def_cfa: r1 offset 0. */
0, 0, 0, 0
};
/* Stripping output sections is normally done before dynamic section
@ -12326,7 +12327,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
size += 20;
size += 24;
if (htab->glink != NULL && htab->glink->size != 0)
size += 24;
if (size != 0)
@ -12366,6 +12367,89 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
(*htab->params->layout_sections_again) ();
}
if (htab->glink_eh_frame != NULL
&& htab->glink_eh_frame->size != 0)
{
bfd_vma val;
bfd_byte *p, *last_fde;
size_t last_fde_len, size, align, pad;
asection *stub_sec;
p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
if (p == NULL)
return FALSE;
htab->glink_eh_frame->contents = p;
last_fde = p;
memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
/* CIE length (rewrite in case little-endian). */
last_fde_len = sizeof (glink_eh_frame_cie) - 4;
bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
p += sizeof (glink_eh_frame_cie);
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
last_fde = p;
last_fde_len = 20;
/* FDE length. */
bfd_put_32 (htab->elf.dynobj, 20, p);
p += 4;
/* CIE pointer. */
val = p - htab->glink_eh_frame->contents;
bfd_put_32 (htab->elf.dynobj, val, p);
p += 4;
/* Offset to stub section, written later. */
p += 4;
/* stub section size. */
bfd_put_32 (htab->elf.dynobj, stub_sec->size, p);
p += 4;
/* Augmentation. */
p += 1;
/* Pad. */
p += 7;
}
if (htab->glink != NULL && htab->glink->size != 0)
{
last_fde = p;
last_fde_len = 20;
/* FDE length. */
bfd_put_32 (htab->elf.dynobj, 20, p);
p += 4;
/* CIE pointer. */
val = p - htab->glink_eh_frame->contents;
bfd_put_32 (htab->elf.dynobj, val, p);
p += 4;
/* Offset to .glink, written later. */
p += 4;
/* .glink size. */
bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p);
p += 4;
/* Augmentation. */
p += 1;
*p++ = DW_CFA_advance_loc + 1;
*p++ = DW_CFA_register;
*p++ = 65;
*p++ = 12;
*p++ = DW_CFA_advance_loc + 4;
*p++ = DW_CFA_restore_extended;
*p++ = 65;
}
/* Subsume any padding into the last FDE if user .eh_frame
sections are aligned more than glink_eh_frame. Otherwise any
zero padding will be seen as a terminator. */
size = p - htab->glink_eh_frame->contents;
align = 1;
align <<= htab->glink_eh_frame->output_section->alignment_power;
align -= 1;
pad = ((size + align) & ~align) - size;
htab->glink_eh_frame->size = size + pad;
bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
}
maybe_strip_output (info, htab->brlt);
if (htab->glink_eh_frame != NULL)
maybe_strip_output (info, htab->glink_eh_frame);
@ -12723,117 +12807,6 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
return FALSE;
}
if (htab->glink_eh_frame != NULL
&& htab->glink_eh_frame->size != 0)
{
bfd_vma val;
bfd_byte *last_fde;
size_t last_fde_len, size, align, pad;
p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
if (p == NULL)
return FALSE;
htab->glink_eh_frame->contents = p;
last_fde = p;
htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
/* CIE length (rewrite in case little-endian). */
last_fde_len = sizeof (glink_eh_frame_cie) - 4;
bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
p += sizeof (glink_eh_frame_cie);
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
last_fde = p;
last_fde_len = 16;
/* FDE length. */
bfd_put_32 (htab->elf.dynobj, 16, p);
p += 4;
/* CIE pointer. */
val = p - htab->glink_eh_frame->contents;
bfd_put_32 (htab->elf.dynobj, val, p);
p += 4;
/* Offset to stub section. */
val = (stub_sec->output_section->vma
+ stub_sec->output_offset);
val -= (htab->glink_eh_frame->output_section->vma
+ htab->glink_eh_frame->output_offset);
val -= p - htab->glink_eh_frame->contents;
if (val + 0x80000000 > 0xffffffff)
{
info->callbacks->einfo
(_("%P: %s offset too large for .eh_frame sdata4 encoding"),
stub_sec->name);
return FALSE;
}
bfd_put_32 (htab->elf.dynobj, val, p);
p += 4;
/* stub section size. */
bfd_put_32 (htab->elf.dynobj, stub_sec->rawsize, p);
p += 4;
/* Augmentation. */
p += 1;
/* Pad. */
p += 3;
}
if (htab->glink != NULL && htab->glink->size != 0)
{
last_fde = p;
last_fde_len = 20;
/* FDE length. */
bfd_put_32 (htab->elf.dynobj, 20, p);
p += 4;
/* CIE pointer. */
val = p - htab->glink_eh_frame->contents;
bfd_put_32 (htab->elf.dynobj, val, p);
p += 4;
/* Offset to .glink. */
val = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ 8);
val -= (htab->glink_eh_frame->output_section->vma
+ htab->glink_eh_frame->output_offset);
val -= p - htab->glink_eh_frame->contents;
if (val + 0x80000000 > 0xffffffff)
{
info->callbacks->einfo
(_("%P: %s offset too large for .eh_frame sdata4 encoding"),
htab->glink->name);
return FALSE;
}
bfd_put_32 (htab->elf.dynobj, val, p);
p += 4;
/* .glink size. */
bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p);
p += 4;
/* Augmentation. */
p += 1;
*p++ = DW_CFA_advance_loc + 1;
*p++ = DW_CFA_register;
*p++ = 65;
*p++ = 12;
*p++ = DW_CFA_advance_loc + 4;
*p++ = DW_CFA_restore_extended;
*p++ = 65;
}
/* Subsume any padding into the last FDE if user .eh_frame
sections are aligned more than glink_eh_frame. Otherwise any
zero padding will be seen as a terminator. */
size = p - htab->glink_eh_frame->contents;
align = 1;
align <<= htab->glink_eh_frame->output_section->alignment_power;
align -= 1;
pad = ((size + align) & ~align) - size;
htab->glink_eh_frame->size = size + pad;
bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
}
/* Build the stubs as directed by the stub hash table. */
bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
@ -12859,6 +12832,9 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
break;
}
/* Note that the glink_eh_frame check here is not only testing that
the generated size matched the calculated size but also that
bfd_elf_discard_info didn't make any changes to the section. */
if (stub_sec != NULL
|| (htab->glink_eh_frame != NULL
&& htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
@ -15126,13 +15102,81 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
NULL))
return FALSE;
if (htab->glink_eh_frame != NULL
&& htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
&& !_bfd_elf_write_section_eh_frame (output_bfd, info,
htab->glink_eh_frame,
htab->glink_eh_frame->contents))
return FALSE;
&& htab->glink_eh_frame->size != 0)
{
bfd_vma val;
bfd_byte *p;
asection *stub_sec;
p = htab->glink_eh_frame->contents + sizeof (glink_eh_frame_cie);
for (stub_sec = htab->params->stub_bfd->sections;
stub_sec != NULL;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
/* FDE length. */
p += 4;
/* CIE pointer. */
p += 4;
/* Offset to stub section. */
val = (stub_sec->output_section->vma
+ stub_sec->output_offset);
val -= (htab->glink_eh_frame->output_section->vma
+ htab->glink_eh_frame->output_offset
+ (p - htab->glink_eh_frame->contents));
if (val + 0x80000000 > 0xffffffff)
{
info->callbacks->einfo
(_("%P: %s offset too large for .eh_frame sdata4 encoding"),
stub_sec->name);
return FALSE;
}
bfd_put_32 (dynobj, val, p);
p += 4;
/* stub section size. */
p += 4;
/* Augmentation. */
p += 1;
/* Pad. */
p += 7;
}
if (htab->glink != NULL && htab->glink->size != 0)
{
/* FDE length. */
p += 4;
/* CIE pointer. */
p += 4;
/* Offset to .glink. */
val = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ 8);
val -= (htab->glink_eh_frame->output_section->vma
+ htab->glink_eh_frame->output_offset
+ (p - htab->glink_eh_frame->contents));
if (val + 0x80000000 > 0xffffffff)
{
info->callbacks->einfo
(_("%P: %s offset too large for .eh_frame sdata4 encoding"),
htab->glink->name);
return FALSE;
}
bfd_put_32 (dynobj, val, p);
p += 4;
/* .glink size. */
p += 4;
/* Augmentation. */
p += 1;
/* Ops. */
p += 7;
}
if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
&& !_bfd_elf_write_section_eh_frame (output_bfd, info,
htab->glink_eh_frame,
htab->glink_eh_frame->contents))
return FALSE;
}
/* We need to handle writing out multiple GOT sections ourselves,
since we didn't add them to DYNOBJ. We know dynobj is the first

View file

@ -12154,6 +12154,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
bfd *sub;
elf_gc_mark_hook_fn gc_mark_hook;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_link_hash_table *htab;
if (!bed->can_gc_sections
|| !is_elf_hash_table (info->hash))
@ -12163,10 +12164,10 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
}
bed->gc_keep (info);
htab = elf_hash_table (info);
/* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section
at the .eh_frame section if we can mark the FDEs individually. */
_bfd_elf_begin_eh_frame_parsing (info);
for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
{
asection *sec;
@ -12183,27 +12184,20 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
sec = bfd_get_next_section_by_name (sec);
}
}
_bfd_elf_end_eh_frame_parsing (info);
/* Apply transitive closure to the vtable entry usage info. */
elf_link_hash_traverse (elf_hash_table (info),
elf_gc_propagate_vtable_entries_used,
&ok);
elf_link_hash_traverse (htab, elf_gc_propagate_vtable_entries_used, &ok);
if (!ok)
return FALSE;
/* Kill the vtable relocations that were not used. */
elf_link_hash_traverse (elf_hash_table (info),
elf_gc_smash_unused_vtentry_relocs,
&ok);
elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok);
if (!ok)
return FALSE;
/* Mark dynamically referenced symbols. */
if (elf_hash_table (info)->dynamic_sections_created)
elf_link_hash_traverse (elf_hash_table (info),
bed->gc_mark_dynamic_ref,
info);
if (htab->dynamic_sections_created)
elf_link_hash_traverse (htab, bed->gc_mark_dynamic_ref, info);
/* Grovel through relocs to find out who stays ... */
gc_mark_hook = bed->gc_mark_hook;
@ -12682,7 +12676,6 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
{
asection *i;
_bfd_elf_begin_eh_frame_parsing (info);
for (i = o->map_head.s; i != NULL; i = i->map_head.s)
{
if (i->size == 0)
@ -12703,7 +12696,6 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
fini_reloc_cookie_for_section (&cookie, i);
}
_bfd_elf_end_eh_frame_parsing (info);
}
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)

View file

@ -1,3 +1,9 @@
2014-08-22 Alan Modra <amodra@gmail.com>
* emultempl/ppc64elf.em (gld${EMULATION_NAME}_after_allocation): Call
bfd_elf_discard_info after generating glink .eh_frame. Delete
redundant test on ppc64_elf_setup_section_lists status.
2014-08-20 Maciej W. Rozycki <macro@codesourcery.com>
* emultempl/armelf.em (OPTION_STUBGROUP_SIZE): Fix formatting.

View file

@ -460,19 +460,6 @@ gld${EMULATION_NAME}_after_allocation (void)
{
int ret;
/* bfd_elf_discard_info just plays with data and debugging sections,
ie. doesn't affect code size, so we can delay resizing the
sections. It's likely we'll resize everything in the process of
adding stubs. */
ret = bfd_elf_discard_info (link_info.output_bfd, &link_info);
if (ret < 0)
{
einfo ("%X%P: .eh_frame/.stab edit: %E\n");
return;
}
else if (ret > 0)
need_laying_out = 1;
/* If generating a relocatable output file, then we don't have any
stubs. */
if (stub_file != NULL && !link_info.relocatable)
@ -480,7 +467,7 @@ gld${EMULATION_NAME}_after_allocation (void)
ret = ppc64_elf_setup_section_lists (&link_info);
if (ret < 0)
einfo ("%X%P: can not size stub section: %E\n");
else if (ret > 0)
else
{
ppc64_elf_start_multitoc_partition (&link_info);
@ -510,6 +497,19 @@ gld${EMULATION_NAME}_after_allocation (void)
}
}
/* We can't parse and merge .eh_frame until the glink .eh_frame has
been generated. Otherwise the glink .eh_frame CIE won't be
merged with other CIEs, and worse, the glink .eh_frame FDEs won't
be listed in .eh_frame_hdr. */
ret = bfd_elf_discard_info (link_info.output_bfd, &link_info);
if (ret < 0)
{
einfo ("%X%P: .eh_frame/.stab edit: %E\n");
return;
}
else if (ret > 0)
need_laying_out = 1;
if (need_laying_out != -1)
{
gld${EMULATION_NAME}_map_segments (need_laying_out);