[binutils-gdb] BFD linker: Allow target backends to provide alternate entry names.

Nick Clifton nickc@sourceware.org
Fri Apr 25 11:32:54 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a965df05e48d98298f73e49d28028b3a760eeeab

commit a965df05e48d98298f73e49d28028b3a760eeeab
Author: Pali Roh?r <pali@kernel.org>
Date:   Fri Apr 25 12:31:48 2025 +0100

    BFD linker: Allow target backends to provide alternate entry names.
    
    PR 30144

Diff:
---
 ld/emultempl/emulation.em |  3 ++-
 ld/emultempl/pe.em        | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 ld/ld.texi                |  4 +++-
 ld/ldemul.c               |  8 ++++++++
 ld/ldemul.h               |  8 +++++++-
 ld/ldlang.c               | 34 +++++++++++++++++---------------
 6 files changed, 88 insertions(+), 19 deletions(-)

diff --git a/ld/emultempl/emulation.em b/ld/emultempl/emulation.em
index 7fe821a519d..8ff71d60352 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 50bb082770d..b522687c1d5 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
diff --git a/ld/ld.texi b/ld/ld.texi
index e8e09f8ec1c..ea4536a9112 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -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 dce0d385fe0..35f91a287ca 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 aa014ae25c8..c58d4c26b95 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 97fdb91da33..e0368171fa9 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -2485,12 +2485,19 @@ lang_map (void)
 			      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)
     {
@@ -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);
@@ -7234,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;
 	}
@@ -7255,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;


More information about the Binutils-cvs mailing list