[PATCH 2/3] bfd/ELF: Retain strong undefined symbols under -z dynamic-undefined-weak

Hakan Candar hakan@envs.net
Wed Jul 16 16:03:22 GMT 2025


Add `bfd_is_undef_symbol` macro for clarity and consistency across
backends. Adjust symbol hiding and dynamic marking logic in elflink.c
to treat undefined strong symbols the same as weak ones when applying
retention rules.

This improves alignment with the gABI and LLD behavior, especially
under `-z [no]dynamic-undefined-weak`. Backends that already respected
this logic (e.g., x86_64, ppc) show no regressions, and can now retain
strong undefined symbols as dynamic relocations via -z dynamic-undefined-weak.

Some backends that previously did not support `-z [no]dynamic-undefined-weak`
(e.g., aarch64, mips, riscv) now follow the shared logic correctly as
described above, enabling dynamic relocations for strong undefineds.

Other backends (e.g., sh4, m68k) do not yet respect the centralized
behavior and continue to prune undefined symbols unconditionally due
to backend-specific conditionals. These will be addressed incrementally.

bfd/
	* linker.c (bfd_is_undef_symbol): New macro for detecting
	undefined symbols, strong or weak.
	* elf-bfd.h (UNDEF_NO_DYNAMIC_RELOC): New macro for controlling
	undefined symbol retention behavior.
	* elflink.c (_bfd_elf_adjust_dynamic_symbol): Use
	bfd_is_undef_symbol to apply retention logic uniformly.

ld/
	* ld.texi: Clarify that -z dynamic-undefined-weak also affects
	strong undefined symbols.
	* lexsup.c (elf_shlib_list_options): Likewise.
	* NEWS: Mention the new behaviour regarding non-weak undefineds.

Signed-off-by: Hakan Candar <hakan@envs.net>
---
 bfd/bfd-in2.h |  8 ++++++++
 bfd/elf-bfd.h | 10 ++++++++++
 bfd/elflink.c |  2 +-
 bfd/linker.c  |  9 +++++++++
 ld/NEWS       |  5 ++++-
 ld/ld.texi    |  4 ++--
 ld/lexsup.c   |  4 ++--
 7 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index b013ef954da..e62a66111f5 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2924,6 +2924,14 @@ const char *bfd_format_string (bfd_format format);
    && bfd_is_abs_section ((H)->u.def.section) \
    && !(H)->rel_from_abs)
 
+/* Return TRUE if the symbol described by a linker hash entry H
+   is undefined.  This includes both strong and weak undefined
+   symbols.  Use this macro to check whether the symbol has not
+   been resolved during the link.  */
+#define bfd_is_undef_symbol(H) \
+  ((H)->type == bfd_link_hash_undefined \
+    || (H)->type == bfd_link_hash_undefweak)
+
 bool _bfd_generic_link_add_one_symbol
    (struct bfd_link_info *info,
     bfd *abfd,
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 2bd855a936c..13bb2a4155b 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -302,6 +302,16 @@ weakdef (struct elf_link_hash_entry *h)
    && (ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT	\
        || (INFO)->dynamic_undefined_weak == 0))
 
+/* Whether an undefined symbol should resolve to its link-time
+   value, even in PIC or PIE objects.  The linker_def test is to
+   handle symbols like __ehdr_start that may be undefweak in early
+   stages of linking but are guaranteed to be defined later.  */
+#define UNDEF_NO_DYNAMIC_RELOC(INFO, H)                 \
+  (bfd_is_undef_symbol (&(H)->root)                     \
+   && !(H)->root.linker_def                             \
+   && (ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT    \
+       || (INFO)->dynamic_undefined_weak == 0))
+
 /* Common symbols that are turned into definitions don't have the
    DEF_REGULAR flag set, so they might appear to be undefined.
    Symbols defined in linker scripts also don't have DEF_REGULAR set.  */
diff --git a/bfd/elflink.c b/bfd/elflink.c
index c4f57cf2f3c..90f596f929e 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -3249,7 +3249,7 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
   htab = elf_hash_table (eif->info);
   bed = get_elf_backend_data (htab->dynobj);
 
-  if (h->root.type == bfd_link_hash_undefweak)
+  if (bfd_is_undef_symbol (&h->root))
     {
       if (eif->info->dynamic_undefined_weak == 0)
 	(*bed->elf_backend_hide_symbol) (eif->info, h, true);
diff --git a/bfd/linker.c b/bfd/linker.c
index a9a23e5b9de..aa6ea560e9a 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -513,8 +513,17 @@ _bfd_link_hash_table_init
 .   && bfd_is_abs_section ((H)->u.def.section) \
 .   && !(H)->rel_from_abs)
 .
+.{* Return TRUE if the symbol described by a linker hash entry H
+.   is undefined.  This includes both strong and weak undefined
+.   symbols.  Use this macro to check whether the symbol has not
+.   been resolved during the link.  *}
+.#define bfd_is_undef_symbol(H) \
+.  ((H)->type == bfd_link_hash_undefined \
+.    || (H)->type == bfd_link_hash_undefweak)
+.
 */
 
+
 struct bfd_link_hash_entry *
 bfd_link_hash_lookup (struct bfd_link_hash_table *table,
 		      const char *string,
diff --git a/ld/NEWS b/ld/NEWS
index dcb8511fc04..b53feb86fcc 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -6,7 +6,10 @@ Changes in 2.45:
   ELF emulation code and is accepted on all ELF targets.  This removes the
   need for per-target wiring.
 
-  Some backends may not yet fully respect this centralized
+  The option now also applies to strong undefined symbols, making them
+  eligible for retention or removal alongside weak undefined symbols.  This
+  unifies the retention behavior under the same flag, aligning with the gABI
+  and LLD behavior.  Some backends may not yet fully respect this centralized
   logic due to backend-specific conditionals.
 
 * On s390 64-bit (s390x), generate SFrame stack trace information (.sframe)
diff --git a/ld/ld.texi b/ld/ld.texi
index ffdb4d97412..317180beff0 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1433,12 +1433,12 @@ This option is the inverse of @samp{-z undefs}.
 
 @item dynamic-undefined-weak
 @itemx nodynamic-undefined-weak
-Make undefined weak symbols dynamic when building a dynamic object,
+Make undefined symbols dynamic when building a dynamic object,
 if they are referenced from a regular object file and not forced local
 by symbol visibility or versioning.  Do not make them dynamic if
 @samp{nodynamic-undefined-weak}.  If neither option is given, a target
 may default to either option being in force, or make some other
-selection of undefined weak symbols dynamic.
+selection of undefined symbols dynamic.
 
 These options are available for all ELF targets, but some backends may
 not yet fully implement consistent handling of undefined symbol retention.
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 5f0c040e352..b76cf13de23 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2268,8 +2268,8 @@ elf_shlib_list_options (FILE *file)
   -z nomemory-seal            Don't mark oject to be memory sealed (default)\n"));
 #endif
   fprintf (file, _("\
-  -z dynamic-undefined-weak   Make undefined weak symbols dynamic\n\
-  -z nodynamic-undefined-weak Do not make undefined weak symbols dynamic\n"));
+  -z dynamic-undefined-weak   Make undefined symbols dynamic\n\
+  -z nodynamic-undefined-weak Do not make undefined symbols dynamic\n"));
 }
 
 static void
-- 
2.47.0



More information about the Binutils mailing list