This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
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;