1d52dc8
binutils/
1d52dc8
1d52dc8
2007-05-09  H.J. Lu  <hongjiu.lu@intel.com>
1d52dc8
1d52dc8
	PR binutils/4476
1d52dc8
	* readelf.c (print_dynamic_symbol): New.
1d52dc8
	(process_symbol_table): Handle DT_GNU_HASH for dynamic symbols.
1d52dc8
1d52dc8
ld/testsuite/
1d52dc8
1d52dc8
2007-05-09  H.J. Lu  <hongjiu.lu@intel.com>
1d52dc8
1d52dc8
	PR binutils/4476
1d52dc8
	* ld-elf/hash.d: Check "-s -D" for readelf.
1d52dc8
900278a
--- binutils/readelf.c.hash	2007-05-09 10:54:22.000000000 -0700
900278a
+++ binutils/readelf.c	2007-05-09 17:24:46.000000000 -0700
1d52dc8
@@ -7033,6 +7033,39 @@ get_dynamic_data (FILE *file, unsigned i
1d52dc8
   return i_data;
1d52dc8
 }
1d52dc8
 
1d52dc8
+static void
1d52dc8
+print_dynamic_symbol (bfd_vma si, unsigned long hn)
1d52dc8
+{
1d52dc8
+  Elf_Internal_Sym *psym;
1d52dc8
+  int n;
1d52dc8
+
1d52dc8
+  psym = dynamic_symbols + si;
1d52dc8
+
1d52dc8
+  n = print_vma (si, DEC_5);
1d52dc8
+  if (n < 5)
1d52dc8
+    fputs ("     " + n, stdout);
1d52dc8
+  printf (" %3lu: ", hn);
1d52dc8
+  print_vma (psym->st_value, LONG_HEX);
1d52dc8
+  putchar (' ');
1d52dc8
+  print_vma (psym->st_size, DEC_5);
1d52dc8
+
1d52dc8
+  printf ("  %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
1d52dc8
+  printf (" %6s",  get_symbol_binding (ELF_ST_BIND (psym->st_info)));
1d52dc8
+  printf (" %3s",  get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
1d52dc8
+  /* Check to see if any other bits in the st_other field are set.
1d52dc8
+     Note - displaying this information disrupts the layout of the
1d52dc8
+     table being generated, but for the moment this case is very
1d52dc8
+     rare.  */
1d52dc8
+  if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
1d52dc8
+    printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
1d52dc8
+  printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
1d52dc8
+  if (VALID_DYNAMIC_NAME (psym->st_name))
1d52dc8
+    print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
1d52dc8
+  else
1d52dc8
+    printf (" <corrupt: %14ld>", psym->st_name);
1d52dc8
+  putchar ('\n');
1d52dc8
+}
1d52dc8
+
1d52dc8
 /* Dump the symbol table.  */
1d52dc8
 static int
1d52dc8
 process_symbol_table (FILE *file)
1d52dc8
@@ -7045,12 +7078,14 @@ process_symbol_table (FILE *file)
1d52dc8
   bfd_vma ngnubuckets = 0;
1d52dc8
   bfd_vma *gnubuckets = NULL;
1d52dc8
   bfd_vma *gnuchains = NULL;
1d52dc8
+  bfd_vma gnusymidx = 0;
1d52dc8
 
1d52dc8
   if (! do_syms && !do_histogram)
1d52dc8
     return 1;
1d52dc8
 
1d52dc8
-  if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL)
1d52dc8
-				|| do_histogram))
1d52dc8
+  if (dynamic_info[DT_HASH]
1d52dc8
+      && (do_histogram
1d52dc8
+	  || (do_using_dynamic && dynamic_strings != NULL)))
1d52dc8
     {
1d52dc8
       unsigned char nb[8];
1d52dc8
       unsigned char nc[8];
1d52dc8
@@ -7094,54 +7129,157 @@ process_symbol_table (FILE *file)
1d52dc8
 	return 0;
1d52dc8
     }
1d52dc8
 
