Apologies, here is the implementation with regenerated configure this time. Do excuse me sending an entirely new mail instead of replying to the previous one, I have to do it this way due to a quirk in my email client.
best regards, Julian gcc/ChangeLog: * config/i386/i386.cc (ix86_legitimate_constant_p): Handle new UNSPEC. (legitimate_pic_operand_p): Handle new UNSPEC. (legitimate_pic_address_disp_p): Handle new UNSPEC. (ix86_legitimate_address_p): Handle new UNSPEC. (ix86_tls_index_symbol): New symbol for _tls_index. (ix86_tls_index): Handle creation of _tls_index symbol. (legitimize_tls_address): Create thread local access sequence. (output_pic_addr_const): Handle new UNSPEC. (i386_output_dwarf_dtprel): Handle new UNSPEC. (i386_asm_output_addr_const_extra): Handle new UNSPEC. * config/i386/i386.h (TARGET_WIN32_TLS): Define. * config/i386/i386.md: New UNSPEC. * config/i386/predicates.md: Handle new UNSPEC. * config/mingw/mingw32.h (TARGET_WIN32_TLS): Define. (TARGET_ASM_SELECT_SECTION): Define. (DEFAULT_TLS_SEG_REG): Define. * config/mingw/winnt.cc (mingw_pe_select_section): Select proper TLS section. (mingw_pe_unique_section): Handle TLS section. * config/mingw/winnt.h (mingw_pe_select_section): Declare. * configure: Regenerate. * configure.ac: New check for broken linker thread local support >From fceb5113f33a950048d57a1ecde39084eaa09ffe Mon Sep 17 00:00:00 2001 From: Julian Waters <tanksherma...@gmail.com> Date: Tue, 15 Oct 2024 20:56:22 +0800 Subject: [PATCH] Implement Windows TLS Signed-off-by: Julian Waters <tanksherma...@gmail.com> --- gcc/config/i386/i386.cc | 61 ++++++++++++++++++++++++++++++++++- gcc/config/i386/i386.h | 1 + gcc/config/i386/i386.md | 1 + gcc/config/i386/predicates.md | 1 + gcc/config/mingw/mingw32.h | 9 ++++++ gcc/config/mingw/winnt.cc | 14 ++++++++ gcc/config/mingw/winnt.h | 1 + gcc/configure | 29 +++++++++++++++++ gcc/configure.ac | 29 +++++++++++++++++ 9 files changed, 145 insertions(+), 1 deletion(-) diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 473e4cbf10e..304189bd947 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -11170,6 +11170,9 @@ ix86_legitimate_constant_p (machine_mode mode, rtx x) x = XVECEXP (x, 0, 0); return (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC); + case UNSPEC_SECREL32: + x = XVECEXP (x, 0, 0); + return GET_CODE (x) == SYMBOL_REF; default: return false; } @@ -11306,6 +11309,9 @@ legitimate_pic_operand_p (rtx x) x = XVECEXP (inner, 0, 0); return (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_EXEC); + case UNSPEC_SECREL32: + x = XVECEXP (inner, 0, 0); + return GET_CODE (x) == SYMBOL_REF; case UNSPEC_MACHOPIC_OFFSET: return legitimate_pic_address_disp_p (x); default: @@ -11486,6 +11492,9 @@ legitimate_pic_address_disp_p (rtx disp) disp = XVECEXP (disp, 0, 0); return (GET_CODE (disp) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (disp) == TLS_MODEL_LOCAL_DYNAMIC); + case UNSPEC_SECREL32: + disp = XVECEXP (disp, 0, 0); + return GET_CODE (disp) == SYMBOL_REF; } return false; @@ -11763,6 +11772,7 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict, case UNSPEC_INDNTPOFF: case UNSPEC_NTPOFF: case UNSPEC_DTPOFF: + case UNSPEC_SECREL32: break; default: @@ -11788,7 +11798,8 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict, || GET_CODE (XEXP (XEXP (disp, 0), 0)) != UNSPEC || !CONST_INT_P (XEXP (XEXP (disp, 0), 1)) || (XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_DTPOFF - && XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_NTPOFF)) + && XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_NTPOFF + && XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_SECREL32)) /* Non-constant pic memory reference. */ return false; } @@ -12112,6 +12123,22 @@ get_thread_pointer (machine_mode tp_mode, bool to_reg) return tp; } +/* Construct the SYMBOL_REF for the _tls_index symbol. */ + +static GTY(()) rtx ix86_tls_index_symbol; + +static rtx +ix86_tls_index (void) +{ + if (!ix86_tls_index_symbol) + ix86_tls_index_symbol = gen_rtx_SYMBOL_REF (SImode, "_tls_index"); + + if (flag_pic) + return gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, ix86_tls_index_symbol), UNSPEC_PCREL)); + else + return ix86_tls_index_symbol; +} + /* Construct the SYMBOL_REF for the tls_get_addr function. */ static GTY(()) rtx ix86_tls_symbol; @@ -12170,6 +12197,26 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov) machine_mode tp_mode = Pmode; int type; +#if TARGET_WIN32_TLS + off = gen_const_mem (SImode, ix86_tls_index ()); + set_mem_alias_set (off, GOT_ALIAS_SET); + + tp = gen_const_mem (Pmode, GEN_INT (TARGET_64BIT ? 88 : 44)); + set_mem_addr_space (tp, DEFAULT_TLS_SEG_REG); + + if (TARGET_64BIT) + off = convert_to_mode (Pmode, off, 1); + + base = force_reg (Pmode, off); + tp = copy_to_mode_reg (Pmode, tp); + + tp = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, tp, gen_rtx_MULT (Pmode, base, GEN_INT (UNITS_PER_WORD)))); + set_mem_alias_set (tp, GOT_ALIAS_SET); + + base = force_reg (Pmode, tp); + + return gen_rtx_PLUS (Pmode, base, gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_SECREL32))); +#else /* Fall back to global dynamic model if tool chain cannot support local dynamic. */ if (TARGET_SUN_TLS && !TARGET_64BIT @@ -12403,6 +12450,7 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov) } return dest; +#endif } /* Return true if the TLS address requires insn using integer registers. @@ -12872,6 +12920,9 @@ output_pic_addr_const (FILE *file, rtx x, int code) case UNSPEC_INDNTPOFF: fputs ("@indntpoff", file); break; + case UNSPEC_SECREL32: + fputs ("@secrel32", file); + break; #if TARGET_MACHO case UNSPEC_MACHOPIC_OFFSET: putc ('-', file); @@ -12897,7 +12948,11 @@ i386_output_dwarf_dtprel (FILE *file, int size, rtx x) { fputs (ASM_LONG, file); output_addr_const (file, x); +#if TARGET_WIN32_TLS + fputs ("@secrel32", file); +#else fputs ("@dtpoff", file); +#endif switch (size) { case 4: @@ -14650,6 +14705,10 @@ i386_asm_output_addr_const_extra (FILE *file, rtx x) output_addr_const (file, op); fputs ("@indntpoff", file); break; + case UNSPEC_SECREL32: + output_addr_const (file, op); + fputs ("@secrel32", file); + break; #if TARGET_MACHO case UNSPEC_MACHOPIC_OFFSET: output_addr_const (file, op); diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 51934400951..a10a368a5f7 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -510,6 +510,7 @@ extern unsigned char ix86_prefetch_sse; #define TARGET_GNU2_TLS (ix86_tls_dialect == TLS_DIALECT_GNU2) #define TARGET_ANY_GNU_TLS (TARGET_GNU_TLS || TARGET_GNU2_TLS) #define TARGET_SUN_TLS 0 +#define TARGET_WIN32_TLS 0 #ifndef TARGET_64BIT_DEFAULT #define TARGET_64BIT_DEFAULT 0 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index effab299349..865bf29d853 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -79,6 +79,7 @@ UNSPEC_MACHOPIC_OFFSET UNSPEC_PCREL UNSPEC_SIZEOF + UNSPEC_SECREL32 ;; Prologue support UNSPEC_STACK_ALLOC diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 053312bbe27..d83b27355cc 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -218,6 +218,7 @@ case UNSPEC_DTPOFF: case UNSPEC_GOTNTPOFF: case UNSPEC_NTPOFF: + case UNSPEC_SECREL32: return true; default: break; diff --git a/gcc/config/mingw/mingw32.h b/gcc/config/mingw/mingw32.h index 0dfe8e995b6..251271901a3 100644 --- a/gcc/config/mingw/mingw32.h +++ b/gcc/config/mingw/mingw32.h @@ -308,6 +308,15 @@ do { \ #undef TARGET_N_FORMAT_TYPES #define TARGET_N_FORMAT_TYPES 3 +#undef TARGET_WIN32_TLS +#define TARGET_WIN32_TLS 1 + +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION mingw_pe_select_section + +#undef DEFAULT_TLS_SEG_REG +#define DEFAULT_TLS_SEG_REG (TARGET_64BIT ? ADDR_SPACE_SEG_GS : ADDR_SPACE_SEG_FS) + #define HAVE_ENABLE_EXECUTE_STACK #undef CHECK_EXECUTE_STACK_ENABLED #define CHECK_EXECUTE_STACK_ENABLED flag_setstackexecutable diff --git a/gcc/config/mingw/winnt.cc b/gcc/config/mingw/winnt.cc index 9d433daaf5a..8453965f625 100644 --- a/gcc/config/mingw/winnt.cc +++ b/gcc/config/mingw/winnt.cc @@ -392,6 +392,15 @@ i386_pe_strip_name_encoding_full (const char *str) return name; } +section * +mingw_pe_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) +{ + if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)) + return get_named_section (decl, ".tls$", reloc); + else + return default_select_section (decl, reloc, align); +} + void mingw_pe_unique_section (tree decl, int reloc) { @@ -416,6 +425,8 @@ mingw_pe_unique_section (tree decl, int reloc) prefix = ".text$"; else if (decl_readonly_section (decl, reloc)) prefix = ".rdata$"; + else if (DECL_THREAD_LOCAL_P (decl)) + prefix = ".tls$"; else prefix = ".data$"; len = strlen (name) + strlen (prefix); @@ -490,6 +501,9 @@ mingw_pe_asm_named_section (const char *name, unsigned int flags, *f++ = 'e'; #endif + if (strcmp (name, ".tls$") == 0) + *f++ = 'd'; + if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0) /* readonly data */ { diff --git a/gcc/config/mingw/winnt.h b/gcc/config/mingw/winnt.h index 97fefbcebca..525ac3691f4 100644 --- a/gcc/config/mingw/winnt.h +++ b/gcc/config/mingw/winnt.h @@ -30,6 +30,7 @@ extern void mingw_pe_file_end (void); extern void mingw_pe_maybe_record_exported_symbol (tree, const char *, int); extern void mingw_pe_record_stub (const char *); extern unsigned int mingw_pe_section_type_flags (tree, const char *, int); +extern section *mingw_pe_select_section (tree, int, unsigned HOST_WIDE_INT); extern void mingw_pe_unique_section (tree, int); extern bool mingw_pe_valid_dllimport_attribute_p (const_tree); diff --git a/gcc/configure b/gcc/configure index 150ab616414..cd0afa829bb 100755 --- a/gcc/configure +++ b/gcc/configure @@ -27730,6 +27730,35 @@ if test $gcc_cv_as_tls = yes; then fi fi +case $target_os in + win32 | pe | cygwin* | mingw32*) + if test $set_have_as_tls = yes; then + # Hack to check whether ld breaks on @secrel32 for Windows + if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 44 -o "$gcc_cv_gld_major_version" -gt 2; then + : # ld support for @secrel32 was fixed in this version + else + as_fn_error $? "ld version is known to have broken secrel32 relocations, configure without --enable-tls or with --disable-tls to remove this error" "$LINENO" 5 + fi + elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x -a x$gcc_cv_objdump != x; then + echo '.text' > conftest.s + echo 'foo: nop' >> conftest.s + echo '.data' >> conftest.s + echo '.secrel32 foo' >> conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1 && $gcc_cv_ld -o conftest.exe conftest.o > /dev/null; then + if $gcc_cv_objdump -h conftest.exe | grep '\.reloc\>' > /dev/null; then + as_fn_error $? "ld has broken secrel32 relocations, configure without --enable-tls or with --disable-tls to remove this error" "$LINENO" 5 + fi + else + as_fn_error $? "Error occurred while checking for broken secrel32 relocations" "$LINENO" 5 + fi + rm -f conftest.s conftest.o conftest.exe + else + as_fn_error $? "Cannot check for broken secrel32 relocations to determine support for --enable-tls" "$LINENO" 5 + fi + fi + ;; +esac if test $set_have_as_tls = yes ; then $as_echo "#define HAVE_AS_TLS 1" >>confdefs.h diff --git a/gcc/configure.ac b/gcc/configure.ac index bdb22d53e2c..00bfa452691 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4166,6 +4166,35 @@ else [$tls_as_opt], [$conftest_s],, [set_have_as_tls=yes]) fi +case $target_os in + win32 | pe | cygwin* | mingw32*) + if test $set_have_as_tls = yes; then + # Hack to check whether ld breaks on @secrel32 for Windows + if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 44 -o "$gcc_cv_gld_major_version" -gt 2; then + : # ld support for @secrel32 was fixed in this version + else + AC_MSG_ERROR([ld version is known to have broken secrel32 relocations, configure without --enable-tls or with --disable-tls to remove this error]) + fi + elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x -a x$gcc_cv_objdump != x; then + echo '.text' > conftest.s + echo 'foo: nop' >> conftest.s + echo '.data' >> conftest.s + echo '.secrel32 foo' >> conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1 && $gcc_cv_ld -o conftest.exe conftest.o > /dev/null; then + if $gcc_cv_objdump -h conftest.exe | grep '\.reloc\>' > /dev/null; then + AC_MSG_ERROR([ld has broken secrel32 relocations, configure without --enable-tls or with --disable-tls to remove this error]) + fi + else + AC_MSG_ERROR([Error occurred while checking for broken secrel32 relocations]) + fi + rm -f conftest.s conftest.o conftest.exe + else + AC_MSG_ERROR([Cannot check for broken secrel32 relocations to determine support for --enable-tls]) + fi + fi + ;; +esac if test $set_have_as_tls = yes ; then AC_DEFINE(HAVE_AS_TLS, 1, [Define if your assembler and linker support thread-local storage.]) -- 2.45.2