[patch ld]: Avoid duplicates in internal import/export element lists

Kai Tietz ktietz70@googlemail.com
Wed Apr 13 15:48:00 GMT 2011


2011/4/13 Kai Tietz <ktietz70@googlemail.com>:
> Hello,
>
> by investigating for the issue about inlines in combination with
> dllexport attribute I found
> issues in ld's def-file handling of import and export list.  This
> attached patch might fix
> also PR binutils/12658 issue.
>
> ChangeLog ld/
>
> 2011-04-13  Kai Tietz
>
>        PR binutils/12658
>        * deffile.h (def_file_add_export): Add is_dup argument.
>        (def_file_add_import): Likewise.
>        * deffilep.y (are_names_equal): New helper.
>        (cmp_export_elem): New helper.
>        (find_export_in_list): Add search routine for exports.
>        (def_file_add_export): Check for duplicates.
>        (cmp_import_elem): New helper.
>        (find_import_in_list): Add search routine for imports.
>        (def_file_add_import): Check for duplicates.
>        (def_exports): Handle duplicates.
>        (def_imports): Likewise.
>        * pe-dll.c (process_def_file_and_drectve): Likewise.
>        (pe_implied_import_dll): Likewise.
>
> Tested for x86_64-w64-mingw32 and i686-w64-mingw32. Ok for apply?

I noticed that for imports I wasn't sorting and checking for ordinals.
The attached patch fixes that.

Regards,
Kai
-------------- next part --------------
Index: src/ld/deffile.h
===================================================================
--- src.orig/ld/deffile.h	2011-02-15 18:40:12.000000000 +0100
+++ src/ld/deffile.h	2011-04-13 09:31:20.825029400 +0200
@@ -105,10 +105,10 @@ extern def_file *def_file_parse (const c
 extern void def_file_free (def_file *);
 extern def_file_export *def_file_add_export (def_file *, const char *,
 					     const char *, int,
-					     const char *);
+					     const char *, int *);
 extern def_file_import *def_file_add_import (def_file *, const char *,
 					     const char *, int, const char *,
-					     const char *);
+					     const char *, int *);
 extern void def_file_add_directive (def_file *, const char *, int);
 extern def_file_module *def_get_module (def_file *, const char *);
 #ifdef DEF_FILE_PRINT
Index: src/ld/deffilep.y
===================================================================
--- src.orig/ld/deffilep.y	2010-07-10 18:03:44.000000000 +0200
+++ src/ld/deffilep.y	2011-04-13 11:50:55.837020900 +0200
@@ -534,16 +534,105 @@ def_file_print (FILE *file, def_file *fd
 }
 #endif
 
