${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
{
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;
+}
\f
static char *
gld${EMULATION_NAME}_get_script (int *isfile)
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
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},...
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)
{
(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.
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 {
config.map_file);
}
+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)
{
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);
}
}
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;
{
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);
{
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;
}
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;