summaryrefslogtreecommitdiff
path: root/ld/deffilep.y
diff options
context:
space:
mode:
authorKai Tietz <kai.tietz@onevision.com>2011-04-13 12:53:35 +0000
committerKai Tietz <kai.tietz@onevision.com>2011-04-13 12:53:35 +0000
commitcf9de0d7b580d7a37293817f0496183f3b7299e2 (patch)
treea6d6ea99b69567aa54ee0e27311244b3346f4b7b /ld/deffilep.y
parent72755b1f95fcbb70580f28723fc8b961acc0df41 (diff)
downloadbinutils-redhat-cf9de0d7b580d7a37293817f0496183f3b7299e2.tar.gz
2011-04-13 Kai Tietz <ktietz@redhat.com>
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.
Diffstat (limited to 'ld/deffilep.y')
-rw-r--r--ld/deffilep.y195
1 files changed, 182 insertions, 13 deletions
diff --git a/ld/deffilep.y b/ld/deffilep.y
index 36214d9fc0..a1cd99370b 100644
--- a/ld/deffilep.y
+++ b/ld/deffilep.y
@@ -534,16 +534,105 @@ def_file_print (FILE *file, def_file *fdef)
}
#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 char *name)
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