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]

Powerpc disassembly and gdb breakpoints


This patch from Ulrich Weigand implements synthetic symbols on plt
call stubs for powerpc, and the same for powerpc64 except that the
symbol is on the glink branch table instead.  See the fixme I added
to explain why putting the synthetic symbol on the stub is difficult
for ppc64.

	* elf32-ppc.c (section_covers_vma): New function.
	(ppc_elf_get_synthetic_symtab): New function.
	(bfd_elf32_get_synthetic_symtab): Define.
	* elf64-ppc.c (section_covers_vma): New function.
	(ppc64_elf_get_synthetic_symtab): Generate sym@plt on glink branch
	table entries, and __glink_PLTresolve on resolver stub.
	(ppc64_elf_build_stubs): Rename __glink sym to __glink_PLTresolve.

Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.236
diff -u -p -r1.236 elf32-ppc.c
--- bfd/elf32-ppc.c	12 May 2008 12:47:47 -0000	1.236
+++ bfd/elf32-ppc.c	14 May 2008 01:13:27 -0000
@@ -2291,6 +2291,208 @@ ppc_elf_final_write_processing (bfd *abf
   apuinfo_list_finish ();
 }
 
+static bfd_boolean
+section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
+{
+  bfd_vma vma = *(bfd_vma *) ptr;
+  return ((section->flags & SEC_ALLOC) != 0
+	  && section->vma <= vma
+	  && vma < section->vma + section->size);
+}
+
+static long
+ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
+			      long dynsymcount, asymbol **dynsyms,
+			      asymbol **ret)
+{
+  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+  asection *plt, *relplt, *dynamic, *glink;
+  bfd_vma glink_vma = 0;
+  bfd_vma resolv_vma = 0;
+  bfd_vma stub_vma;
+  asymbol *s;
+  arelent *p;
+  long count, i;
+  size_t size;
+  char *names;
+  bfd_byte buf[4];
+
+  *ret = NULL;
+
+  if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
+    return 0;
+
+  if (dynsymcount <= 0)
+    return 0;
+
+  relplt = bfd_get_section_by_name (abfd, ".rela.plt");
+  if (relplt == NULL)
+    return 0;
+
+  plt = bfd_get_section_by_name (abfd, ".plt");
+  if (plt == NULL)
+    return 0;
+
+  /* Call common code to handle old-style executable PLTs.  */
+  if (elf_section_flags (plt) & SHF_EXECINSTR)
+    return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
+					  dynsymcount, dynsyms, ret);
+
+  /* If this object was prelinked, the prelinker stored the address
+     of .glink at got[1].  If it wasn't prelinked, got[1] will be zero.  */
+  dynamic = bfd_get_section_by_name (abfd, ".dynamic");
+  if (dynamic != NULL)
+    {
+      bfd_byte *dynbuf, *extdyn, *extdynend;
+      size_t extdynsize;
+      void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
+
+      if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf))
+	return -1;
+
+      extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
+      swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
+
+      extdyn = dynbuf;
+      extdynend = extdyn + dynamic->size;
+      for (; extdyn < extdynend; extdyn += extdynsize)
+	{
+	  Elf_Internal_Dyn dyn;
+	  (*swap_dyn_in) (abfd, extdyn, &dyn);
+
+	  if (dyn.d_tag == DT_NULL)
+	    break;
+
+	  if (dyn.d_tag == DT_PPC_GOT)
+	    {
+	      unsigned int g_o_t = dyn.d_un.d_val;
+	      asection *got = bfd_get_section_by_name (abfd, ".got");
+	      if (got != NULL
+		  && bfd_get_section_contents (abfd, got, buf,
+					       g_o_t - got->vma + 4, 4))
+		glink_vma = bfd_get_32 (abfd, buf);
+	      break;
+	    }
+	}
+      free (dynbuf);
+    }
+
+  /* Otherwise we read the first plt entry.  */
+  if (glink_vma == 0)
+    {
+      if (bfd_get_section_contents (abfd, plt, buf, 0, 4))
+	glink_vma = bfd_get_32 (abfd, buf);
+    }
+
+  if (glink_vma == 0)
+    return 0;
+
+  /* The .glink section usually does not survive the final
+     link; search for the section (usually .text) where the
+     glink stubs now reside.  */
+  glink = bfd_sections_find_if (abfd, section_covers_vma, &glink_vma);
+  if (glink == NULL)
+    return 0;
+
+  /* Determine glink PLT resolver by reading the relative branch
+     from the first glink stub.  */
+  if (bfd_get_section_contents (abfd, glink, buf,
+				glink_vma - glink->vma, 4))
+    {
+      unsigned int insn = bfd_get_32 (abfd, buf);
+
+      /* The first glink stub may either branch to the resolver ...  */
+      insn ^= B;
+      if ((insn & ~0x3fffffc) == 0)
+	resolv_vma = glink_vma + (insn ^ 0x2000000) - 0x2000000;
+
+      /* ... or fall through a bunch of NOPs.  */
+      else if ((insn ^ B ^ NOP) == 0)
+	for (i = 4;
+	     bfd_get_section_contents (abfd, glink, buf,
+				       glink_vma - glink->vma + i, 4);
+	     i += 4)
+	  if (bfd_get_32 (abfd, buf) != NOP)
+	    {
+	      resolv_vma = glink_vma + i;
+	      break;
+	    }
+    }
+
+  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+  if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+    return -1;
+
+  count = relplt->size / sizeof (Elf32_External_Rela);
+  stub_vma = glink_vma - (bfd_vma) count * 16;
+  size = count * sizeof (asymbol);
+  p = relplt->relocation;
+  for (i = 0; i < count; i++, p++)
+    size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+
+  size += sizeof (asymbol) + sizeof ("__glink");
+
+  if (resolv_vma)
+    size += sizeof (asymbol) + sizeof ("__glink_PLTresolve");
+
+  s = *ret = bfd_malloc (size);
+  if (s == NULL)
+    return -1;
+
+  names = (char *) (s + count + 1 + (resolv_vma != 0));
+  p = relplt->relocation;
+  for (i = 0; i < count; i++, p++)
+    {
+      size_t len;
+
+      *s = **p->sym_ptr_ptr;
+      /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
+	 we are defining a symbol, ensure one of them is set.  */
+      if ((s->flags & BSF_LOCAL) == 0)
+	s->flags |= BSF_GLOBAL;
+      s->section = glink;
+      s->value = stub_vma - glink->vma;
+      s->name = names;
+      s->udata.p = NULL;
+      len = strlen ((*p->sym_ptr_ptr)->name);
+      memcpy (names, (*p->sym_ptr_ptr)->name, len);
+      names += len;
+      memcpy (names, "@plt", sizeof ("@plt"));
+      names += sizeof ("@plt");
+      ++s;
+      stub_vma += 16;
+    }
+
+  /* Add a symbol at the start of the glink branch table.  */
+  memset (s, sizeof *s, 0);
+  s->the_bfd = abfd;
+  s->flags = BSF_GLOBAL;
+  s->section = glink;
+  s->value = glink_vma - glink->vma;
+  s->name = names;
+  memcpy (names, "__glink", sizeof ("__glink"));
+  names += sizeof ("__glink");
+  s++;
+  count++;
+
+  if (resolv_vma)
+    {
+      /* Add a symbol for the glink PLT resolver.  */
+      memset (s, sizeof *s, 0);
+      s->the_bfd = abfd;
+      s->flags = BSF_GLOBAL;
+      s->section = glink;
+      s->value = resolv_vma - glink->vma;
+      s->name = names;
+      memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve"));
+      names += sizeof ("__glink_PLTresolve");
+      s++;
+      count++;
+    }
+
+  return count;
+}
+
 /* The following functions are specific to the ELF linker, while
    functions above are used generally.  They appear in this file more
    or less in the order in which they are called.  eg.
@@ -7818,6 +8020,7 @@ ppc_elf_finish_dynamic_sections (bfd *ou
 #define bfd_elf32_bfd_reloc_name_lookup	ppc_elf_reloc_name_lookup
 #define bfd_elf32_bfd_set_private_flags		ppc_elf_set_private_flags
 #define bfd_elf32_bfd_link_hash_table_create	ppc_elf_link_hash_table_create
+#define bfd_elf32_get_synthetic_symtab		ppc_elf_get_synthetic_symtab
 
 #define elf_backend_object_p			ppc_elf_object_p
 #define elf_backend_gc_mark_hook		ppc_elf_gc_mark_hook
@@ -7932,6 +8135,8 @@ ppc_elf_vxworks_final_write_processing (
 #undef elf_backend_got_header_size
 #define elf_backend_got_header_size		12
 
+#undef bfd_elf32_get_synthetic_symtab
+
 #undef bfd_elf32_bfd_link_hash_table_create
 #define bfd_elf32_bfd_link_hash_table_create \
   ppc_elf_vxworks_link_hash_table_create
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.280
diff -u -p -r1.280 elf64-ppc.c
--- bfd/elf64-ppc.c	12 May 2008 12:47:47 -0000	1.280
+++ bfd/elf64-ppc.c	14 May 2008 01:13:30 -0000
@@ -2771,8 +2771,17 @@ sym_exists_at (asymbol **syms, long lo, 
   return NULL;
 }
 
+static bfd_boolean
+section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
+{
+  bfd_vma vma = *(bfd_vma *) ptr;
+  return ((section->flags & SEC_ALLOC) != 0
+	  && section->vma <= vma
+	  && vma < section->vma + section->size);
+}
+
 /* Create synthetic symbols, effectively restoring "dot-symbol" function
-   entry syms.  */
+   entry syms.  Also generate @plt symbols for the glink branch table.  */
 
 static long
 ppc64_elf_get_synthetic_symtab (bfd *abfd,
@@ -2862,8 +2871,6 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
   symcount = i;
 
   count = 0;
-  if (opdsymend == secsymend)
-    goto done;
 
   if (relocatable)
     {
@@ -2872,6 +2879,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
       size_t size;
       long relcount;
 
+      if (opdsymend == secsymend)
+	goto done;
+
       slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
       relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
       if (relcount == 0)
@@ -2960,8 +2970,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
     }
   else
     {
+      bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
       bfd_byte *contents;
       size_t size;
+      long plt_count = 0;
+      bfd_vma glink_vma = 0, resolv_vma = 0;
+      asection *dynamic, *glink = NULL, *relplt = NULL;
+      arelent *p;
 
       if (!bfd_malloc_and_get_section (abfd, opd, &contents))
 	{
@@ -2988,11 +3003,85 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
 	    }
 	}
 
+      /* Get start of .glink stubs from DT_PPC64_GLINK.  */
+      dynamic = bfd_get_section_by_name (abfd, ".dynamic");
+      if (dynamic != NULL)
+	{
+	  bfd_byte *dynbuf, *extdyn, *extdynend;
+	  size_t extdynsize;
+	  void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
+
+	  if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf))
+	    goto free_contents_and_exit;
+
+	  extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
+	  swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
+
+	  extdyn = dynbuf;
+	  extdynend = extdyn + dynamic->size;
+	  for (; extdyn < extdynend; extdyn += extdynsize)
+	    {
+	      Elf_Internal_Dyn dyn;
+	      (*swap_dyn_in) (abfd, extdyn, &dyn);
+
+	      if (dyn.d_tag == DT_NULL)
+		break;
+
+	      if (dyn.d_tag == DT_PPC64_GLINK)
+		{
+		  /* The first glink stub starts at offset 32; see comment in
+		     ppc64_elf_finish_dynamic_sections. */
+		  glink_vma = dyn.d_un.d_val + 32;
+		  /* The .glink section usually does not survive the final
+		     link; search for the section (usually .text) where the
+		     glink stubs now reside.  */
+		  glink = bfd_sections_find_if (abfd, section_covers_vma,
+						&glink_vma);
+		  break;
+		}
+	    }
+
+	  free (dynbuf);
+	}
+
+      if (glink != NULL)
+	{
+	  /* Determine __glink trampoline by reading the relative branch
+	     from the first glink stub.  */
+	  bfd_byte buf[4];
+	  if (bfd_get_section_contents (abfd, glink, buf,
+					glink_vma + 4 - glink->vma, 4))
+	    {
+	      unsigned int insn = bfd_get_32 (abfd, buf);
+	      insn ^= B_DOT;
+	      if ((insn & ~0x3fffffc) == 0)
+		resolv_vma = glink_vma + 4 + (insn ^ 0x2000000) - 0x2000000;
+	    }
+
+	  if (resolv_vma)
+	    size += sizeof (asymbol) + sizeof ("__glink_PLTresolve");
+	}
+
+      relplt = bfd_get_section_by_name (abfd, ".rela.plt");
+      if (glink != NULL && relplt != NULL)
+	{
+	  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+	  if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
+	    goto free_contents_and_exit;
+	
+	  plt_count = relplt->size / sizeof (Elf64_External_Rela);
+	  size += plt_count * sizeof (asymbol);
+
+	  p = relplt->relocation;
+	  for (i = 0; i < plt_count; i++, p++)
+	    size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+	}
+
       s = *ret = bfd_malloc (size);
       if (s == NULL)
 	goto free_contents_and_exit;
 
