This is the mail archive of the binutils@sources.redhat.com 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]

[PATCH] Make ia64 unwind sections corresponding to linkonce functions linkonce as well


Hi!

The following patch puts unwind info for .gnu.linkonce.t.* sections into
.gnu.linkonce.ia64unw{,i}.* so that the redundant copies are removed by the
linker.

In addition to this, it fixes readelf so that it prints all SHT_IA_64_UNWIND
sections, not just the last one with .IA_64.unwind_info as info section.

The EXCLUDE_FILE(*crtend.o) in the linker script is ugly, but necessary,
since apparently *(.IA_64.unwind_info* .gnu.linkonce.ia64unwi.*) does not
work as described in documentation (looking at ldlang.c and ldgram.y there
is really no code to deal with it, so it acts the same as
*(.IA_64.unwind_info*) *(.gnu.linkonce.ia64unwi.*)).
I'll try to deal with it separately.
Tested with:

#include <exception>

void foo()
{
  throw exception();
}

inline void bar()
{
  foo();
}

int main()
{
  try {
    bar();
  } catch (...) {};
}

compiled with -O0 (with some .xdata8 hand adjusted) - it creates exactly
the same binary as without this patch (again, with some .xdata8 hand
adjusted, though in a different way).
Ok to commit?
If this makes it in, I'll post adjusted gcc patch for .xdata8 output.

2001-05-01  Jakub Jelinek  <jakub@redhat.com>

bfd/
	* elfxx-ia64.c (is_unwind_section_name): Consider linkonce unwind
	sections as well.
	(elfNN_ia64_final_write_processing): Map .gnu.linkonce.ia64unw.FOO
	to .gnu.linkonce.t.FOO text section.

binutils/
	* readelf.c (process_unwind): Print all unwind sections, not just
	one.

gas/
	* config/tc-ia64.c (special_linkonce_name): New.
	(make_unw_section): Map .gnu.linkonce.t.FOO text section into
	.gnu.linkonce.ia64unw{,i}.FOO.
	(ia64_elf_section_type): Handle .gnu.linkonce.ia64unw{,i}.FOO.
	(dot_endp): Add comment about it.

include/
	* elf/ia64.h (ELF_STRING_ia64_unwind_once): Define.
	(ELF_STRING_ia64_unwind_info_once): Define.

ld/
	* emulparams/elf64_ia64.sh (OTHER_READONLY_SECTIONS): Put
	.gnu.linkonce.ia64unw{,i} sections into corresponding .IA_64.unwind*
	output sections, make sure crtend.o's .IA_64.unwind section comes
	last.

--- bfd/elfxx-ia64.c.jj	Wed Feb 14 02:32:26 2001
+++ bfd/elfxx-ia64.c	Tue May  1 07:39:57 2001
@@ -910,12 +910,14 @@ static inline boolean
 is_unwind_section_name (name)
 	const char *name;
 {
-  size_t len1, len2;
+  size_t len1, len2, len3;
 
   len1 = sizeof (ELF_STRING_ia64_unwind) - 1;
   len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1;
-  return (strncmp (name, ELF_STRING_ia64_unwind, len1) == 0
-	  && strncmp (name, ELF_STRING_ia64_unwind_info, len2) != 0);
+  len3 = sizeof (ELF_STRING_ia64_unwind_once) - 1;
+  return ((strncmp (name, ELF_STRING_ia64_unwind, len1) == 0
+	   && strncmp (name, ELF_STRING_ia64_unwind_info, len2) != 0)
+	  || strncmp (name, ELF_STRING_ia64_unwind_once, len3) == 0);
 }
 
 /* Handle an IA-64 specific section when reading an object file.  This
@@ -1053,6 +1055,18 @@ elfNN_ia64_final_write_processing (abfd,
 	      else
 		/* .IA_64.unwindFOO -> FOO */
 		text_sect = bfd_get_section_by_name (abfd, sname);
+	    }
+	  else if (sname
+		   && (len = sizeof (ELF_STRING_ia64_unwind_once) - 1,
+		       strncmp (sname, ELF_STRING_ia64_unwind_once, len)) == 0)
+	    {
+	      /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.t.FOO */
+	      size_t len2 = sizeof (".gnu.linkonce.t.") - 1;
+	      char *once_name = alloca (len2 + strlen (sname) - len + 1);
+
+	      memcpy (once_name, ".gnu.linkonce.t.", len2);
+	      strcpy (once_name + len2, sname + len);
+	      text_sect = bfd_get_section_by_name (abfd, once_name);
 	    }
 	  else
 	    /* last resort: fall back on .text */
--- binutils/readelf.c.jj	Sun Feb 11 19:48:25 2001
+++ binutils/readelf.c	Tue May  1 08:32:12 2001
@@ -3372,7 +3372,7 @@ process_unwind (file)
      FILE * file;
 {
   Elf32_Internal_Shdr *sec, *unwsec = NULL, *strsec;
-  unsigned long i, addr_size;
+  unsigned long i, addr_size, unwcount = 0, unwstart = 0;
   struct unw_aux_info aux;
 
   memset (& aux, 0, sizeof (aux));
@@ -3395,40 +3395,100 @@ process_unwind (file)
 			  (char *) aux.strtab, char *, "string table");
 	}
       else if (sec->sh_type == SHT_IA_64_UNWIND)
