From c9e3887989960034fd89d176f72d7e14d5bc3d79 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 6 Nov 2002 19:36:20 +0000 Subject: Adds support for fastcall symbols as used on Microsoft Windows platforms (i386) --- ld/ChangeLog | 17 ++ ld/deffilep.y | 39 +++- ld/emultempl/pe.em | 429 +++++++++++++++++----------------- ld/pe-dll.c | 62 +++-- ld/testsuite/ChangeLog | 8 + ld/testsuite/ld-fastcall/export.s | 3 + ld/testsuite/ld-fastcall/fastcall.exp | 50 ++++ ld/testsuite/ld-fastcall/import.s | 4 + 8 files changed, 371 insertions(+), 241 deletions(-) create mode 100644 ld/testsuite/ld-fastcall/export.s create mode 100644 ld/testsuite/ld-fastcall/fastcall.exp create mode 100644 ld/testsuite/ld-fastcall/import.s (limited to 'ld') diff --git a/ld/ChangeLog b/ld/ChangeLog index 5985d59..3470f70 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,20 @@ +2002-11-07 Danny Smith + + * deffilep.y (def_lex): Handle '@' as first character of an ID. + * pe-dll.c (auto-export): Filter on "_imp_" prefix, not "_imp__". + (make_one): Don't prefix decorated fastcall symbols with '_'. + (pe_process_import_defs): Likewise. + * emultempl/pe.em (pe_fixup_stdcalls): Don't fixup fastcall + symbols to cdecl names or vise-versa. + +2002-10-13 Eric Kohl + + * pe-dll.c (process_def_file): Handle fastcall symbols when + generating undecorated aliases. Don't prefix decorated fastcall + symbols with '_'. + (fill_exported_offsets): Don't prefix decorated fastcall symbols + with '_'. + 2002-10-29 Daniel Jacobowitz * emultempl/aix.em: Use include <> for generated headers. diff --git a/ld/deffilep.y b/ld/deffilep.y index 51d17f8..e9a6310 100644 --- a/ld/deffilep.y +++ b/ld/deffilep.y @@ -1,6 +1,6 @@ %{ /* deffilep.y - parser for .def files */ -/* Copyright 1995, 1997, 1998, 1999, 2000, 2001 +/* Copyright 1995, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -966,9 +966,27 @@ def_lex () return NUMBER; } - if (ISALPHA (c) || strchr ("$:-_?", c)) + if (ISALPHA (c) || strchr ("$:-_?@", c)) { bufptr = 0; + q = c; + put_buf (c); + c = def_getc (); + + if (q == '@') + { + if (ISBLANK (c) ) /* '@' followed by whitespace. */ + return (q); + else if (ISDIGIT (c)) /* '@' followed by digit. */ + { + def_ungetc (c); + return (q); + } +#if TRACE + printf ("lex: @ returns itself\n"); +#endif + } + while (c != EOF && (ISALNUM (c) || strchr ("$:-_?/@", c))) { put_buf (c); @@ -976,14 +994,17 @@ def_lex () } if (c != EOF) def_ungetc (c); - for (i = 0; tokens[i].name; i++) - if (strcmp (tokens[i].name, buffer) == 0) - { + if (ISALPHA (q)) /* Check for tokens. */ + { + for (i = 0; tokens[i].name; i++) + if (strcmp (tokens[i].name, buffer) == 0) + { #if TRACE - printf ("lex: `%s' is a string token\n", buffer); + printf ("lex: `%s' is a string token\n", buffer); #endif - return tokens[i].token; - } + return tokens[i].token; + } + } #if TRACE printf ("lex: `%s' returns ID\n", buffer); #endif @@ -1008,7 +1029,7 @@ def_lex () return ID; } - if (c == '=' || c == '.' || c == '@' || c == ',') + if (c == '=' || c == '.' || c == ',') { #if TRACE printf ("lex: `%c' returns itself\n", c); diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 474b984..0eb3eed 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -794,69 +794,71 @@ pe_fixup_stdcalls () { static int gave_warning_message = 0; struct bfd_link_hash_entry *undef, *sym; - char *at; + if (pe_dll_extra_pe_debug) - { - printf ("%s\n", __FUNCTION__); - } + printf ("%s\n", __FUNCTION__); for (undef = link_info.hash->undefs; undef; undef=undef->next) if (undef->type == bfd_link_hash_undefined) - { - at = strchr (undef->root.string, '@'); - if (at) - { - /* The symbol is a stdcall symbol, so let's look for a cdecl - symbol with the same name and resolve to that */ - char *cname = xstrdup (undef->root.string); - at = strchr (cname, '@'); - *at = 0; - sym = bfd_link_hash_lookup (link_info.hash, cname, 0, 0, 1); - if (sym && sym->type == bfd_link_hash_defined) - { - undef->type = bfd_link_hash_defined; - undef->u.def.value = sym->u.def.value; - undef->u.def.section = sym->u.def.section; - if (pe_enable_stdcall_fixup == -1) - { - einfo (_("Warning: resolving %s by linking to %s\n"), - undef->root.string, cname); - if (! gave_warning_message) - { - gave_warning_message = 1; - einfo(_("Use --enable-stdcall-fixup to disable these warnings\n")); - einfo(_("Use --disable-stdcall-fixup to disable these fixups\n")); - } - } - } - } - else { - /* The symbol is a cdecl symbol, so we look for stdcall - symbols - which means scanning the whole symbol table */ - pe_undef_found_sym = 0; - bfd_link_hash_traverse (link_info.hash, pe_undef_cdecl_match, - (PTR) undef->root.string); - sym = pe_undef_found_sym; - if (sym) - { - undef->type = bfd_link_hash_defined; - undef->u.def.value = sym->u.def.value; - undef->u.def.section = sym->u.def.section; - if (pe_enable_stdcall_fixup == -1) - { - einfo (_("Warning: resolving %s by linking to %s\n"), - undef->root.string, sym->root.string); - if (! gave_warning_message) - { - gave_warning_message = 1; - einfo(_("Use --enable-stdcall-fixup to disable these warnings\n")); - einfo(_("Use --disable-stdcall-fixup to disable these fixups\n")); - } - } - } + char* at = strchr (undef->root.string, '@'); + int lead_at = (*undef->root.string == '@'); + /* For now, don't try to fixup fastcall symbols. */ + + if (at && !lead_at) + { + /* The symbol is a stdcall symbol, so let's look for a + cdecl symbol with the same name and resolve to that. */ + char *cname = xstrdup (undef->root.string /* + lead_at */); + at = strchr (cname, '@'); + *at = 0; + sym = bfd_link_hash_lookup (link_info.hash, cname, 0, 0, 1); + + if (sym && sym->type == bfd_link_hash_defined) + { + undef->type = bfd_link_hash_defined; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + if (pe_enable_stdcall_fixup == -1) + { + einfo (_("Warning: resolving %s by linking to %s\n"), + undef->root.string, cname); + if (! gave_warning_message) + { + gave_warning_message = 1; + einfo(_("Use --enable-stdcall-fixup to disable these warnings\n")); + einfo(_("Use --disable-stdcall-fixup to disable these fixups\n")); + } + } + } + } + else + { + /* The symbol is a cdecl symbol, so we look for stdcall + symbols - which means scanning the whole symbol table */ + pe_undef_found_sym = 0; + bfd_link_hash_traverse (link_info.hash, pe_undef_cdecl_match, + (PTR) undef->root.string); + sym = pe_undef_found_sym; + if (sym) + { + undef->type = bfd_link_hash_defined; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; + if (pe_enable_stdcall_fixup == -1) + { + einfo (_("Warning: resolving %s by linking to %s\n"), + undef->root.string, sym->root.string); + if (! gave_warning_message) + { + gave_warning_message = 1; + einfo(_("Use --enable-stdcall-fixup to disable these warnings\n")); + einfo(_("Use --disable-stdcall-fixup to disable these fixups\n")); + } + } + } + } } - } } static int @@ -865,30 +867,24 @@ make_import_fixup (rel, s) asection *s; { struct symbol_cache_entry *sym = *rel->sym_ptr_ptr; + int addend = 0; if (pe_dll_extra_pe_debug) - { - printf ("arelent: %s@%#lx: add=%li\n", sym->name, - (long) rel->address, (long) rel->addend); - } + printf ("arelent: %s@%#lx: add=%li\n", sym->name, + (long) rel->address, (long) rel->addend); - { - int addend = 0; - if (!bfd_get_section_contents(s->owner, s, &addend, rel->address, sizeof(addend))) - { - einfo (_("%C: Cannot get section contents - auto-import exception\n"), - s->owner, s, rel->address); - } + if (!bfd_get_section_contents(s->owner, s, &addend, rel->address, sizeof(addend))) + einfo (_("%C: Cannot get section contents - auto-import exception\n"), + s->owner, s, rel->address); - if (addend == 0) - pe_create_import_fixup (rel); - else - { - einfo (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"), - s->owner, s, rel->address, sym->name); - einfo ("%X"); - } - } + if (addend == 0) + pe_create_import_fixup (rel); + else + { + einfo (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"), + s->owner, s, rel->address, sym->name); + einfo ("%X"); + } return 1; } @@ -897,59 +893,62 @@ static void pe_find_data_imports () { struct bfd_link_hash_entry *undef, *sym; + for (undef = link_info.hash->undefs; undef; undef=undef->next) { if (undef->type == bfd_link_hash_undefined) { /* C++ symbols are *long* */ char buf[4096]; - if (pe_dll_extra_pe_debug) - { - printf ("%s:%s\n", __FUNCTION__, undef->root.string); - } + + if (pe_dll_extra_pe_debug) + printf ("%s:%s\n", __FUNCTION__, undef->root.string); + sprintf (buf, "__imp_%s", undef->root.string); sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1); + if (sym && sym->type == bfd_link_hash_defined) { if (link_info.pei386_auto_import == -1) info_msg (_("Info: resolving %s by linking to %s (auto-import)\n"), - undef->root.string, buf); - { - bfd *b = sym->u.def.section->owner; - asymbol **symbols; - int nsyms, symsize, i; - - symsize = bfd_get_symtab_upper_bound (b); - symbols = (asymbol **) xmalloc (symsize); - nsyms = bfd_canonicalize_symtab (b, symbols); - - for (i = 0; i < nsyms; i++) - { - if (memcmp(symbols[i]->name, "__head_", - sizeof ("__head_") - 1)) - continue; - if (pe_dll_extra_pe_debug) - { - printf ("->%s\n", symbols[i]->name); - } - pe_data_import_dll = (char*) (symbols[i]->name + - sizeof ("__head_") - 1); - break; - } - } - - pe_walk_relocs_of_symbol (&link_info, undef->root.string, - make_import_fixup); - - /* let's differentiate it somehow from defined */ - undef->type = bfd_link_hash_defweak; - /* we replace original name with __imp_ prefixed, this - 1) may trash memory 2) leads to duplicate symbol generation. - Still, IMHO it's better than having name poluted. */ - undef->root.string = sym->root.string; - undef->u.def.value = sym->u.def.value; - undef->u.def.section = sym->u.def.section; + undef->root.string, buf); + + { + bfd *b = sym->u.def.section->owner; + asymbol **symbols; + int nsyms, symsize, i; + + symsize = bfd_get_symtab_upper_bound (b); + symbols = (asymbol **) xmalloc (symsize); + nsyms = bfd_canonicalize_symtab (b, symbols); + + for (i = 0; i < nsyms; i++) + { + if (memcmp(symbols[i]->name, "__head_", + sizeof ("__head_") - 1)) + continue; + + if (pe_dll_extra_pe_debug) + printf ("->%s\n", symbols[i]->name); + + pe_data_import_dll = (char*) (symbols[i]->name + + sizeof ("__head_") - 1); + break; + } + } + + pe_walk_relocs_of_symbol (&link_info, undef->root.string, + make_import_fixup); + + /* Let's differentiate it somehow from defined. */ + undef->type = bfd_link_hash_defweak; + /* We replace original name with __imp_ prefixed, this + 1) may trash memory 2) leads to duplicate symbol generation. + Still, IMHO it's better than having name poluted. */ + undef->root.string = sym->root.string; + undef->u.def.value = sym->u.def.value; + undef->u.def.section = sym->u.def.section; } } } @@ -962,9 +961,8 @@ pr_sym (h, string) PTR string ATTRIBUTE_UNUSED; { if (pe_dll_extra_pe_debug) - { - printf("+%s\n",h->string); - } + printf ("+%s\n",h->string); + return true; } @@ -972,11 +970,11 @@ pr_sym (h, string) static void gld_${EMULATION_NAME}_after_open () { - if (pe_dll_extra_pe_debug) { bfd *a; struct bfd_link_hash_entry *sym; + printf ("%s()\n", __FUNCTION__); for (sym = link_info.hash->undefs; sym; sym=sym->next) @@ -984,9 +982,7 @@ gld_${EMULATION_NAME}_after_open () bfd_hash_traverse (&link_info.hash->table, pr_sym,NULL); for (a = link_info.input_bfds; a; a = a->link_next) - { - printf("*%s\n",a->filename); - } + printf ("*%s\n",a->filename); } /* Pass the wacky PE command line options into the output bfd. @@ -1216,7 +1212,7 @@ static void gld_${EMULATION_NAME}_before_allocation() { #ifdef TARGET_IS_ppcpe - /* Here we rummage through the found bfds to collect toc information */ + /* Here we rummage through the found bfds to collect toc information. */ { LANG_FOR_EACH_INPUT_STATEMENT (is) { @@ -1228,7 +1224,7 @@ gld_${EMULATION_NAME}_before_allocation() } } - /* We have seen it all. Allocate it, and carry on */ + /* We have seen it all. Allocate it, and carry on. */ ppc_allocate_toc_section (&link_info); #endif /* TARGET_IS_ppcpe */ @@ -1238,7 +1234,7 @@ gld_${EMULATION_NAME}_before_allocation() Here we rummage through the found bfds to collect glue information. FIXME: should this be based on a command line - option? krk@cygnus.com */ + option? krk@cygnus.com. */ { LANG_FOR_EACH_INPUT_STATEMENT (is) { @@ -1252,20 +1248,21 @@ gld_${EMULATION_NAME}_before_allocation() } } - /* We have seen it all. Allocate it, and carry on */ + /* We have seen it all. Allocate it, and carry on. */ bfd_arm_pe_allocate_interworking_sections (& link_info); #endif /* TARGET_IS_armpe */ } #ifdef DLL_SUPPORT /* This is called when an input file isn't recognized as a BFD. We - check here for .DEF files and pull them in automatically. */ + check here for .DEF files and pull them in automatically. */ static int -saw_option(char *option) +saw_option (char * option) { int i; - for (i=0; init[i].ptr; i++) + + for (i = 0; init[i].ptr; i++) if (strcmp (init[i].symbol, option) == 0) return init[i].inited; return 0; @@ -1280,81 +1277,86 @@ gld_${EMULATION_NAME}_unrecognized_file(entry) const char *ext = entry->filename + strlen (entry->filename) - 4; if (strcmp (ext, ".def") == 0 || strcmp (ext, ".DEF") == 0) - { - if (pe_def_file == 0) - pe_def_file = def_file_empty (); - def_file_parse (entry->filename, pe_def_file); - if (pe_def_file) { - int i, buflen=0, len; - char *buf; - for (i=0; inum_exports; i++) - { - len = strlen(pe_def_file->exports[i].internal_name); - if (buflen < len+2) - buflen = len+2; - } - buf = (char *) xmalloc (buflen); - for (i=0; inum_exports; i++) + if (pe_def_file == 0) + pe_def_file = def_file_empty (); + + def_file_parse (entry->filename, pe_def_file); + + if (pe_def_file) { - struct bfd_link_hash_entry *h; - sprintf(buf, "_%s", pe_def_file->exports[i].internal_name); + int i, buflen=0, len; + char *buf; - h = bfd_link_hash_lookup (link_info.hash, buf, true, true, true); - if (h == (struct bfd_link_hash_entry *) NULL) - einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); - if (h->type == bfd_link_hash_new) + for (i = 0; i < pe_def_file->num_exports; i++) { - h->type = bfd_link_hash_undefined; - h->u.undef.abfd = NULL; - bfd_link_add_undef (link_info.hash, h); + len = strlen(pe_def_file->exports[i].internal_name); + if (buflen < len + 2) + buflen = len + 2; } - } - free (buf); - /* def_file_print (stdout, pe_def_file); */ - if (pe_def_file->is_dll == 1) - link_info.shared = 1; + buf = (char *) xmalloc (buflen); - if (pe_def_file->base_address != (bfd_vma)(-1)) - { - pe.ImageBase = - pe_data (output_bfd)->pe_opthdr.ImageBase = - init[IMAGEBASEOFF].value = pe_def_file->base_address; - init[IMAGEBASEOFF].inited = 1; - if (image_base_statement) - image_base_statement->exp = - exp_assop ('=', "__image_base__", exp_intop (pe.ImageBase)); - } + for (i = 0; i < pe_def_file->num_exports; i++) + { + struct bfd_link_hash_entry *h; + + sprintf(buf, "_%s", pe_def_file->exports[i].internal_name); + + h = bfd_link_hash_lookup (link_info.hash, buf, true, true, true); + if (h == (struct bfd_link_hash_entry *) NULL) + einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); + if (h->type == bfd_link_hash_new) + { + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = NULL; + bfd_link_add_undef (link_info.hash, h); + } + } + free (buf); + + /* def_file_print (stdout, pe_def_file); */ + if (pe_def_file->is_dll == 1) + link_info.shared = 1; + + if (pe_def_file->base_address != (bfd_vma)(-1)) + { + pe.ImageBase = + pe_data (output_bfd)->pe_opthdr.ImageBase = + init[IMAGEBASEOFF].value = pe_def_file->base_address; + init[IMAGEBASEOFF].inited = 1; + if (image_base_statement) + image_base_statement->exp = + exp_assop ('=', "__image_base__", exp_intop (pe.ImageBase)); + } #if 0 - /* Not sure if these *should* be set */ - if (pe_def_file->version_major != -1) - { - pe.MajorImageVersion = pe_def_file->version_major; - pe.MinorImageVersion = pe_def_file->version_minor; - } + /* Not sure if these *should* be set */ + if (pe_def_file->version_major != -1) + { + pe.MajorImageVersion = pe_def_file->version_major; + pe.MinorImageVersion = pe_def_file->version_minor; + } #endif - if (pe_def_file->stack_reserve != -1 - && ! saw_option ("__size_of_stack_reserve__")) - { - pe.SizeOfStackReserve = pe_def_file->stack_reserve; - if (pe_def_file->stack_commit != -1) - pe.SizeOfStackCommit = pe_def_file->stack_commit; - } - if (pe_def_file->heap_reserve != -1 - && ! saw_option ("__size_of_heap_reserve__")) - { - pe.SizeOfHeapReserve = pe_def_file->heap_reserve; - if (pe_def_file->heap_commit != -1) - pe.SizeOfHeapCommit = pe_def_file->heap_commit; - } - return true; + if (pe_def_file->stack_reserve != -1 + && ! saw_option ("__size_of_stack_reserve__")) + { + pe.SizeOfStackReserve = pe_def_file->stack_reserve; + if (pe_def_file->stack_commit != -1) + pe.SizeOfStackCommit = pe_def_file->stack_commit; + } + if (pe_def_file->heap_reserve != -1 + && ! saw_option ("__size_of_heap_reserve__")) + { + pe.SizeOfHeapReserve = pe_def_file->heap_reserve; + if (pe_def_file->heap_commit != -1) + pe.SizeOfHeapCommit = pe_def_file->heap_commit; + } + return true; + } } - } #endif return false; - } static boolean @@ -1377,6 +1379,7 @@ gld_${EMULATION_NAME}_recognized_file(entry) if (bfd_get_format (entry->the_bfd) == bfd_object) { const char *ext = entry->filename + strlen (entry->filename) - 4; + if (strcmp (ext, ".dll") == 0 || strcmp (ext, ".DLL") == 0) return pe_implied_import_dll (entry->filename); } @@ -1447,9 +1450,10 @@ gld_${EMULATION_NAME}_finish () pe_dll_generate_def_file (pe_out_def_filename); #endif /* DLL_SUPPORT */ - /* I don't know where .idata gets set as code, but it shouldn't be */ + /* I don't know where .idata gets set as code, but it shouldn't be. */ { asection *asec = bfd_get_section_by_name (output_bfd, ".idata"); + if (asec) { asec->flags &= ~SEC_CODE; @@ -1505,7 +1509,6 @@ struct orphan_save lang_statement_union_type **stmt; }; -/*ARGSUSED*/ static boolean gld_${EMULATION_NAME}_place_orphan (file, s) lang_input_statement_type *file; @@ -1521,7 +1524,6 @@ gld_${EMULATION_NAME}_place_orphan (file, s) secname = bfd_get_section_name (s->owner, s); /* Look through the script to see where to place this section. */ - hold_section_name = xstrdup (secname); if (!link_info.relocateable) { @@ -1655,8 +1657,8 @@ gld_${EMULATION_NAME}_place_orphan (file, s) { char *symname; - /* lang_leave_ouput_section_statement resets stat_ptr. Put - stat_ptr back where we want it. */ + /* lang_leave_ouput_section_statement resets stat_ptr. + Put stat_ptr back where we want it. */ if (place != NULL) stat_ptr = &add; @@ -1752,7 +1754,6 @@ gld_${EMULATION_NAME}_place_orphan (file, s) /* The section name has a '$'. Sort it with the other '$' sections. */ - found_dollar = false; for ( ; *pl != NULL; pl = &(*pl)->header.next) { @@ -1813,26 +1814,24 @@ gld_${EMULATION_NAME}_open_dynamic_archive (arch, search, entry) #endif + 1); - /* Try "libfoo.dll.a" first (preferred explicit import library for dll's */ + /* Try "libfoo.dll.a" first (preferred explicit import library for dll's. */ sprintf (string, "%s/lib%s.dll.a", search->name, filename); if (! ldfile_try_open_bfd (string, entry)) { - /* Try "foo.dll.a" next (alternate explicit import library for dll's */ + /* Try "foo.dll.a" next (alternate explicit import library for dll's. */ sprintf (string, "%s/%s.dll.a", search->name, filename); if (! ldfile_try_open_bfd (string, entry)) { -/* - Try libfoo.a next. Normally, this would be interpreted as a static - library, but it *could* be an import library. For backwards compatibility, - libfoo.a needs to ==precede== libfoo.dll and foo.dll in the search, - or sometimes errors occur when building legacy packages. - - Putting libfoo.a here means that in a failure case (i.e. the library - -lfoo is not found) we will search for libfoo.a twice before - giving up -- once here, and once when searching for a "static" lib. - for a "static" lib. -*/ + /* Try libfoo.a next. Normally, this would be interpreted as a static + library, but it *could* be an import library. For backwards compatibility, + libfoo.a needs to ==precede== libfoo.dll and foo.dll in the search, + or sometimes errors occur when building legacy packages. + + Putting libfoo.a here means that in a failure case (i.e. the library + -lfoo is not found) we will search for libfoo.a twice before + giving up -- once here, and once when searching for a "static" lib. + for a "static" lib. */ /* Try "libfoo.a" (import lib, or static lib, but must take precedence over dll's) */ sprintf (string, "%s/lib%s.a", search->name, filename); @@ -1859,14 +1858,14 @@ gld_${EMULATION_NAME}_open_dynamic_archive (arch, search, entry) } } } - else /* pe_dll_search_prefix not specified */ + else /* pe_dll_search_prefix not specified. */ #endif { - /* Try "libfoo.dll" (preferred dll name) */ + /* Try "libfoo.dll" (preferred dll name). */ sprintf (string, "%s/lib%s.dll", search->name, filename); if (! ldfile_try_open_bfd (string, entry)) { - /* Finally, try "foo.dll" (alternate dll name) */ + /* Finally, try "foo.dll" (alternate dll name). */ sprintf (string, "%s/%s.dll", search->name, filename); if (! ldfile_try_open_bfd (string, entry)) { diff --git a/ld/pe-dll.c b/ld/pe-dll.c index e59c32d..a85bf94 100644 --- a/ld/pe-dll.c +++ b/ld/pe-dll.c @@ -618,7 +618,8 @@ process_def_file (abfd, info) /* This will preserve internal_name, which may have been pointing to the same memory as name, or might not have. */ - char *tmp = xstrdup (pe_def_file->exports[i].name); + int lead_at = (*pe_def_file->exports[i].name =='@'); + char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at); *(strchr (tmp, '@')) = 0; pe_def_file->exports[i].name = tmp; @@ -632,7 +633,8 @@ process_def_file (abfd, info) { if (strchr (pe_def_file->exports[i].name, '@')) { - char *tmp = xstrdup (pe_def_file->exports[i].name); + int lead_at = (*pe_def_file->exports[i].name == '@' ) ; + char *tmp = xstrdup (pe_def_file->exports[i].name + lead_at); *(strchr (tmp, '@')) = 0; if (auto_export (NULL, pe_def_file, tmp)) @@ -701,7 +703,8 @@ process_def_file (abfd, info) { char *name = (char *) xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); - if (pe_details->underscored) + if (pe_details->underscored + && (*pe_def_file->exports[i].internal_name != '@')) { *name = '_'; strcpy (name + 1, pe_def_file->exports[i].internal_name); @@ -915,7 +918,8 @@ fill_exported_offsets (abfd, info) { char *name = (char *) xmalloc (strlen (pe_def_file->exports[i].internal_name) + 2); - if (pe_details->underscored) + if (pe_details->underscored + && (*pe_def_file->exports[i].internal_name != '@')) { *name = '_'; strcpy (name + 1, pe_def_file->exports[i].internal_name); @@ -1811,15 +1815,27 @@ make_one (exp, parent) id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2); id4 = quick_section (abfd, ".idata$4", SEC_HAS_CONTENTS, 2); id6 = quick_section (abfd, ".idata$6", SEC_HAS_CONTENTS, 2); - if (! exp->flag_data) - quick_symbol (abfd, U (""), exp->internal_name, "", tx, BSF_GLOBAL, 0); - quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, BSF_GLOBAL, 0); - quick_symbol (abfd, U ("_imp__"), exp->internal_name, "", id5, BSF_GLOBAL, 0); - /* Symbol to reference ord/name of imported - data symbol, used to implement auto-import. */ - if (exp->flag_data) - quick_symbol (abfd, U("_nm__"), exp->internal_name, "", id6, - BSF_GLOBAL,0); + + if (*exp->internal_name == '@') + { + if (! exp->flag_data) + quick_symbol (abfd, "", exp->internal_name, "", tx, BSF_GLOBAL, 0); + quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, BSF_GLOBAL, 0); + quick_symbol (abfd, U ("_imp_"), exp->internal_name, "", id5, BSF_GLOBAL, 0); + /* Fastcall applies only to functions, + so no need for auto-import symbol. */ + } + else + { + if (! exp->flag_data) + quick_symbol (abfd, U (""), exp->internal_name, "", tx, BSF_GLOBAL, 0); + quick_symbol (abfd, U ("_head_"), dll_symname, "", UNDSEC, BSF_GLOBAL, 0); + quick_symbol (abfd, U ("_imp__"), exp->internal_name, "", id5, BSF_GLOBAL, 0); + /* Symbol to reference ord/name of imported + data symbol, used to implement auto-import. */ + if (exp->flag_data) + quick_symbol (abfd, U("_nm__"), exp->internal_name, "", id6, BSF_GLOBAL,0); + } if (pe_dll_compat_implib) quick_symbol (abfd, U ("__imp_"), exp->internal_name, "", id5, BSF_GLOBAL, 0); @@ -2231,20 +2247,32 @@ pe_process_import_defs (output_bfd, link_info) { def_file_export exp; struct bfd_link_hash_entry *blhe; - + int lead_at = (*pe_def_file->imports[i].internal_name == '@'); /* See if we need this import. */ char *name = (char *) xmalloc (strlen (pe_def_file->imports[i].internal_name) + 2 + 6); - sprintf (name, "%s%s", U (""), pe_def_file->imports[i].internal_name); + + if (lead_at) + sprintf (name, "%s%s", "", pe_def_file->imports[i].internal_name); + else + sprintf (name, "%s%s",U (""), pe_def_file->imports[i].internal_name); + blhe = bfd_link_hash_lookup (link_info->hash, name, false, false, false); + if (!blhe || (blhe && blhe->type != bfd_link_hash_undefined)) { - sprintf (name, "%s%s", U ("_imp__"), - pe_def_file->imports[i].internal_name); + if (lead_at) + sprintf (name, "%s%s", U ("_imp_"), + pe_def_file->imports[i].internal_name); + else + sprintf (name, "%s%s", U ("_imp__"), + pe_def_file->imports[i].internal_name); + blhe = bfd_link_hash_lookup (link_info->hash, name, false, false, false); } free (name); + if (blhe && blhe->type == bfd_link_hash_undefined) { bfd *one; diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index b10913b..744f7fc 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2002-11-07 Casper S. Hornstrup + + * ld-fastcall: New directory for testing fastcall support. + * ld-fastcall/export.s: New file for testing fastcall symbol + handling. + * ld-fastcall/import.s: Likewise. + * ld-fastcall/fastcall.exp: Likewise. + 2002-11-03 Kaz Kojima * ld-sh/rd-sh.exp: Add -isa=SHcompact to ASFLAGS for SH-5. diff --git a/ld/testsuite/ld-fastcall/export.s b/ld/testsuite/ld-fastcall/export.s new file mode 100644 index 0000000..d8df66d --- /dev/null +++ b/ld/testsuite/ld-fastcall/export.s @@ -0,0 +1,3 @@ + .text +.globl @extern_fastcall_function@0 +@extern_fastcall_function@0: diff --git a/ld/testsuite/ld-fastcall/fastcall.exp b/ld/testsuite/ld-fastcall/fastcall.exp new file mode 100644 index 0000000..896adb9 --- /dev/null +++ b/ld/testsuite/ld-fastcall/fastcall.exp @@ -0,0 +1,50 @@ +# Test that the linker can handle fastcall symbols correctly. +# Copyright 2002 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +set testname "ld (fastcall symbols)" + +if {![istarget "i*86-*-*"]} { + return +} + +if {![istarget "i*86-*-*pe*"] \ + && ![istarget "i*86-*-cygwin*"] \ + && ![istarget "i*86-*-mingw32*"] } { + set target_xfail "yes" +} else { + set target_xfail "no" +} + +set ldflags "" + +if ![ld_assemble $as $srcdir/$subdir/export.s tmpdir/export.o] { + verbose "Unable to assemble test file!" 1 + unresolved $testname + return +} + +if ![ld_assemble $as $srcdir/$subdir/import.s tmpdir/import.o] { + verbose "Unable to assemble test file!" 1 + unresolved $testname + return +} + +if ![ld_simple_link $ld tmpdir/extern.x "$ldflags tmpdir/export.o tmpdir/import.o"] { + fail $testname +} else { + pass $testname +} diff --git a/ld/testsuite/ld-fastcall/import.s b/ld/testsuite/ld-fastcall/import.s new file mode 100644 index 0000000..e33918b --- /dev/null +++ b/ld/testsuite/ld-fastcall/import.s @@ -0,0 +1,4 @@ + .text +.globl _start +_start: + call @extern_fastcall_function@0 -- cgit v1.1