diff options
author | Kai Tietz <kai.tietz@onevision.com> | 2011-04-13 12:53:36 +0000 |
---|---|---|
committer | Kai Tietz <kai.tietz@onevision.com> | 2011-04-13 12:53:36 +0000 |
commit | db17156eaa6dbb38436c6a01712688e35389e773 (patch) | |
tree | d21e8952f2eee10e1e62512a1c98b7857c211bf5 | |
parent | 7f880bc3d4d91558b61f7460dabacc04c0ed44a3 (diff) | |
download | fsf-binutils-gdb-db17156eaa6dbb38436c6a01712688e35389e773.zip fsf-binutils-gdb-db17156eaa6dbb38436c6a01712688e35389e773.tar.gz fsf-binutils-gdb-db17156eaa6dbb38436c6a01712688e35389e773.tar.bz2 |
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.
-rw-r--r-- | ld/ChangeLog | 17 | ||||
-rw-r--r-- | ld/deffile.h | 4 | ||||
-rw-r--r-- | ld/deffilep.y | 195 | ||||
-rw-r--r-- | ld/pe-dll.c | 20 |
4 files changed, 214 insertions, 22 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog index a139a81..855912d 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,20 @@ +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. + 2011-04-11 Chris Quenelle <chris.quenelle@oracle.com> * scripttempl/elf.sc (.exception_ranges): Add new section. diff --git a/ld/deffile.h b/ld/deffile.h index 8ddd070..ca8c779 100644 --- a/ld/deffile.h +++ b/ld/deffile.h @@ -105,10 +105,10 @@ extern def_file *def_file_parse (const char *, def_file *); 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 diff --git a/ld/deffilep.y b/ld/deffilep.y index 36214d9..a1cd993 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 diff --git a/ld/pe-dll.c b/ld/pe-dll.c index 7de718a..c8abf4d 100644 --- a/ld/pe-dll.c +++ b/ld/pe-dll.c @@ -751,10 +751,13 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * 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 ATTRIBUTE_UNUSED, struct bfd_link_info * 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 ATTRIBUTE_UNUSED, struct bfd_link_info * 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 *filename) 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 *filename) || (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", |