This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: RFC: Unwind info for PLT
On Mon, Jun 13, 2011 at 01:53:38PM -0700, Ian Lance Taylor wrote:
> Richard Henderson <rth@redhat.com> writes:
>
> > On 06/13/2011 10:13 AM, Jakub Jelinek wrote:
> >> Yeah, easier to write and easier to change. Anyway, if you prefer to do
> >> it in ld, I can try to do it there. Just a question, should it be done
> >> unconditionally, or guarded with some ld cmdline option (either existing one, like
> >> abuse --eh-frame-hdr for it, or a new one)?
> >
> > I don't have a real preference. I could see abusing --eh-frame-hdr makes sense.
>
> I believe the default should be to generate the additional new unwind
> information. The only people who would not want it would be people who
> want to minimize their binary size. I also don't think this has
> anything to do with --eh-frame-hdr, which simply directs the linker to
> create a PT_GNU_EH_FRAME program header. So I think there should be a
> new linker option to *not* generate unwind info, and we should have
> -fno-unwind-tables pass that option to a linker which understands it.
Ok, here is a WIP patch which seems to work in light testing on x86_64.
It doesn't have yet an option to force no generation of the unwind info,
and some testcases (especially for TLS transitions) will either need
to be adjusted or get passed the new option to prevent .eh_frame for
.plt, as the 16 byte instead of 4 byte alignment of .plt section
shifted various offsets in those.
2011-06-14 Jakub Jelinek <jakub@redhat.com>
* elf-eh-frame.c (_bfd_elf_parse_eh_frame): Allow no relocations
at all for linker created .eh_frame sections.
(_bfd_elf_discard_section_eh_frame): Handle linker created
.eh_frame sections with no relocations.
* elf64-x86-64.c: Include dwarf2.h.
(elf_x86_64_eh_frame_plt): New variable.
(PLT_CIE_LENGTH, PLT_FDE_LENGTH, PLT_FDE_START_OFFSET,
PLT_FDE_LEN_OFFSET): Define.
(struct elf_x86_64_link_hash_table): Add plt_eh_frame field.
(elf_x86_64_create_dynamic_sections): Create and fill in
.eh_frame section for .plt section.
(elf_x86_64_size_dynamic_sections): Write .plt section size
into .eh_frame FDE covering .plt section.
(elf_x86_64_finish_dynamic_sections): Write .plt section
start into .eh_frame FDE covering .plt section. Call
_bfd_elf_write_section_eh_frame on htab->plt_eh_frame section.
(elf_backend_plt_alignment): Define to 4.
--- bfd/elf-eh-frame.c.jj 2011-03-16 10:27:06.000000000 +0100
+++ bfd/elf-eh-frame.c 2011-06-14 20:33:15.000000000 +0200
@@ -777,8 +777,6 @@ _bfd_elf_parse_eh_frame (bfd *abfd, stru
}
else
{
- asection *rsec;
-
/* Find the corresponding CIE. */
unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
for (cie = local_cies; cie < local_cies + cie_count; cie++)
@@ -794,17 +792,22 @@ _bfd_elf_parse_eh_frame (bfd *abfd, stru
= cie->cie_inf->add_augmentation_size;
ENSURE_NO_RELOCS (buf);
- REQUIRE (GET_RELOC (buf));
-
- /* Chain together the FDEs for each section. */
- rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
- /* RSEC will be NULL if FDE was cleared out as it was belonging to
- a discarded SHT_GROUP. */
- if (rsec)
+ if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL)
{
- REQUIRE (rsec->owner == abfd);
- this_inf->u.fde.next_for_section = elf_fde_list (rsec);
- elf_fde_list (rsec) = this_inf;
+ asection *rsec;
+
+ REQUIRE (GET_RELOC (buf));
+
+ /* Chain together the FDEs for each section. */
+ rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
+ /* RSEC will be NULL if FDE was cleared out as it was belonging to
+ a discarded SHT_GROUP. */
+ if (rsec)
+ {
+ REQUIRE (rsec->owner == abfd);
+ this_inf->u.fde.next_for_section = elf_fde_list (rsec);
+ elf_fde_list (rsec) = this_inf;
+ }
}
/* Skip the initial location and address range. */
@@ -1137,6 +1140,9 @@ _bfd_elf_discard_section_eh_frame
if (sec_info == NULL)
return FALSE;
+ ptr_size = (get_elf_backend_data (sec->owner)
+ ->elf_backend_eh_frame_address_size (sec->owner, sec));
+
hdr_info = &elf_hash_table (info)->eh_info;
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
if (ent->size == 4)
@@ -1145,11 +1151,25 @@ _bfd_elf_discard_section_eh_frame
ent->removed = sec->map_head.s != NULL;
else if (!ent->cie)
{
- cookie->rel = cookie->rels + ent->reloc_index;
- /* FIXME: octets_per_byte. */
- BFD_ASSERT (cookie->rel < cookie->relend
- && cookie->rel->r_offset == ent->offset + 8);
- if (!(*reloc_symbol_deleted_p) (ent->offset + 8, cookie))
+ bfd_boolean keep;
+ if ((sec->flags & SEC_LINKER_CREATED) != 0 && cookie->rels == NULL)
+ {
+ unsigned int width
+ = get_DW_EH_PE_width (ent->fde_encoding, ptr_size);
+ bfd_vma value
+ = read_value (abfd, sec->contents + ent->offset + 8 + width,
+ width, get_DW_EH_PE_signed (ent->fde_encoding));
+ keep = value != 0;
+ }
+ else
+ {
+ cookie->rel = cookie->rels + ent->reloc_index;
+ /* FIXME: octets_per_byte. */
+ BFD_ASSERT (cookie->rel < cookie->relend
+ && cookie->rel->r_offset == ent->offset + 8);
+ keep = !(*reloc_symbol_deleted_p) (ent->offset + 8, cookie);
+ }
+ if (keep)
{
if (info->shared
&& (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr
@@ -1178,8 +1198,6 @@ _bfd_elf_discard_section_eh_frame
sec_info->cies = NULL;
}
- ptr_size = (get_elf_backend_data (sec->owner)
- ->elf_backend_eh_frame_address_size (sec->owner, sec));
offset = 0;
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
if (!ent->removed)
--- bfd/elf64-x86-64.c.jj 2011-06-14 08:59:45.000000000 +0200
+++ bfd/elf64-x86-64.c 2011-06-14 22:01:44.000000000 +0200
@@ -29,6 +29,7 @@
#include "bfd_stdint.h"
#include "objalloc.h"
#include "hashtab.h"
+#include "dwarf2.h"
#include "elf/x86-64.h"
@@ -408,6 +409,45 @@ static const bfd_byte elf_x86_64_plt_ent
0, 0, 0, 0 /* replaced with offset to start of .plt0. */
};
+/* .eh_frame covering the .plt section. */
+
+static const bfd_byte elf_x86_64_eh_frame_plt[] =
+{
+#define PLT_CIE_LENGTH 20
+#define PLT_FDE_LENGTH 36
+#define PLT_FDE_START_OFFSET 4 + PLT_CIE_LENGTH + 8
+#define PLT_FDE_LEN_OFFSET 4 + PLT_CIE_LENGTH + 12
+ PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */
+ 0, 0, 0, 0, /* CIE ID */
+ 1, /* CIE version */
+ 'z', 'R', 0, /* Augmentation string */
+ 1, /* Code alignment factor */
+ 0x78, /* Data alignment factor */
+ 16, /* Return address column */
+ 1, /* Augmentation size */
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */
+ DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */
+ DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */
+ DW_CFA_nop, DW_CFA_nop,
+
+ PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */
+ PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */
+ 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */
+ 0, 0, 0, 0, /* .plt size goes here */
+ 0, /* Augmentation size */
+ DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */
+ DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */
+ DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */
+ DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 10 to __PLT__+16 */
+ DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */
+ 11, /* Block length */
+ DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */
+ DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */
+ DW_OP_lit15, DW_OP_and, DW_OP_lit11, DW_OP_ge,
+ DW_OP_lit3, DW_OP_shl, DW_OP_plus,
+ DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
+};
+
/* x86-64 ELF linker hash entry. */
struct elf_x86_64_link_hash_entry
@@ -481,6 +521,7 @@ struct elf_x86_64_link_hash_table
/* Short-cuts to get to dynamic linker sections. */
asection *sdynbss;
asection *srelbss;
+ asection *plt_eh_frame;
union
{
@@ -727,6 +768,23 @@ elf_x86_64_create_dynamic_sections (bfd
|| (!info->shared && !htab->srelbss))
abort ();
+ if (bfd_get_section_by_name (dynobj, ".eh_frame") == NULL
+ && htab->elf.splt != NULL)
+ {
+ flagword flags = get_elf_backend_data (dynobj)->dynamic_sec_flags;
+ htab->plt_eh_frame
+ = bfd_make_section_with_flags (dynobj, ".eh_frame",
+ flags | SEC_READONLY);
+ if (htab->plt_eh_frame == NULL
+ || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 3))
+ return FALSE;
+
+ htab->plt_eh_frame->size = sizeof (elf_x86_64_eh_frame_plt);
+ htab->plt_eh_frame->contents
+ = bfd_alloc (dynobj, htab->plt_eh_frame->size);
+ memcpy (htab->plt_eh_frame->contents, elf_x86_64_eh_frame_plt,
+ sizeof (elf_x86_64_eh_frame_plt));
+ }
return TRUE;
}
@@ -2601,6 +2659,13 @@ elf_x86_64_size_dynamic_sections (bfd *o
return FALSE;
}
+ if (htab->plt_eh_frame != NULL
+ && htab->elf.splt != NULL
+ && htab->elf.splt->size != 0
+ && (htab->elf.splt->flags & SEC_EXCLUDE) == 0)
+ bfd_put_32 (dynobj, htab->elf.splt->size,
+ htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
+
if (htab->elf.dynamic_sections_created)
{
/* Add some entries to the .dynamic section. We fill in the
@@ -4401,6 +4466,33 @@ elf_x86_64_finish_dynamic_sections (bfd
GOT_ENTRY_SIZE;
}
+ /* Adjust .eh_frame for .plt section. */
+ if (htab->plt_eh_frame != NULL)
+ {
+ if (htab->elf.splt != NULL
+ && htab->elf.splt->size != 0
+ && (htab->elf.splt->flags & SEC_EXCLUDE) == 0
+ && htab->elf.splt->output_section != NULL
+ && htab->plt_eh_frame->output_section != NULL)
+ {
+ bfd_vma plt_start = htab->elf.splt->output_section->vma;
+ bfd_vma eh_frame_start = htab->plt_eh_frame->output_section->vma
+ + htab->plt_eh_frame->output_offset
+ + PLT_FDE_START_OFFSET;
+ bfd_put_signed_32 (dynobj, plt_start - eh_frame_start,
+ htab->plt_eh_frame->contents
+ + PLT_FDE_START_OFFSET);
+ }
+ if (htab->plt_eh_frame->sec_info_type
+ == ELF_INFO_TYPE_EH_FRAME)
+ {
+ if (! _bfd_elf_write_section_eh_frame (output_bfd, info,
+ htab->plt_eh_frame,
+ htab->plt_eh_frame->contents))
+ return FALSE;
+ }
+ }
+
if (htab->elf.sgot && htab->elf.sgot->size > 0)
elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize
= GOT_ENTRY_SIZE;
@@ -4667,6 +4759,7 @@ static const struct bfd_elf_special_sect
#define elf_backend_want_plt_sym 0
#define elf_backend_got_header_size (GOT_ENTRY_SIZE*3)
#define elf_backend_rela_normal 1
+#define elf_backend_plt_alignment 4
#define elf_info_to_howto elf_x86_64_info_to_howto
Jakub