-	unwsec = sec;
-      else if (strcmp (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info) == 0)
-	{
-	  aux.info_size = sec->sh_size;
-	  aux.info_addr = sec->sh_addr;
-	  GET_DATA_ALLOC (sec->sh_offset, aux.info_size, aux.info,
-			  char *, "unwind info");
-	}
+	unwcount++;
     }
 
-  if (unwsec)
+  if (!unwcount)
+    printf (_("\nThere are no unwind sections in this file.\n"));
+
+  while (unwcount-- > 0)
     {
-      printf (_("\nUnwind section "));
+      char *suffix;
+      size_t len, len2;
+
+      for (i = unwstart, sec = section_headers + unwstart;
+	   i < elf_header.e_shnum; ++i, ++sec)
+	if (sec->sh_type == SHT_IA_64_UNWIND)
+	  {
+	    unwsec = sec;
+	    break;
+	  }
+
+      unwstart = i + 1;
+      len = sizeof (ELF_STRING_ia64_unwind_once) - 1;
 
-      if (string_table == NULL)
-	printf ("%d", unwsec->sh_name);
+      if (strncmp (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once,
+		   len) == 0)
+	{
+	  /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO */
+	  len2 = sizeof (ELF_STRING_ia64_unwind_info_once) - 1;
+	  suffix = SECTION_NAME (unwsec) + len;
+	  for (i = 0, sec = section_headers; i < elf_header.e_shnum;
+	       ++i, ++sec)
+	    if (strncmp (SECTION_NAME (sec),
+			 ELF_STRING_ia64_unwind_info_once, len2) == 0
+		&& strcmp (SECTION_NAME (sec) + len2, suffix) == 0)
+	      break;
+	}
       else
-	printf ("'%s'", SECTION_NAME (unwsec));
+	{
+	  /* .IA_64.unwindFOO -> .IA_64.unwind_infoFOO
+	     .IA_64.unwind or BAR -> .IA_64.unwind_info */
+	  len = sizeof (ELF_STRING_ia64_unwind) - 1;
+	  len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1;
+	  suffix = "";
+	  if (strncmp (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind,
+		       len) == 0)
+	    suffix = SECTION_NAME (unwsec) + len;
+	  for (i = 0, sec = section_headers; i < elf_header.e_shnum;
+	       ++i, ++sec)
+	    if (strncmp (SECTION_NAME (sec),
+			 ELF_STRING_ia64_unwind_info, len2) == 0
+		&& strcmp (SECTION_NAME (sec) + len2, suffix) == 0)
+	      break;
+	}
+
+      if (i == elf_header.e_shnum)
+	{
+	  printf (_("\nCould not find unwind info section for "));
 
-      printf (_(" at offset 0x%lx contains %lu entries:\n"),
-	      unwsec->sh_offset, (unsigned long) (unwsec->sh_size / (3 * addr_size)));
+	  if (string_table == NULL)
+	    printf ("%d", unwsec->sh_name);
+	  else
+	    printf ("'%s'", SECTION_NAME (unwsec));
+	}
+      else
+	{
+	  aux.info_size = sec->sh_size;
+	  aux.info_addr = sec->sh_addr;
+	  GET_DATA_ALLOC (sec->sh_offset, aux.info_size, aux.info,
+			  char *, "unwind info");
 
-      (void) slurp_ia64_unwind_table (file, & aux, unwsec);
+	  printf (_("\nUnwind section "));
 
-      if (aux.table_len > 0)
-	dump_ia64_unwind (& aux);
+	  if (string_table == NULL)
+	    printf ("%d", unwsec->sh_name);
+	  else
+	    printf ("'%s'", SECTION_NAME (unwsec));
+
+	  printf (_(" at offset 0x%lx contains %lu entries:\n"),
+		  unwsec->sh_offset,
+		  (unsigned long) (unwsec->sh_size / (3 * addr_size)));
+
+	  (void) slurp_ia64_unwind_table (file, & aux, unwsec);
+
+	  if (aux.table_len > 0)
+	    dump_ia64_unwind (& aux);
+
+	  if (aux.table)
+	    free ((char *) aux.table);
+	  if (aux.info)
+	    free ((char *) aux.info);
+	  aux.table = NULL;
+	  aux.info = NULL;
+	}
     }
-  else
-    printf (_("\nThere are no unwind sections in this file.\n"));
 
-  if (aux.table)
-    free ((char *) aux.table);
-  if (aux.info)
-    free ((char *) aux.info);
   if (aux.symtab)
     free (aux.symtab);
   if (aux.strtab)
--- gas/config/tc-ia64.c.jj	Wed Feb 14 02:27:23 2001
+++ gas/config/tc-ia64.c	Tue May  1 07:30:36 2001
@@ -518,6 +518,11 @@ static char special_section_name[][20] =
     {".IA_64.unwind"}, {".IA_64.unwind_info"}
   };
 
