ld: Prevent `_tls_used` and `_load_config_used` from being garbage-collected
LIU Hao
lh_mouse@126.com
Mon Jul 27 15:38:42 GMT 2026
Hello,
Below is a patch that is required for LD to work with `--gc-sections` with recent mingw-w64, tested on
x86_64-w64-mingw32 and i686-w64-mingw32.
I don't have access to binutils Git so please commit it for me. Also please consider backporting.
From 9a98b90d43739f5979a999acda3beb21b17442b2 Mon Sep 17 00:00:00 2001
From: LIU Hao <lh_mouse@126.com>
Date: Mon, 27 Jul 2026 23:11:54 +0800
Subject: [PATCH] ld: Prevent `_tls_used` and `_load_config_used` from being
garbage-collected
Earlier today I pushed some patches to mingw-w64 to make `_tls_used` only
linked on demand, by referencing it indirectly through tentative definitions.
However, since the startup code no longer has strong references to `_tls_used`,
if LD is passed `--gc-sections`, it garbage-collects `_tls_used`, resulting 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>
---
ld/emultempl/pe.em | 10 ++++++++++
ld/emultempl/pep.em | 5 +++++
2 files changed, 15 insertions(+)
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index 07ef2ca5953..475e0349ff8 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. */
+#if defined (TARGET_IS_i386pe)
+ lang_add_gc_name ("__tls_used");
+ lang_add_gc_name ("__load_config_used");
+#else
+ lang_add_gc_name ("_tls_used");
+ lang_add_gc_name ("_load_config_used");
+#endif
+
#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 14be8435685..1ab5c4d88f7 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -1624,6 +1624,11 @@ 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. */
+ lang_add_gc_name ("_tls_used");
+ lang_add_gc_name ("_load_config_used");
+
#ifdef DLL_SUPPORT
pep_process_import_defs (link_info.output_bfd, &link_info);
--
2.55.0
-------------- next part --------------
From 9a98b90d43739f5979a999acda3beb21b17442b2 Mon Sep 17 00:00:00 2001
From: LIU Hao <lh_mouse@126.com>
Date: Mon, 27 Jul 2026 23:11:54 +0800
Subject: [PATCH] ld: Prevent `_tls_used` and `_load_config_used` from being
garbage-collected
Earlier today I pushed some patches to mingw-w64 to make `_tls_used` only
linked on demand, by referencing it indirectly through tentative definitions.
However, since the startup code no longer has strong references to `_tls_used`,
if LD is passed `--gc-sections`, it garbage-collects `_tls_used`, resulting 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>
---
ld/emultempl/pe.em | 10 ++++++++++
ld/emultempl/pep.em | 5 +++++
2 files changed, 15 insertions(+)
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index 07ef2ca5953..475e0349ff8 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. */
+#if defined (TARGET_IS_i386pe)
+ lang_add_gc_name ("__tls_used");
+ lang_add_gc_name ("__load_config_used");
+#else
+ lang_add_gc_name ("_tls_used");
+ lang_add_gc_name ("_load_config_used");
+#endif
+
#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 14be8435685..1ab5c4d88f7 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -1624,6 +1624,11 @@ 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. */
+ lang_add_gc_name ("_tls_used");
+ lang_add_gc_name ("_load_config_used");
+
#ifdef DLL_SUPPORT
pep_process_import_defs (link_info.output_bfd, &link_info);
--
2.55.0
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <https://sourceware.org/pipermail/binutils/attachments/20260727/e9c8fd8d/attachment.sig>
More information about the Binutils
mailing list