+/* Helper routine to check for identity of string pointers,
+   which might be NULL.  */
+
+static int
+are_names_equal (const char *s1, const char *s2)
+{
+  if (!s1 && !s2)
+    return 0;
+  if (!s1 || !s2)
+    return (!s1 ? -1 : 1);
+  return strcmp (s1, s2);
+}
+
+static int
+cmp_export_elem (const def_file_export *e, const char *ex_name,
+		 const char *in_name, const char *its_name,
+		 int ord)
+{
+  int r;
+
+  if ((r = are_names_equal (ex_name, e->name)) != 0)
+    return r;
+  if ((r = are_names_equal (in_name, e->internal_name)) != 0)
+    return r;
+  if ((r = are_names_equal (its_name, e->its_name)) != 0)
+    return r;
+  return (ord - e->ordinal);
+}
+
+/* Search the position of the identical element, or returns the position
+   of the next higher element. If last valid element is smaller, then MAX
+   is returned.  */
+
+static int
+find_export_in_list (def_file_export *b, int max,
+		     const char *ex_name, const char *in_name,
+		     const char *its_name, int ord, int *is_ident)
+{
+  int e, l, r, p;
+
+  *is_ident = 0;
+  if (!max)
+    return 0;
+  if ((e = cmp_export_elem (b, ex_name, in_name, its_name, ord)) <= 0)
+    return 0;
+  if (max == 1)
+    return 1;
+  if ((e = cmp_export_elem (b + (max - 1), ex_name, in_name, its_name, ord)) > 0)
+    return max;
+  else if (!e || max == 2)
+    return max - 1;
+  l = 0; r = max - 1;
+  while (l < r)
+    {
+      p = (l + r) / 2;
+      e = cmp_export_elem (b + p, ex_name, in_name, its_name, ord);
+      if (!e)
+        {
+          *is_ident = 1;
+          return p;
+        }
+      else if (e < 0)
+        r = p - 1;
+      else if (e > 0)
+        l = p + 1;
+    }
+  if ((e = cmp_export_elem (b + l, ex_name, in_name, its_name, ord)) > 0)
+    ++l;
+  else if (!e)
+    *is_ident = 1;
+  return l;
+}
+
 def_file_export *
 def_file_add_export (def_file *fdef,
 		     const char *external_name,
 		     const char *internal_name,
 		     int ordinal,
-		     const char *its_name)
+		     const char *its_name,
+		     int *is_dup)
 {
   def_file_export *e;
+  int pos;
   int max_exports = ROUND_UP(fdef->num_exports, 32);
 
+  if (internal_name && !external_name)
+    external_name = internal_name;
+  if (external_name && !internal_name)
+    internal_name = external_name;
+
+  /* We need to avoid duplicates.  */
+  *is_dup = 0;
+  pos = find_export_in_list (fdef->exports, fdef->num_exports,
+		     external_name, internal_name,
+		     its_name, ordinal, is_dup);
+
+  if (*is_dup != 0)
+    return (fdef->exports + pos);
+
   if (fdef->num_exports >= max_exports)
     {
       max_exports = ROUND_UP(fdef->num_exports + 1, 32);
@@ -553,12 +642,11 @@ def_file_add_export (def_file *fdef,
       else
 	fdef->exports = xmalloc (max_exports * sizeof (def_file_export));
     }
-  e = fdef->exports + fdef->num_exports;
+
+  e = fdef->exports + pos;
+  if (pos != fdef->num_exports)
+    memmove (&e[1], e, (sizeof (def_file_export) * (fdef->num_exports - pos)));
   memset (e, 0, sizeof (def_file_export));
-  if (internal_name && !external_name)
-    external_name = internal_name;
-  if (external_name && !internal_name)
-    internal_name = external_name;
   e->name = xstrdup (external_name);
   e->internal_name = xstrdup (internal_name);
   e->its_name = (its_name ? xstrdup (its_name) : NULL);
@@ -594,17 +682,88 @@ def_stash_module (def_file *fdef, const
   return s;
 }
 
+static int
+cmp_import_elem (const def_file_import *e, const char *ex_name,
+		 const char *in_name, const char *module,
+		 int ord)
+{
+  int r;
+
+  if ((r = are_names_equal (ex_name, e->name)) != 0)
+    return r;
+  if ((r = are_names_equal (in_name, e->internal_name)) != 0)
+    return r;
+  if (ord != e->ordinal)
+    return (ord < e->ordinal ? -1 : 1);
+  return are_names_equal (module, (e->module ? e->module->name : NULL));
+}
+
+/* Search the position of the identical element, or returns the position
+   of the next higher element. If last valid element is smaller, then MAX
+   is returned.  */
+
+static int
+find_import_in_list (def_file_import *b, int max,
+		     const char *ex_name, const char *in_name,
+		     const char *module, int ord, int *is_ident)
+{
+  int e, l, r, p;
+
+  *is_ident = 0;
+  if (!max)
+    return 0;
+  if ((e = cmp_import_elem (b, ex_name, in_name, module, ord)) <= 0)
+    return 0;
+  if (max == 1)
+    return 1;
+  if ((e = cmp_import_elem (b + (max - 1), ex_name, in_name, module, ord)) > 0)
+    return max;
+  else if (!e || max == 2)
+    return max - 1;
+  l = 0; r = max - 1;
+  while (l < r)
+    {
+      p = (l + r) / 2;
+      e = cmp_import_elem (b + p, ex_name, in_name, module, ord);
+      if (!e)
+        {
+          *is_ident = 1;
+          return p;
+        }
+      else if (e < 0)
+        r = p - 1;
+      else if (e > 0)
+        l = p + 1;
+    }
+  if ((e = cmp_import_elem (b + l, ex_name, in_name, module, ord)) > 0)
+    ++l;
+  else if (!e)
+    *is_ident = 1;
+  return l;
+}
+
 def_file_import *
 def_file_add_import (def_file *fdef,
 		     const char *name,
 		     const char *module,
 		     int ordinal,
 		     const char *internal_name,
-		     const char *its_name)
+		     const char *its_name,
+		     int *is_dup)
 {
   def_file_import *i;
+  int pos;
   int max_imports = ROUND_UP (fdef->num_imports, 16);
 
+  /* We need to avoid here duplicates.  */
+  *is_dup = 0;
+  pos = find_import_in_list (fdef->imports, fdef->num_imports,
+			     name,
+			     (!internal_name ? name : internal_name),
+			     module, ordinal, is_dup);
+  if (*is_dup != 0)
+    return fdef->imports + pos;
+
   if (fdef->num_imports >= max_imports)
     {
       max_imports = ROUND_UP (fdef->num_imports+1, 16);
@@ -615,7 +774,9 @@ def_file_add_import (def_file *fdef,
       else
 	fdef->imports = xmalloc (max_imports * sizeof (def_file_import));
     }
-  i = fdef->imports + fdef->num_imports;
+  i = fdef->imports + pos;
+  if (pos != fdef->num_imports)
+    memmove (&i[1], i, (sizeof (def_file_import) * (fdef->num_imports - pos)));
   memset (i, 0, sizeof (def_file_import));
   if (name)
     i->name = xstrdup (name);
@@ -849,6 +1010,7 @@ def_exports (const char *external_name,
 	     const char *its_name)
 {
   def_file_export *dfe;
+  int is_dup = 0;
 
   if (!internal_name && external_name)
     internal_name = external_name;
@@ -857,7 +1019,13 @@ def_exports (const char *external_name,
 #endif
 
   dfe = def_file_add_export (def, external_name, internal_name, ordinal,
-  							 its_name);
+			     its_name, &is_dup);
+
+  /* We might check here for flag redefinition and warn.  For now we
+     ignore duplicates silently.  */
+  if (is_dup)
+    return;
+
   if (flags & 1)
     dfe->flag_noname = 1;
   if (flags & 2)
@@ -877,15 +1045,16 @@ def_import (const char *internal_name,
 	    const char *its_name)
 {
   char *buf = 0;
-  const char *ext = dllext ? dllext : "dll";    
+  const char *ext = dllext ? dllext : "dll";
+  int is_dup = 0;
    
   buf = xmalloc (strlen (module) + strlen (ext) + 2);
   sprintf (buf, "%s.%s", module, ext);
   module = buf;
 
-  def_file_add_import (def, name, module, ordinal, internal_name, its_name);
-  if (buf)
-    free (buf);
+  def_file_add_import (def, name, module, ordinal, internal_name, its_name,
+		       &is_dup);
+  free (buf);
 }
 
 static void
Index: src/ld/pe-dll.c
===================================================================
--- src.orig/ld/pe-dll.c	2011-02-28 19:24:45.000000000 +0100
+++ src/ld/pe-dll.c	2011-04-13 09:32:52.969730300 +0200
@@ -751,10 +751,13 @@ process_def_file_and_drectve (bfd *abfd
 
 		  if (auto_export (b, pe_def_file, sn))
 		    {
+		      int is_dup = 0;
 		      def_file_export *p;
-		      p=def_file_add_export (pe_def_file, sn, 0, -1, NULL);
+		      p = def_file_add_export (pe_def_file, sn, 0, -1,
+					       NULL, &is_dup);
 		      /* Fill data flag properly, from dlltool.c.  */
-		      p->flag_data = !(symbols[j]->flags & BSF_FUNCTION);
+		      if (!is_dup)
+		        p->flag_data = !(symbols[j]->flags & BSF_FUNCTION);
 		    }
 		}
 	    }
@@ -801,6 +804,7 @@ process_def_file_and_drectve (bfd *abfd
 
 	  if (strchr (pe_def_file->exports[i].name, '@'))
 	    {
+	      int is_dup = 1;
 	      int lead_at = (*pe_def_file->exports[i].name == '@');
 	      char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at);
 
@@ -808,9 +812,9 @@ process_def_file_and_drectve (bfd *abfd
 	      if (auto_export (NULL, pe_def_file, tmp))
 		def_file_add_export (pe_def_file, tmp,
 				     pe_def_file->exports[i].internal_name,
-				     -1, NULL);
-	      else
-		free (tmp);
+				     -1, NULL, &is_dup);
+	      if (is_dup)
+	        free (tmp);
 	    }
 	}
     }
@@ -3146,6 +3150,7 @@ pe_implied_import_dll (const char *filen
 	 exported in buggy auto-import releases.  */
       if (! CONST_STRNEQ (erva + name_rva, "__nm_"))
  	{
+	  int is_dup = 0;
  	  /* is_data is true if the address is in the data, rdata or bss
 	     segment.  */
  	  is_data =
@@ -3154,9 +3159,10 @@ pe_implied_import_dll (const char *filen
 	    || (func_rva >= bss_start && func_rva < bss_end);
 
 	  imp = def_file_add_import (pe_def_file, erva + name_rva,
-				     dllname, i, 0, NULL);
+				     dllname, i, 0, NULL, &is_dup);
  	  /* Mark symbol type.  */
- 	  imp->data = is_data;
+ 	  if (!is_dup)
+ 	    imp->data = is_data;
 
  	  if (pe_dll_extra_pe_debug)
 	    printf ("%s dll-name: %s sym: %s addr: 0x%lx %s\n",


More information about the Binutils mailing list