This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]