This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


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

Re: NEW PATCH: Handle undefined symbol in DSO from DT_NEEDED


On Wed, May 09, 2001 at 03:53:21PM -0700, H . J . Lu wrote:
> 
> Here is a new patch for ld. For undefined symbol in a DSO, the dynamic
> linker binds it to a hidden definition if and only if there is only
> one hidden definition. This patch will make ld to do the same, but 
> only for DSO from DT_NEEDED. Otherwise, it is a real error.
> 
> If there is no objecttion, I will check it in by Friday.
> 

Here is an update. The dynamic linker will bind the underfined,
unvesioned symbol to the first defition.


H.J.
----
2001-05-09  H.J. Lu  <hjl@gnu.org>

	* elf-bfd.h (elf_link_loaded_list): New structure.
	(elf_link_hash_table): Add "loaded".

	* elf.c (_bfd_elf_link_hash_table_init): Initialize the
	 "loaded" field to NULL.

	* elflink.h (elf_link_check_versioned_symbol): New function.
	Return true if there is one hidden definition for the undefined
	symbol.

	* elflink.h (elf_link_output_extsym): For undefined symbol in
	DSO from DT_NEEDED, Call elf_link_check_versioned_symbol to
	check if there is one hidden definition.

Index: elf-bfd.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elf-bfd.h,v
retrieving revision 1.8
diff -u -p -r1.8 elf-bfd.h
--- elf-bfd.h	2001/04/13 18:47:21	1.8
+++ elf-bfd.h	2001/05/10 00:36:50
@@ -213,6 +213,12 @@ struct elf_link_local_dynamic_entry
   Elf_Internal_Sym isym;
 };
 
+struct elf_link_loaded_list
+{
+  struct elf_link_loaded_list *next;
+  bfd *abfd;
+};
+
 /* ELF linker hash table.  */
 
 struct elf_link_hash_table
@@ -248,6 +254,8 @@ struct elf_link_hash_table
   /* A linked list of DT_RPATH/DT_RUNPATH names found in dynamic
      objects included in the link.  */
   struct bfd_link_needed_list *runpath;
+  /* A linked list of BFD's loaded in the link. */
+  struct elf_link_loaded_list *loaded;
 };
 
 /* Look up an entry in an ELF linker hash table.  */
Index: elf.c
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elf.c,v
retrieving revision 1.51
diff -u -p -r1.51 elf.c
--- elf.c	2001/04/27 21:05:00	1.51
+++ elf.c	2001/05/10 00:36:50
@@ -1037,6 +1037,7 @@ _bfd_elf_link_hash_table_init (table, ab
   table->bucketcount = 0;
   table->needed = NULL;
   table->runpath = NULL;
+  table->loaded = NULL;
   table->hgot = NULL;
   table->stab_info = NULL;
   table->merge_info = NULL;
Index: elflink.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elflink.h,v
retrieving revision 1.58
diff -u -p -r1.58 elflink.h
--- elflink.h	2001/05/03 06:45:26	1.58
+++ elflink.h	2001/05/10 00:36:50
@@ -60,7 +60,147 @@ static boolean elf_link_size_reloc_secti
 static void elf_link_adjust_relocs
   PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int,
 	   struct elf_link_hash_entry **));
