diff options
Diffstat (limited to 'ld')
-rw-r--r-- | ld/emultempl/emulation.em | 3 | ||||
-rw-r--r-- | ld/emultempl/pe.em | 50 | ||||
-rw-r--r-- | ld/ld.texi | 4 | ||||
-rw-r--r-- | ld/ldemul.c | 8 | ||||
-rw-r--r-- | ld/ldemul.h | 8 | ||||
-rw-r--r-- | ld/ldlang.c | 37 | ||||
-rw-r--r-- | ld/ldmisc.c | 10 |
7 files changed, 90 insertions, 30 deletions
diff --git a/ld/emultempl/emulation.em b/ld/emultempl/emulation.em index 7fe821a..8ff71d6 100644 --- a/ld/emultempl/emulation.em +++ b/ld/emultempl/emulation.em @@ -36,6 +36,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = ${LDEMUL_EMIT_CTF_EARLY-NULL}, ${LDEMUL_ACQUIRE_STRINGS_FOR_CTF-NULL}, ${LDEMUL_NEW_DYNSYM_FOR_CTF-NULL}, - ${LDEMUL_PRINT_SYMBOL-NULL} + ${LDEMUL_PRINT_SYMBOL-NULL}, + ${LDEMUL_FIND_START_SYMBOL-NULL} }; EOF diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 50bb082..b522687 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -2448,6 +2448,55 @@ gld${EMULATION_NAME}_find_potential_libraries { return ldfile_open_file_search (name, entry, "", ".lib"); } + +static struct bfd_link_hash_entry * +gld${EMULATION_NAME}_find_alt_start_symbol + (struct bfd_sym_chain *entry) +{ +#if defined (TARGET_IS_i386pe) + bool entry_has_stdcall_suffix; +#endif + struct bfd_link_hash_entry *h; + size_t entry_name_len; + char *symbol_name; + const char *prefix; + const char *suffix; + + entry_name_len = strlen (entry->name); + + if (is_underscoring ()) + prefix = "_"; + else + prefix = ""; + +#if defined (TARGET_IS_i386pe) + if ((entry_name_len > 2 && entry->name[entry_name_len-2] == '@' && ISDIGIT (entry->name[entry_name_len-1])) + || (entry_name_len > 3 && entry->name[entry_name_len-3] == '@' && ISDIGIT (entry->name[entry_name_len-2]) && ISDIGIT (entry->name[entry_name_len-1])) + || (entry_name_len > 4 && entry->name[entry_name_len-4] == '@' && ISDIGIT (entry->name[entry_name_len-3]) && ISDIGIT (entry->name[entry_name_len-2]) && ISDIGIT (entry->name[entry_name_len-1]))) + entry_has_stdcall_suffix = true; + else + entry_has_stdcall_suffix = false; + + if (!entry_has_stdcall_suffix && (bfd_link_dll (&link_info) || dll)) + suffix = "@12"; + else if (!entry_has_stdcall_suffix && pe_subsystem == 1 /* NT kernel driver */) + suffix = "@8"; + else +#endif + suffix = ""; + + if (*prefix == '\0' && *suffix == '\0') + return NULL; + + symbol_name = xmalloc (entry_name_len + 5); + strcpy (symbol_name, prefix); + strcat (symbol_name, entry->name); + strcat (symbol_name, suffix); + + h = bfd_link_hash_lookup (link_info.hash, symbol_name, false, false, true); + free (symbol_name); + return h; +} static char * gld${EMULATION_NAME}_get_script (int *isfile) @@ -2526,5 +2575,6 @@ LDEMUL_UNRECOGNIZED_FILE=gld${EMULATION_NAME}_unrecognized_file LDEMUL_LIST_OPTIONS=gld${EMULATION_NAME}_list_options LDEMUL_RECOGNIZED_FILE=gld${EMULATION_NAME}_recognized_file LDEMUL_FIND_POTENTIAL_LIBRARIES=gld${EMULATION_NAME}_find_potential_libraries +LDEMUL_FIND_START_SYMBOL=gld${EMULATION_NAME}_find_alt_start_symbol source_em ${srcdir}/emultempl/emulation.em @@ -531,7 +531,9 @@ named @var{entry}, the linker will try to parse @var{entry} as a number, and use that as the entry address (the number will be interpreted in base 10; you may use a leading @samp{0x} for base 16, or a leading @samp{0} for base 8). @xref{Entry Point}, for a discussion of defaults -and other ways of specifying the entry point. +and other ways of specifying the entry point. For i386 PE, @var{entry} +can be also the original function name (without the leading underscore +and/or the trailing stdcall @samp{@@number} when applicable). @kindex --exclude-libs @item --exclude-libs @var{lib},@var{lib},... diff --git a/ld/ldemul.c b/ld/ldemul.c index dce0d38..35f91a2 100644 --- a/ld/ldemul.c +++ b/ld/ldemul.c @@ -35,6 +35,14 @@ static ld_emulation_xfer_type *ld_emulation; +struct bfd_link_hash_entry * +ldemul_find_alt_start_symbol (struct bfd_sym_chain *entry) +{ + if (ld_emulation->find_alt_start_symbol) + return ld_emulation->find_alt_start_symbol (entry); + return NULL; +} + void ldemul_hll (char *name) { diff --git a/ld/ldemul.h b/ld/ldemul.h index aa014ae..c58d4c2 100644 --- a/ld/ldemul.h +++ b/ld/ldemul.h @@ -115,9 +115,10 @@ extern void ldemul_acquire_strings_for_ctf (struct ctf_dict *, struct elf_strtab_hash *); extern void ldemul_new_dynsym_for_ctf (struct ctf_dict *, int symidx, struct elf_internal_sym *); - extern bool ldemul_print_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr); +extern struct bfd_link_hash_entry * ldemul_find_alt_start_symbol + (struct bfd_sym_chain *); typedef struct ld_emulation_xfer_struct { /* Run before parsing the command line and script file. @@ -259,6 +260,11 @@ typedef struct ld_emulation_xfer_struct { bool (*print_symbol) (struct bfd_link_hash_entry *hash_entry, void *ptr); + /* Called when ENTRY->name cannot be found by a direct lookup in INFO->hash. + Allows emulations to try variations of the name. */ + struct bfd_link_hash_entry * (*find_alt_start_symbol) + (struct bfd_sym_chain *entry); + } ld_emulation_xfer_type; typedef enum { diff --git a/ld/ldlang.c b/ld/ldlang.c index 0bb9e17..e036817 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -2486,11 +2486,18 @@ lang_map (void) } static bool +is_defined (struct bfd_link_hash_entry *h) +{ + return h != NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak); +} + +static bool sort_def_symbol (struct bfd_link_hash_entry *hash_entry, void *info ATTRIBUTE_UNUSED) { - if ((hash_entry->type == bfd_link_hash_defined - || hash_entry->type == bfd_link_hash_defweak) + if (is_defined (hash_entry) && hash_entry->u.def.section->owner != link_info.output_bfd && hash_entry->u.def.section->owner != NULL) { @@ -4184,9 +4191,7 @@ ldlang_check_require_defined_symbols (void) h = bfd_link_hash_lookup (link_info.hash, ptr->name, false, false, true); - if (h == NULL - || (h->type != bfd_link_hash_defined - && h->type != bfd_link_hash_defweak)) + if (! is_defined (h)) einfo(_("%X%P: required symbol `%s' not defined\n"), ptr->name); } } @@ -4892,9 +4897,7 @@ print_assignment (lang_assignment_statement_type *assignment, h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst, false, false, true); - if (h != NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak)) + if (is_defined (h)) { value = h->u.def.value; value += h->u.def.section->output_section->vma; @@ -4939,8 +4942,7 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr) { asection *sec = (asection *) ptr; - if ((hash_entry->type == bfd_link_hash_defined - || hash_entry->type == bfd_link_hash_defweak) + if (is_defined (hash_entry) && sec == hash_entry->u.def.section) { print_spaces (SECTION_NAME_MAP_LENGTH); @@ -5062,7 +5064,8 @@ print_input_section (asection *i, bool is_discarded) } print_spaces (SECTION_NAME_MAP_LENGTH - len); - if (i->output_section != NULL + if ((i->flags & SEC_EXCLUDE) == 0 + && i->output_section != NULL && i->output_section->owner == link_info.output_bfd) addr = i->output_section->vma + i->output_offset; else @@ -7233,9 +7236,7 @@ lang_end (void) { h = bfd_link_hash_lookup (link_info.hash, sym->name, false, false, false); - if (h != NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak) + if (is_defined (h) && !bfd_is_const_section (h->u.def.section)) break; } @@ -7254,9 +7255,11 @@ lang_end (void) h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name, false, false, true); - if (h != NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak) + + if (! is_defined (h) || h->u.def.section->output_section == NULL) + h = ldemul_find_alt_start_symbol (&entry_symbol); + + if (is_defined (h) && h->u.def.section->output_section != NULL) { bfd_vma val; diff --git a/ld/ldmisc.c b/ld/ldmisc.c index 9ee0781..3f305fa 100644 --- a/ld/ldmisc.c +++ b/ld/ldmisc.c @@ -42,7 +42,6 @@ %C clever filename:linenumber with function %D like %C, but no function name %E current bfd error or errno - %F error is fatal %G like %D, but only function name %H like %C but in addition emit section+offset %P print program name @@ -70,7 +69,6 @@ void vfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning) { - bool isfatal = false; const char *scan; int arg_type; unsigned int arg_count = 0; @@ -280,11 +278,6 @@ vfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning) } break; - case 'F': - /* Error is fatal. */ - isfatal = true; - break; - case 'P': /* Print program name. */ fprintf (fp, "%s", program_name); @@ -586,9 +579,6 @@ vfinfo (FILE *fp, const char *fmt, va_list ap, bool is_warning) if (is_warning && config.fatal_warnings) config.make_executable = false; - - if (isfatal) - xexit (1); } /* Format info message and print on stdout. */ |