-      names = (char *) (s + count);
+      names = (char *) (s + count + plt_count + (resolv_vma != 0));
 
       for (i = secsymend; i < opdsymend; ++i)
 	{
@@ -3048,6 +3137,66 @@ ppc64_elf_get_synthetic_symtab (bfd *abf
 	    }
 	}
       free (contents);
+
+      if (glink != NULL && relplt != NULL)
+	{
+	  if (resolv_vma)
+	    {
+	      /* Add a symbol for the main glink trampoline.  */
+	      memset (s, sizeof *s, 0);
+	      s->the_bfd = abfd;
+	      s->flags = BSF_GLOBAL;
+	      s->section = glink;
+	      s->value = resolv_vma - glink->vma;
+	      s->name = names;
+	      memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve"));
+	      names += sizeof ("__glink_PLTresolve");
+	      s++;
+	      count++;
+	    }
+
+	  /* FIXME: It would be very much nicer to put sym@plt on the
+	     stub rather than on the glink branch table entry.  The
+	     objdump disassembler would then use a sensible symbol
+	     name on plt calls.  The difficulty in doing so is
+	     a) finding the stubs, and,
+	     b) matching stubs against plt entries, and,
+	     c) there can be multiple stubs for a given plt entry.
+
+	     Solving (a) could be done by code scanning, but older
+	     ppc64 binaries used different stubs to current code.
+	     (b) is the tricky one since you need to known the toc
+	     pointer for at least one function that uses a pic stub to
+	     be able to calculate the plt address referenced.
+	     (c) means gdb would need to set multiple breakpoints (or
+	     find the glink branch itself) when setting breakpoints
+	     for pending shared library loads.  */
+	  p = relplt->relocation;
+	  for (i = 0; i < plt_count; i++, p++)
+	    {
+	      size_t len;
+
+	      *s = **p->sym_ptr_ptr;
+	      /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
+		 we are defining a symbol, ensure one of them is set.  */
+	      if ((s->flags & BSF_LOCAL) == 0)
+		s->flags |= BSF_GLOBAL;
+	      s->section = glink;
+	      s->value = glink_vma - glink->vma;
+	      s->name = names;
+	      s->udata.p = NULL;
+	      len = strlen ((*p->sym_ptr_ptr)->name);
+	      memcpy (names, (*p->sym_ptr_ptr)->name, len);
+	      names += len;
+	      memcpy (names, "@plt", sizeof ("@plt"));
+	      names += sizeof ("@plt");
+	      s++;
+	      glink_vma += 8;
+	      if (i >= 0x8000)
+		glink_vma += 4;
+	    }
+	  count += plt_count;
+	}
     }
 
  done:
@@ -9802,7 +9951,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_
       if (htab->emit_stub_syms)
 	{
 	  struct elf_link_hash_entry *h;
-	  h = elf_link_hash_lookup (&htab->elf, "__glink", TRUE, FALSE, FALSE);
+	  h = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
+				    TRUE, FALSE, FALSE);
 	  if (h == NULL)
 	    return FALSE;
 	  if (h->root.type == bfd_link_hash_new)

-- 
Alan Modra
Australia Development Lab, IBM


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