1d52dc8
-  if (do_syms
1d52dc8
-      && dynamic_info[DT_HASH] && do_using_dynamic && dynamic_strings != NULL)
1d52dc8
+  if (dynamic_info_DT_GNU_HASH
1d52dc8
+      && (do_histogram
1d52dc8
+	  || (do_using_dynamic && dynamic_strings != NULL)))
1d52dc8
     {
1d52dc8
-      unsigned long hn;
1d52dc8
-      bfd_vma si;
1d52dc8
+      unsigned char nb[16];
1d52dc8
+      bfd_vma i, maxchain = 0xffffffff, bitmaskwords;
1d52dc8
+      bfd_vma buckets_vma;
1d52dc8
+
1d52dc8
+      if (fseek (file,
1d52dc8
+		 (archive_file_offset
1d52dc8
+		  + offset_from_vma (file, dynamic_info_DT_GNU_HASH,
1d52dc8
+				     sizeof nb)),
1d52dc8
+		 SEEK_SET))
1d52dc8
+	{
1d52dc8
+	  error (_("Unable to seek to start of dynamic information\n"));
1d52dc8
+	  return 0;
1d52dc8
+	}
1d52dc8
+
1d52dc8
+      if (fread (nb, 16, 1, file) != 1)
1d52dc8
+	{
1d52dc8
+	  error (_("Failed to read in number of buckets\n"));
1d52dc8
+	  return 0;
1d52dc8
+	}
1d52dc8
 
1d52dc8
-      printf (_("\nSymbol table for image:\n"));
1d52dc8
+      ngnubuckets = byte_get (nb, 4);
1d52dc8
+      gnusymidx = byte_get (nb + 4, 4);
1d52dc8
+      bitmaskwords = byte_get (nb + 8, 4);
1d52dc8
+      buckets_vma = dynamic_info_DT_GNU_HASH + 16;
1d52dc8
       if (is_32bit_elf)
1d52dc8
-	printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
1d52dc8
+	buckets_vma += bitmaskwords * 4;
1d52dc8
       else
1d52dc8
-	printf (_("  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name\n"));
1d52dc8
+	buckets_vma += bitmaskwords * 8;
1d52dc8
 
1d52dc8
-      for (hn = 0; hn < nbuckets; hn++)
1d52dc8
+      if (fseek (file,
1d52dc8
+		 (archive_file_offset
1d52dc8
+		  + offset_from_vma (file, buckets_vma, 4)),
1d52dc8
+		 SEEK_SET))
1d52dc8
 	{
1d52dc8
-	  if (! buckets[hn])
1d52dc8
-	    continue;
1d52dc8
+	  error (_("Unable to seek to start of dynamic information\n"));
1d52dc8
+	  return 0;
1d52dc8
+	}
1d52dc8
+
1d52dc8
+      gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
1d52dc8
+
1d52dc8
+      if (gnubuckets == NULL)
1d52dc8
+	return 0;
1d52dc8
+
1d52dc8
+      for (i = 0; i < ngnubuckets; i++)
1d52dc8
+	if (gnubuckets[i] != 0)
1d52dc8
+	  {
1d52dc8
+	    if (gnubuckets[i] < gnusymidx)
1d52dc8
+	      return 0;
1d52dc8
+
1d52dc8
+	    if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
1d52dc8
+	      maxchain = gnubuckets[i];
1d52dc8
+	  }
1d52dc8
+
1d52dc8
+      if (maxchain == 0xffffffff)
1d52dc8
+	return 0;
1d52dc8
 
1d52dc8
-	  for (si = buckets[hn]; si < nchains && si > 0; si = chains[si])
1d52dc8
+      maxchain -= gnusymidx;
1d52dc8
+
1d52dc8
+      if (fseek (file,
1d52dc8
+		 (archive_file_offset
1d52dc8
+		  + offset_from_vma (file, buckets_vma
1d52dc8
+					   + 4 * (ngnubuckets + maxchain), 4)),
1d52dc8
+		 SEEK_SET))
1d52dc8
+	{
1d52dc8
+	  error (_("Unable to seek to start of dynamic information\n"));
1d52dc8
+	  return 0;
1d52dc8
+	}
1d52dc8
+
1d52dc8
+      do
1d52dc8
+	{
1d52dc8
+	  if (fread (nb, 4, 1, file) != 1)
1d52dc8
 	    {
1d52dc8
-	      Elf_Internal_Sym *psym;
1d52dc8
-	      int n;
1d52dc8
+	      error (_("Failed to determine last chain length\n"));
1d52dc8
+	      return 0;
1d52dc8
+	    }
1d52dc8
 
1d52dc8
-	      psym = dynamic_symbols + si;
1d52dc8
+	  if (maxchain + 1 == 0)
1d52dc8
+	    return 0;
1d52dc8
 
1d52dc8
-	      n = print_vma (si, DEC_5);
1d52dc8
-	      if (n < 5)
1d52dc8
-		fputs ("     " + n, stdout);
1d52dc8
-	      printf (" %3lu: ", hn);
1d52dc8
-	      print_vma (psym->st_value, LONG_HEX);
1d52dc8
-	      putchar (' ');
1d52dc8
-	      print_vma (psym->st_size, DEC_5);
1d52dc8
+	  ++maxchain;
1d52dc8
+	}
1d52dc8
+      while ((byte_get (nb, 4) & 1) == 0);
1d52dc8
 
1d52dc8
-	      printf ("  %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
1d52dc8
-	      printf (" %6s",  get_symbol_binding (ELF_ST_BIND (psym->st_info)));
1d52dc8
-	      printf (" %3s",  get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
1d52dc8
-	      /* Check to see if any other bits in the st_other field are set.
1d52dc8
-	         Note - displaying this information disrupts the layout of the
1d52dc8
-	         table being generated, but for the moment this case is very rare.  */
1d52dc8
-	      if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
1d52dc8
-		printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
1d52dc8
-	      printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
1d52dc8
-	      if (VALID_DYNAMIC_NAME (psym->st_name))
1d52dc8
-		print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
1d52dc8
-	      else
1d52dc8
-		printf (" <corrupt: %14ld>", psym->st_name);
1d52dc8
-	      putchar ('\n');
1d52dc8
+      if (fseek (file,
1d52dc8
+		 (archive_file_offset
1d52dc8
+		  + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
1d52dc8
+		 SEEK_SET))
1d52dc8
+	{
1d52dc8
+	  error (_("Unable to seek to start of dynamic information\n"));
1d52dc8
+	  return 0;
1d52dc8
+	}
1d52dc8
+
1d52dc8
+      gnuchains = get_dynamic_data (file, maxchain, 4);
1d52dc8
+
1d52dc8
+      if (gnuchains == NULL)
1d52dc8
+	return 0;
1d52dc8
+    }
1d52dc8
+
1d52dc8
+  if ((dynamic_info[DT_HASH] || dynamic_info_DT_GNU_HASH)
1d52dc8
+      && do_syms
1d52dc8
+      && do_using_dynamic
1d52dc8
+      && dynamic_strings != NULL)
1d52dc8
+    {
1d52dc8
+      unsigned long hn;
1d52dc8
+
1d52dc8
+      if (dynamic_info[DT_HASH])
1d52dc8
+	{
1d52dc8
+	  bfd_vma si;
1d52dc8
+
1d52dc8
+	  printf (_("\nSymbol table for image:\n"));
1d52dc8
+	  if (is_32bit_elf)
1d52dc8
+	    printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
1d52dc8
+	  else
1d52dc8
+	    printf (_("  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name\n"));
1d52dc8
+
1d52dc8
+	  for (hn = 0; hn < nbuckets; hn++)
1d52dc8
+	    {
1d52dc8
+	      if (! buckets[hn])
1d52dc8
+		continue;
1d52dc8
+
1d52dc8
+	      for (si = buckets[hn]; si < nchains && si > 0; si = chains[si])
1d52dc8
+		print_dynamic_symbol (si, hn);
1d52dc8
 	    }
1d52dc8
 	}
1d52dc8
+
1d52dc8
+      if (dynamic_info_DT_GNU_HASH)
1d52dc8
+	{
1d52dc8
+	  printf (_("\nSymbol table of `.gnu.hash' for image:\n"));
1d52dc8
+	  if (is_32bit_elf)
1d52dc8
+	    printf (_("  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name\n"));
1d52dc8
+	  else
1d52dc8
+	    printf (_("  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name\n"));
1d52dc8
+
1d52dc8
+	  for (hn = 0; hn < ngnubuckets; ++hn)
1d52dc8
+	    if (gnubuckets[hn] != 0)
1d52dc8
+	      {
1d52dc8
+		bfd_vma si = gnubuckets[hn];
1d52dc8
+		bfd_vma off = si - gnusymidx;
1d52dc8
+
1d52dc8
+		do
1d52dc8
+		  {
1d52dc8
+		    print_dynamic_symbol (si, hn);
1d52dc8
+		    si++;
1d52dc8
+		  }
1d52dc8
+		while ((gnuchains[off++] & 1) == 0);
1d52dc8
+	      }
1d52dc8
+	}
1d52dc8
     }
1d52dc8
   else if (do_syms && !do_using_dynamic)
1d52dc8
     {
1d52dc8
@@ -7426,108 +7564,12 @@ process_symbol_table (FILE *file)
1d52dc8
 
1d52dc8
   if (do_histogram && dynamic_info_DT_GNU_HASH)
1d52dc8
     {
1d52dc8
-      unsigned char nb[16];
1d52dc8
-      bfd_vma i, maxchain = 0xffffffff, symidx, bitmaskwords;
1d52dc8
       unsigned long *lengths;
1d52dc8
       unsigned long *counts;
1d52dc8
       unsigned long hn;
1d52dc8
       unsigned long maxlength = 0;
1d52dc8
       unsigned long nzero_counts = 0;
1d52dc8
       unsigned long nsyms = 0;
1d52dc8
-      bfd_vma buckets_vma;
1d52dc8
-
1d52dc8
-      if (fseek (file,
1d52dc8
-		 (archive_file_offset
1d52dc8
-		  + offset_from_vma (file, dynamic_info_DT_GNU_HASH,
1d52dc8
-				     sizeof nb)),
1d52dc8
-		 SEEK_SET))
1d52dc8
-	{
1d52dc8
-	  error (_("Unable to seek to start of dynamic information\n"));
1d52dc8
-	  return 0;
1d52dc8
-	}
1d52dc8
-
1d52dc8
-      if (fread (nb, 16, 1, file) != 1)
1d52dc8
-	{
1d52dc8
-	  error (_("Failed to read in number of buckets\n"));
1d52dc8
-	  return 0;
1d52dc8
-	}
1d52dc8
-
1d52dc8
-      ngnubuckets = byte_get (nb, 4);
1d52dc8
-      symidx = byte_get (nb + 4, 4);
1d52dc8
-      bitmaskwords = byte_get (nb + 8, 4);
1d52dc8
-      buckets_vma = dynamic_info_DT_GNU_HASH + 16;
1d52dc8
-      if (is_32bit_elf)
1d52dc8
-	buckets_vma += bitmaskwords * 4;
1d52dc8
-      else
1d52dc8
-	buckets_vma += bitmaskwords * 8;
1d52dc8
-
1d52dc8
-      if (fseek (file,
1d52dc8
-		 (archive_file_offset
1d52dc8
-		  + offset_from_vma (file, buckets_vma, 4)),
1d52dc8
-		 SEEK_SET))
1d52dc8
-	{
1d52dc8
-	  error (_("Unable to seek to start of dynamic information\n"));
1d52dc8
-	  return 0;
1d52dc8
-	}
1d52dc8
-
1d52dc8
-      gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
1d52dc8
-
1d52dc8
-      if (gnubuckets == NULL)
1d52dc8
-	return 0;
1d52dc8
-
1d52dc8
-      for (i = 0; i < ngnubuckets; i++)
1d52dc8
-	if (gnubuckets[i] != 0)
1d52dc8
-	  {
1d52dc8
-	    if (gnubuckets[i] < symidx)
1d52dc8
-	      return 0;
1d52dc8
-
1d52dc8
-	    if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
1d52dc8
-	      maxchain = gnubuckets[i];
1d52dc8
-	  }
1d52dc8
-
1d52dc8
-      if (maxchain == 0xffffffff)
1d52dc8
-	return 0;
1d52dc8
-
1d52dc8
-      maxchain -= symidx;
1d52dc8
-
1d52dc8
-      if (fseek (file,
1d52dc8
-		 (archive_file_offset
1d52dc8
-		  + offset_from_vma (file, buckets_vma
1d52dc8
-					   + 4 * (ngnubuckets + maxchain), 4)),
1d52dc8
-		 SEEK_SET))
1d52dc8
-	{
1d52dc8
-	  error (_("Unable to seek to start of dynamic information\n"));
1d52dc8
-	  return 0;
1d52dc8
-	}
1d52dc8
-
1d52dc8
-      do
1d52dc8
-	{
1d52dc8
-	  if (fread (nb, 4, 1, file) != 1)
1d52dc8
-	    {
1d52dc8
-	      error (_("Failed to determine last chain length\n"));
1d52dc8
-	      return 0;
1d52dc8
-	    }
1d52dc8
-
1d52dc8
-	  if (maxchain + 1 == 0)
1d52dc8
-	    return 0;
1d52dc8
-
1d52dc8
-	  ++maxchain;
1d52dc8
-	}
1d52dc8
-      while ((byte_get (nb, 4) & 1) == 0);
1d52dc8
-
1d52dc8
-      if (fseek (file,
1d52dc8
-		 (archive_file_offset
1d52dc8
-		  + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
1d52dc8
-		 SEEK_SET))
1d52dc8
-	{
1d52dc8
-	  error (_("Unable to seek to start of dynamic information\n"));
1d52dc8
-	  return 0;
1d52dc8
-	}
1d52dc8
-
1d52dc8
-      gnuchains = get_dynamic_data (file, maxchain, 4);
1d52dc8
-
1d52dc8
-      if (gnuchains == NULL)
1d52dc8
-	return 0;
1d52dc8
 
1d52dc8
       lengths = calloc (ngnubuckets, sizeof (*lengths));
1d52dc8
       if (lengths == NULL)
1d52dc8
@@ -7545,7 +7587,7 @@ process_symbol_table (FILE *file)
1d52dc8
 	  {
1d52dc8
 	    bfd_vma off, length = 1;
1d52dc8
 
1d52dc8
-	    for (off = gnubuckets[hn] - symidx;
1d52dc8
+	    for (off = gnubuckets[hn] - gnusymidx;
1d52dc8
 		 (gnuchains[off] & 1) == 0; ++off)
1d52dc8
 	      ++length;
1d52dc8
 	    lengths[hn] = length;
900278a
--- ld/testsuite/ld-elf/hash.d.hash	2006-09-15 07:55:42.000000000 -0700
900278a
+++ ld/testsuite/ld-elf/hash.d	2007-05-09 15:46:56.000000000 -0700
1d52dc8
@@ -1,5 +1,5 @@
1d52dc8
 #source: start.s
1d52dc8
-#readelf: -d 
1d52dc8
+#readelf: -d -s -D
1d52dc8
 #ld: -shared --hash-style=gnu
1d52dc8
 #target: *-*-linux*
1d52dc8
 #notarget: mips*-*-*
1d52dc8
@@ -7,3 +7,11 @@
1d52dc8
 #...
1d52dc8
 [ 	]*0x[0-9a-z]+[ 	]+\(GNU_HASH\)[ 	]+0x[0-9a-z]+
1d52dc8
 #...
1d52dc8
+[ 	]+[0-9]+[ 	]+[0-9]+:[ 	]+[0-9a-f]+[ 	]+[0-9]+[ 	]+NOTYPE[	 ]+GLOBAL DEFAULT[ 	]+[1-9] _start
1d52dc8
+#...
1d52dc8
+[ 	]+[0-9]+[ 	]+[0-9]+:[ 	]+[0-9a-f]+[ 	]+[0-9]+[ 	]+NOTYPE[	 ]+GLOBAL DEFAULT[ 	]+[1-9] main
1d52dc8
+#...
1d52dc8
+[ 	]+[0-9]+[ 	]+[0-9]+:[ 	]+[0-9a-f]+[ 	]+[0-9]+[ 	]+NOTYPE[	 ]+GLOBAL DEFAULT[ 	]+[1-9] start
1d52dc8
+#...
1d52dc8
+[ 	]+[0-9]+[ 	]+[0-9]+:[ 	]+[0-9a-f]+[ 	]+[0-9]+[ 	]+NOTYPE[	 ]+GLOBAL DEFAULT[ 	]+[1-9] __start
1d52dc8
+#...