+static boolean elf_link_check_versioned_symbol
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 
+static boolean
+elf_link_check_versioned_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  boolean found = false;
+  bfd *undef_bfd = h->root.u.undef.abfd;
+  struct elf_link_loaded_list *loaded;
+  Elf_External_Sym *buf = NULL;
+  Elf_External_Versym *extversym = NULL;
+
+  if ((undef_bfd->flags & DYNAMIC) == 0
+      || info->hash->creator->flavour != bfd_target_elf_flavour)
+    return false;
+
+  for (loaded = elf_hash_table (info)->loaded;
+       loaded != NULL && !found;
+       loaded = loaded->next)
+    {
+      bfd *input;
+      Elf_Internal_Shdr *hdr;
+      size_t symcount;
+      size_t extsymcount;
+      size_t extsymoff;
+      Elf_Internal_Shdr *versymhdr;
+      Elf_External_Versym *ever;
+      Elf_External_Sym *esym;
+      Elf_External_Sym *esymend;
+
+      input = loaded->abfd;
+
+      /* We check each DSO for a possible versioned difinition.  */
+      if (input == undef_bfd
+	  || (input->flags & DYNAMIC) == 0
+	  || elf_dynversym (input) == 0)
+	continue;
+
+      hdr = &elf_tdata (input)->dynsymtab_hdr;
+
+      symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+      if (elf_bad_symtab (input))
+	{
+	  extsymcount = symcount;
+	  extsymoff = 0;
+	}
+      else
+	{
+	  extsymcount = symcount - hdr->sh_info;
+	  extsymoff = hdr->sh_info;
+	}
+
+      if (extsymcount == 0)
+	continue;
+
+      buf = ((Elf_External_Sym *)
+	     bfd_malloc (extsymcount * sizeof (Elf_External_Sym)));
+      if (buf == NULL)
+	goto no_memory;
+
+      /* Read in the symbol table. */
+      if (bfd_seek (input,
+		     hdr->sh_offset
+		     + extsymoff * sizeof (Elf_External_Sym),
+		      SEEK_SET) != 0
+	 || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym),
+		       extsymcount, input)
+	     != extsymcount * sizeof (Elf_External_Sym)))
+	goto error_return;
+
+      /* Read in any version definitions.  */
+      versymhdr = &elf_tdata (input)->dynversym_hdr;
+      extversym =
+	(Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+      if (extversym == NULL)
+	goto no_memory;
+
+      if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0
+	  || (bfd_read ((PTR) extversym, 1, versymhdr->sh_size, input)
+	      != versymhdr->sh_size))
+	goto error_return;
+
+      ever = extversym + extsymoff;
+      esymend = buf + extsymcount;
+      for (esym = buf; esym < esymend; esym++, ever++)
+	{
+	  const char *name;
+	  Elf_Internal_Sym sym;
+	  Elf_Internal_Versym iver;
+
+	  elf_swap_symbol_in (input, esym, &sym);
+	  if (ELF_ST_BIND (sym.st_info) == STB_LOCAL
+	      || sym.st_shndx == SHN_UNDEF)
+	    continue;
+
+	  name = bfd_elf_string_from_elf_section (input,
+						  hdr->sh_link,
+						  sym.st_name);
+	  if (strcmp (name, h->root.root.string) != 0)
+	    continue;
+
+	  _bfd_elf_swap_versym_in (input, ever, &iver);
+
+	  /* It is defined here and we still get an undefined
+	     symbol. It must be an error. */
+	  if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+	    {
+	      (*_bfd_error_handler)
+		(_("%s: defined in %s"), name,
+		 bfd_get_filename (input));
+	      bfd_set_error (bfd_error_bad_value);
+	      goto error_return;
+	    }
+
+	  if ((iver.vs_vers & VERSYM_VERSION) == 2)
+	    {
+	      /* We found one we can use. This is the first vesion
+		 of the symbol and it is hidden. */
+	      found = true;
+	      break;
+	    }
+	}
+
+      free (buf);
+      free (extversym);
+    }
+
+  return found;
+
+no_memory:
+  bfd_set_error (bfd_error_no_memory);
+error_return:
+  if (buf != NULL)
+    free (buf);
+  if (extversym != NULL)
+    free (extversym);
+  return found;
+}
+
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
 
@@ -2191,6 +2330,22 @@ elf_link_add_object_symbols (abfd, info)
 	  goto error_return;
     }
 
+  {
+    /* We add this to the loaded list.  */
+    struct elf_link_loaded_list *n, **pn;
+
+    n = ((struct elf_link_loaded_list *)
+	 bfd_alloc (abfd, sizeof (struct elf_link_loaded_list)));
+    if (n == NULL)
+      goto error_return;
+    n->next = NULL;
+    n->abfd = abfd;
+    for (pn = &elf_hash_table (info)->loaded; *pn != NULL;
+	 pn = &(*pn)->next)
+      ;
+    *pn = n;
+  }
+
   return true;
 
  error_return:
@@ -5171,9 +5324,22 @@ elf_link_output_extsym (h, data)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
       && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
     {
-      if (! ((*finfo->info->callbacks->undefined_symbol)
-	     (finfo->info, h->root.root.string, h->root.u.undef.abfd,
-	      (asection *) NULL, 0, true)))
+      /* If elf_dt_soname (h->root.u.undef.abfd) != NULL, that means
+	 this DSO is loaded in via a DT_NEEDED entry. In this case,
+	 we do some extra check to see if there is a suitable
+	 definition. */
+      boolean def;
+
+      if (elf_dt_soname (h->root.u.undef.abfd) != NULL)
+	def = elf_link_check_versioned_symbol (finfo->info, h);
+      else
+	def = false; 
+
+      if (!def
+	  && ! ((*finfo->info->callbacks->undefined_symbol)
+		  (finfo->info, h->root.root.string,
+		   h->root.u.undef.abfd, (asection *) NULL,
+		   0, true)))
 	{
 	  eoinfo->failed = true;
 	  return false;


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