+static char *special_linkonce_name[] =
+  {
+    ".gnu.linkonce.ia64unw.", ".gnu.linkonce.ia64unwi."
+  };
+
 /* The best template for a particular sequence of up to three
    instructions:  */
 #define N	IA64_NUM_TYPES
@@ -842,11 +847,20 @@ static int generate_unwind_image PARAMS 
 #define make_unw_section_name(special, text_name, result)		   \
   {									   \
     char *_prefix = special_section_name[special];			   \
-    size_t _prefix_len = strlen (_prefix), _text_len = strlen (text_name); \
-    char *_result = alloca (_prefix_len + _text_len + 1);		   \
+    char *_suffix = text_name;						   \
+    size_t _prefix_len, _suffix_len;					   \
+    char *_result;							   \
+    if (strncmp (text_name, ".gnu.linkonce.t.",				   \
+		 sizeof (".gnu.linkonce.t.") - 1) == 0)			   \
+      {									   \
+	_prefix = special_linkonce_name[special - SPECIAL_SECTION_UNWIND]; \
+	_suffix += sizeof (".gnu.linkonce.t.") - 1;			   \
+      }									   \
+    _prefix_len = strlen (_prefix), _suffix_len = strlen (_suffix);	   \
+    _result = alloca (_prefix_len + _suffix_len + 1);		   	   \
     memcpy(_result, _prefix, _prefix_len);				   \
-    memcpy(_result + _prefix_len, text_name, _text_len);		   \
-    _result[_prefix_len + _text_len] = '\0';				   \
+    memcpy(_result + _prefix_len, _suffix, _suffix_len);		   \
+    _result[_prefix_len + _suffix_len] = '\0';				   \
     result = _result;							   \
   }									   \
 while (0)
@@ -903,10 +917,18 @@ ia64_elf_section_type (str, len)
   if (strncmp (str, ELF_STRING_ia64_unwind_info, len) == 0)
     return SHT_PROGBITS;
 
+  len = sizeof (ELF_STRING_ia64_unwind_info_once) - 1;
+  if (strncmp (str, ELF_STRING_ia64_unwind_info_once, len) == 0)
+    return SHT_PROGBITS;
+
   len = sizeof (ELF_STRING_ia64_unwind) - 1;
   if (strncmp (str, ELF_STRING_ia64_unwind, len) == 0)
     return SHT_IA_64_UNWIND;
 
+  len = sizeof (ELF_STRING_ia64_unwind_once) - 1;
+  if (strncmp (str, ELF_STRING_ia64_unwind_once, len) == 0)
+    return SHT_IA_64_UNWIND;
+
   return -1;
 }
 
@@ -3800,6 +3822,8 @@ dot_endp (dummy)
     .text       .IA_64.unwind
     .text.foo   .IA_64.unwind.text.foo
     .foo        .IA_64.unwind.foo
+    .gnu.linkonce.t.foo
+		.gnu.linkonce.ia64unw.foo
     _info       .IA_64.unwind_info         gas issues error message (ditto)
     _infoFOO    .IA_64.unwind_infoFOO      gas issues error message (ditto)
 
--- include/elf/ia64.h.jj	Thu Nov 16 18:35:07 2000
+++ include/elf/ia64.h	Tue May  1 07:25:31 2001
@@ -47,6 +47,8 @@ Foundation, Inc., 59 Temple Place - Suit
 #define ELF_STRING_ia64_pltoff		".IA_64.pltoff"
 #define ELF_STRING_ia64_unwind		".IA_64.unwind"
 #define ELF_STRING_ia64_unwind_info	".IA_64.unwind_info"
+#define ELF_STRING_ia64_unwind_once	".gnu.linkonce.ia64unw."
+#define ELF_STRING_ia64_unwind_info_once ".gnu.linkonce.ia64unwi."
 
 /* Bits in the sh_flags field of Elf64_Shdr:  */
 
--- ld/emulparams/elf64_ia64.sh.jj	Wed Feb 14 02:23:16 2001
+++ ld/emulparams/elf64_ia64.sh	Tue May  1 09:42:28 2001
@@ -12,4 +12,4 @@ GENERATE_SHLIB_SCRIPT=yes
 NOP=0x00300000010070000002000001000400  # a bundle full of nops
 OTHER_GOT_SECTIONS='.IA_64.pltoff : { *(.IA_64.pltoff) }'
 OTHER_PLT_RELOC_SECTIONS='.rela.IA_64.pltoff : { *(.rela.IA_64.pltoff) }'
-OTHER_READONLY_SECTIONS='.opd : { *(.opd) }  .IA_64.unwind_info : { *(.IA_64.unwind_info*) }  .IA_64.unwind : { *(.IA_64.unwind*) }'
+OTHER_READONLY_SECTIONS='.opd : { *(.opd) }  .IA_64.unwind_info : { *(.IA_64.unwind_info*) *(.gnu.linkonce.ia64unwi.*) }  .IA_64.unwind : { *(EXCLUDE_FILE(*crtend.o) .IA_64.unwind*) *(.gnu.linkonce.ia64unw.*) *(.IA_64.unwind*) }'

	Jakub


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