[binutils-gdb] ld: Prevent `_tls_used` and `_load_config_used` from being garbage-collected

Jan Beulich jbeulich@sourceware.org
Fri Jul 31 11:54:55 GMT 2026


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

commit ee7506d8ffbec39df2262f08a348346914d71efd
Author: LIU Hao <lh_mouse@126.com>
Date:   Fri Jul 31 13:52:14 2026 +0200

    ld: Prevent `_tls_used` and `_load_config_used` from being garbage-collected
    
    In mingw-w64 there's an ongoing effort to make the TLS directory of an image
    optional and only linked on demand. The approach is to have the entrypoint
    function reference TLS initialization callbacks through function pointers as
    tentative definitions, and the object files where TLS initialization callbacks
    are defined should ensure `_tls_used` is linked, by referencing its address in
    file-scope static pointers.
    
    The issue here is that data sections of those object files are not referenced
    otherwise. During linking, if LD is passed `--gc-sections`, it garbage-collects
    such sections along with `_tls_used`, leaving a symbol of value zero, which
    results in a broken executable:
    
       $ objdump -p bin/test_thread_id_cpp.exe | grep -F .tls
       Entry 9 ffffffffc0000000 00000028 Thread Storage Directory [.tls]
    
    This patch prevents `_tls_used` from being garbage-collected, and likewise for
    `_load_config_used`.
    
    Signed-off-by: LIU Hao <lh_mouse@126.com>

Diff:
---
 ld/emultempl/pe.em  | 10 ++++++++++
 ld/emultempl/pep.em | 10 ++++++++++
 2 files changed, 20 insertions(+)

diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index 07ef2ca5953..1d02a86be96 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -1573,6 +1573,16 @@ gld${EMULATION_NAME}_after_open (void)
 
   pe_output_file_set_long_section_names (link_info.output_bfd);
 
+  /* The RVAs of these symbols will be written into the PE header, so they
+     must not be collected.  */
+  char *sym = xstrdup ("__tls_used");
+  sym[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
+  lang_add_gc_name (sym + !sym[0]);
+
+  sym = xstrdup ("__load_config_used");
+  sym[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
+  lang_add_gc_name (sym + !sym[0]);
+
 #ifdef DLL_SUPPORT
   pe_process_import_defs (link_info.output_bfd, &link_info);
 
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index 25ce3963b36..3ba29401821 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -1582,6 +1582,16 @@ gld${EMULATION_NAME}_after_open (void)
 
   pep_output_file_set_long_section_names (link_info.output_bfd);
 
+  /* The RVAs of these symbols will be written into the PE header, so they
+     must not be collected.  */
+  char *sym = xstrdup ("__tls_used");
+  sym[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
+  lang_add_gc_name (sym + !sym[0]);
+
+  sym = xstrdup ("__load_config_used");
+  sym[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
+  lang_add_gc_name (sym + !sym[0]);
+
 #ifdef DLL_SUPPORT
   pep_process_import_defs (link_info.output_bfd, &link_info);


More information about the Binutils-cvs mailing list