[binutils-gdb] ld: Prevent `_tls_used` and `_load_config_used` from being garbage-collected
Jan Beulich via Binutils-cvs <[email protected]> Fri, 31 Jul 2026 11:54:55 +0000 (GMT)
| Newsgroups | gmane.comp.gnu.binutils.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Dee7506d8ffbe= c39df2262f08a348346914d71efd commit ee7506d8ffbec39df2262f08a348346914d71efd Author: LIU Hao <[email protected]> Date: Fri Jul 31 13:52:14 2026 +0200 ld: Prevent `_tls_used` and `_load_config_used` from being garbage-coll= ected =20 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 entrypo= int function reference TLS initialization callbacks through function pointe= rs as tentative definitions, and the object files where TLS initialization ca= llbacks are defined should ensure `_tls_used` is linked, by referencing its add= ress in file-scope static pointers. =20 The issue here is that data sections of those object files are not refe= renced otherwise. During linking, if LD is passed `--gc-sections`, it garbage-= collects such sections along with `_tls_used`, leaving a symbol of value zero, w= hich results in a broken executable: =20 $ objdump -p bin/test_thread_id_cpp.exe | grep -F .tls Entry 9 ffffffffc0000000 00000028 Thread Storage Directory [.tls] =20 This patch prevents `_tls_used` from being garbage-collected, and likew= ise for `_load_config_used`. =20 Signed-off-by: LIU Hao <[email protected]> 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) =20 pe_output_file_set_long_section_names (link_info.output_bfd); =20 + /* The RVAs of these symbols will be written into the PE header, so they + must not be collected. */ + char *sym =3D xstrdup ("__tls_used"); + sym[0] =3D bfd_get_symbol_leading_char (link_info.output_bfd); + lang_add_gc_name (sym + !sym[0]); + + sym =3D xstrdup ("__load_config_used"); + sym[0] =3D 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); =20 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) =20 pep_output_file_set_long_section_names (link_info.output_bfd); =20 + /* The RVAs of these symbols will be written into the PE header, so they + must not be collected. */ + char *sym =3D xstrdup ("__tls_used"); + sym[0] =3D bfd_get_symbol_leading_char (link_info.output_bfd); + lang_add_gc_name (sym + !sym[0]); + + sym =3D xstrdup ("__load_config_used"); + sym[0] =3D 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);