]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
BFD linker: Allow target backends to provide alternate entry names.
authorPali Roh?r <pali@kernel.org>
Fri, 25 Apr 2025 11:31:48 +0000 (12:31 +0100)
committerNick Clifton <nickc@redhat.com>
Fri, 25 Apr 2025 11:31:48 +0000 (12:31 +0100)
PR 30144

ld/emultempl/emulation.em
ld/emultempl/pe.em
ld/ld.texi
ld/ldemul.c
ld/ldemul.h
ld/ldlang.c

index 7fe821a519d09086af445ba15613ccca6edab5d3..8ff71d603527dab387b86847990aa981079ef2d3 100644 (file)
@@ -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
index 50bb082770da9202b47a797b30b86dbb8a4b5bf8..b522687c1d5b4e4fb1d3d998b6ee5f19232b264c 100644 (file)
@@ -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;
+}
 \f
 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
index e8e09f8ec1cbbfaf43bea72951eebb22f7999308..ea4536a9112dc636963971a5ffc01290dda5b520 100644 (file)
@@ -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},...
index dce0d385fe05254f18f6c3b6a4c71887037a0333..35f91a287caa212aa14458e1abf0fff2794d1cc2 100644 (file)
 
 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)
 {
index aa014ae25c8dd486f64313f38b7b116df2729b62..c58d4c26b954b7fd6d6e6a22e731228578e80005 100644 (file)
@@ -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 {
index 97fdb91da33ff463ff7293de9413c484716360b4..e0368171fa908e1755dd4738348a6a8a0b9c697c 100644 (file)
@@ -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;