This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

TLS support for vxworks


This patch adds TLS support, which has been added to vxworks-6.6 in both kernel and RTP modes. WindRiver's TLS specification is essentially the same as the emulated TLS machinery that GCC already has. The differences are in name mangling and the use of special sections for the tls control information and the tls initialization data. This patch adds the necessary target hooks to abstract that information out of the main emulated tls machinery.

Because of the requirement to use special sections, I found it necessary to distinguish emulated TLS variables from regular variables. Fortunately, there are 5 values in current use for TLS_MODEL values, so adding a new value (TLS_MODEL_EMULATED) was straight forward and does not add any new storage requirements. I took care in ordering this new enum value so that existing code was disturbed as little as possible.

Another change that was necessary was forcing the alignment of the TLS variables. Vxworks expects the control information to be an array of objects, but to the compiler each one looks as a single object and some backends (such as MIPS) will increase the alignment of such singleton objects for better performance. The alignment hook I added simply sets DECL_USER_ALIGN appropriately (if the user tries to override the alignment further, things break horribly anyway).

Because of the new section types, I found it necessary to rewrite i386's x86_64_elf_select_section routine, so it could get the emulated TLS section prefixes appropriately.

This has been tested on i686-pc-linux-gnu, to check I've not broken anything there and {i586,arm,sh,mips,sparc,powerpc}-wrs-vxworks.

ok?

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery

2008-03-27  Nathan Sidwell  <nathan@codesourcery.com>

	gcc/
	* targhooks.h (default_emutls_var_fields,
	default_emutls_var_init): Declare.
	* tree.h (DECL_THREAD_LOCAL): Compare against TLS_MODEL_REAL.
	* target.h (struct gcc_target): Add struct emutls member.
	* target-def.h (TARGET_EMUTLS_GET_ADDRESS,
	TARGET_EMUTLS_REGISTER_COMMON, TARGET_EMUTLS_VAR_SECTION,
	TARGET_EMUTLS_TMPL_SECTION, TARGET_EMUTLS_VAR_PREFIX,
	TARGET_EMUTLS_TMPL_PREFIX, TARGET_EMUTLS_VAR_FIELDS,
	TARGET_EMUTLS_VAR_INIT, TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS,
	TARGET_EMUTLS_VAR_ALIGN_FIXED, TARGET_EMUTLS): New.
	(TARGET_INITIALIZER): Add TARGET_EMUTLS.
	* builtins.def (BUILT_IN_EMUTLS_GET_ADDRESS,
	BUILT_IN_EMUTLS_REGISTER_COMMON): Get name from targetm structure.
	* dwarf2out.c (loc_descriptor_from_tree_1): Check if emutls can
	emit debug information.
	* coretypes.h (tls_model): Add TLS_MODEL_EMULATED, TLS_MODEL_REAL.
	* varasm.c: Include targhooks.h.
	(emutls_object_section, emutls_tmpl_section): New.
	(EMUTLS_VAR_PREFIX, EMUTLS_TMPL_PREFIX): Remove.
	(EMUTLS_SEPARATOR): New.
	(prefix_name): New.
	(get_emutls_object_name): New.
	(default_emutls_var_fields): New, broken out of ...
	(get_emutls_object_type): ... here.  Adjust to use target hooks.
	(get_emutls_init_templ_addr): Adjust to use target hooks.
	(emutls_decl): Adjust to use target hooks.
	(emutls_finish): Likewise.
	(default_emutls_var_init): New, broken out of ...
	(assemble_variable): ... here.  Adjust to use target hooks.
	* output.h (enum section_category): Add SECCAT_EMUTLS_VAR,
	SECCAT_EMUTLS_TMPL.
	* c-common.c (handle_section_attribute): Prevent overriding
	sections for emulated tls with special sections.
	* config/i386/i386.c (x86_64_elf_select_section): Add
	SECCAT_EMUTLS_VAR and SECCAT_EMUTLS_TMPL.
	(x86_64_elf_unique_section): Likewise.
	* config/vxworks.c: Include tree.h.
	(vxworks_emutls_var_fields, vxworks_emutls_var_init): New.
	(vxworks_override_options): Set TLS scheme.

	gcc/testsuite/
	* gcc.dg/tls/section-1.c: Disable for vxworks.
	* gcc.dg/tls/section-2.c: New.
	* gcc.dg/tls/opt-4.c: Disable for vxworks.
	* gcc.dg/tls/emutls-1.c: New.

Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 196914)
+++ gcc/targhooks.h	(working copy)
@@ -94,3 +94,5 @@ extern void hook_void_bitmap (bitmap);
 extern bool default_handle_c_option (size_t, const char *, int);
 extern int default_reloc_rw_mask (void);
 extern tree default_mangle_decl_assembler_name (tree, tree);
+extern tree default_emutls_var_fields (tree, tree *);
+extern tree default_emutls_var_init (tree, tree, tree);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 196914)
+++ gcc/tree.h	(working copy)
@@ -3188,7 +3188,7 @@ extern void decl_fini_priority_insert (t
 /* In a VAR_DECL, nonzero if the data should be allocated from
    thread-local storage.  */
 #define DECL_THREAD_LOCAL_P(NODE) \
-  (VAR_DECL_CHECK (NODE)->decl_with_vis.tls_model != TLS_MODEL_NONE)
+  (VAR_DECL_CHECK (NODE)->decl_with_vis.tls_model >= TLS_MODEL_REAL)
 
 struct tree_var_decl GTY(())
 {
Index: gcc/target.h
===================================================================
--- gcc/target.h	(revision 196914)
+++ gcc/target.h	(working copy)
@@ -917,6 +917,34 @@ struct gcc_target
     void (*adjust_class_at_definition) (tree type);
   } cxx;
 
+  /* Functions and data for emulated TLS support.  */
+  struct emutls {
+    /* Name of the address, variable and common functions.  */
+    char const *get_address;
+    char const *register_common;
+
+    /* Prefixes for proxy variable and template.  */
+    char const *var_section;
+    char const *tmpl_section;
+
+    /* Prefixes for proxy variable and template.  */
+    char const *var_prefix;
+    char const *tmpl_prefix;
+    
+    /* Function to generate field definitions of the proxy variable.  */
+    tree (*var_fields) (tree, tree *);
+
+    /* Function to initialize a proxy variable.  */
+    tree (*var_init) (tree, tree, tree);
+
+    /* Whether we are allowed to alter the usual alignment of the
+       proxy variable.  */
+    bool var_align_fixed;
+
+    /* Whether we can emit debug information for TLS vars.  */
+    bool debug_form_tls_address;
+  } emutls;  
+
   /* For targets that need to mark extra registers as live on entry to
      the function, they should define this target hook and set their
      bits in the bitmap passed in. */  
Index: gcc/testsuite/gcc.dg/tls/section-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/section-1.c	(revision 196914)
+++ gcc/testsuite/gcc.dg/tls/section-1.c	(working copy)
@@ -2,6 +2,9 @@
    sections which can't work.  */
 /* { dg-require-effective-target tls_native } */
 
+/* This test only makes sense on non-emulated tls implementations */
+/* { dg-do compile { target { ! *-*-vxworks* } } } */
+
 #define A(X)	__attribute__((section(X)))
 
 __thread int i A("foo");		/* Ok */
Index: gcc/testsuite/gcc.dg/tls/section-2.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/section-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tls/section-2.c	(revision 0)
@@ -0,0 +1,10 @@
+/* Verify that we get errors for trying to put TLS data in 
+   sections which can't work.  */
+/* { dg-require-effective-target tls } */
+
+/* This test only makes sense on vxworks' emulated tls implementation */
+/* { dg-do compile { target *-*-vxworks* } } */
+
+#define A(X)	__attribute__((section(X)))
+
+__thread int i A("foo"); /* { dg-error "cannot be overridden" } */
Index: gcc/testsuite/gcc.dg/tls/opt-4.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/opt-4.c	(revision 196914)
+++ gcc/testsuite/gcc.dg/tls/opt-4.c	(working copy)
@@ -48,7 +48,7 @@ baz (const struct A *x, char *y)
 }
 
 /* Verify tcc1 and tcc2 variables show up only in the TLS access sequences.  */
-/* { dg-final { scan-assembler "tcc1@" { target i?86-*-* x86_64-*-* } } } */
-/* { dg-final { scan-assembler "tcc2@" { target i?86-*-* x86_64-*-* } } } */
-/* { dg-final { scan-assembler-not "tcc1\[^@\]" { target i?86-*-* x86_64-*-* } } } */
-/* { dg-final { scan-assembler-not "tcc2\[^@\]" { target i?86-*-* x86_64-*-* } } } */
+/* { dg-final { scan-assembler "tcc1@" { target { { i?86-*-* x86_64-*-* } && { ! *-*-vxworks } } } } } */
+/* { dg-final { scan-assembler "tcc2@" { target { { i?86-*-* x86_64-*-* } && { ! *-*-vxworks } } } } } */
+/* { dg-final { scan-assembler-not "tcc1\[^@\]" { target { { i?86-*-* x86_64-*-* } && { ! *-*-vxworks } } } } } */
+/* { dg-final { scan-assembler-not "tcc2\[^@\]" { target { { i?86-*-* x86_64-*-* } && { ! *-*-vxworks } } } } } */
Index: gcc/testsuite/gcc.dg/tls/emutls-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tls/emutls-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tls/emutls-1.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-do run { target *-wrs-vxworks } } */
+/* { dg-require-effective-target tls } */
+
+/* vxworks' TLS model requires no extra padding on the tls proxy
+   objects.  */
+
+__thread int i;
+__thread int j;
+
+extern int __tls__i;
+extern int __tls__j;
+
+int main ()
+{
+  int delta = ((char *)&__tls__j - (char *)&__tls__i);
+
+  if (delta < 0)
+    delta = -delta;
+  
+  return delta != 12;
+}
Index: gcc/builtins.def
===================================================================
--- gcc/builtins.def	(revision 196914)
+++ gcc/builtins.def	(working copy)
@@ -745,8 +745,16 @@ DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_
 DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit")
 
 /* TLS emulation.  */
-DEF_EXT_LIB_BUILTIN (BUILT_IN_EMUTLS_GET_ADDRESS, "__emutls_get_address", BT_FN_PTR_PTR, ATTR_CONST_NOTHROW_NONNULL)
-DEF_EXT_LIB_BUILTIN (BUILT_IN_EMUTLS_REGISTER_COMMON, "__emutls_register_common", BT_FN_VOID_PTR_WORD_WORD_PTR, ATTR_NOTHROW_LIST)
+DEF_BUILTIN (BUILT_IN_EMUTLS_GET_ADDRESS, targetm.emutls.get_address,
+	     BUILT_IN_NORMAL,
+	     BT_FN_PTR_PTR,  BT_FN_PTR_PTR,
+	     true, true, true, ATTR_CONST_NOTHROW_NONNULL, false,
+	     !targetm.have_tls)
+DEF_BUILTIN (BUILT_IN_EMUTLS_REGISTER_COMMON,
+	     targetm.emutls.register_common, BUILT_IN_NORMAL,
+	     BT_FN_VOID_PTR_WORD_WORD_PTR, BT_FN_VOID_PTR_WORD_WORD_PTR,
+	     true, true, true, ATTR_NOTHROW_LIST, false,
+	     !targetm.have_tls)
 
 /* Synchronization Primitives.  */
 #include "sync-builtins.def"
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 196914)
+++ gcc/dwarf2out.c	(working copy)
@@ -9487,16 +9487,33 @@ loc_descriptor_from_tree_1 (tree loc, in
       if (DECL_THREAD_LOCAL_P (loc))
 	{
 	  rtx rtl;
+	  unsigned first_op;
+	  unsigned second_op;
 
-	  /* If this is not defined, we have no way to emit the data.  */
-	  if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel)
-	    return 0;
-
-	  /* The way DW_OP_GNU_push_tls_address is specified, we can only
-	     look up addresses of objects in the current module.  */
-	  if (DECL_EXTERNAL (loc))
-	    return 0;
-
+	  if (targetm.have_tls)
+	    {
+	      /* If this is not defined, we have no way to emit the
+	         data.  */
+	      if (!targetm.asm_out.output_dwarf_dtprel)
+		return 0;
+
+	       /* The way DW_OP_GNU_push_tls_address is specified, we
+	     	  can only look up addresses of objects in the current
+	     	  module.  */
+	      if (DECL_EXTERNAL (loc))
+		return 0;
+	      first_op = INTERNAL_DW_OP_tls_addr;
+	      second_op = DW_OP_GNU_push_tls_address;
+	    }
+	  else
+	    {
+	      if (!targetm.emutls.debug_form_tls_address)
+		return 0;
+	      loc = emutls_decl (loc);
+	      first_op = DW_OP_addr;
+	      second_op = DW_OP_form_tls_address;
+	    }
+	  
 	  rtl = rtl_for_decl_location (loc);
 	  if (rtl == NULL_RTX)
 	    return 0;
@@ -9507,11 +9524,11 @@ loc_descriptor_from_tree_1 (tree loc, in
 	  if (! CONSTANT_P (rtl))
 	    return 0;
 
-	  ret = new_loc_descr (INTERNAL_DW_OP_tls_addr, 0, 0);
+	  ret = new_loc_descr (first_op, 0, 0);
 	  ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
 	  ret->dw_loc_oprnd1.v.val_addr = rtl;
-
-	  ret1 = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+	  
+	  ret1 = new_loc_descr (second_op, 0, 0);
 	  add_loc_descr (&ret, ret1);
 
 	  have_address = 1;
Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h	(revision 196914)
+++ gcc/coretypes.h	(working copy)
@@ -69,7 +69,9 @@ struct cpp_reader;
    to it, so it's here.  */
 enum tls_model {
   TLS_MODEL_NONE,
-  TLS_MODEL_GLOBAL_DYNAMIC,
+  TLS_MODEL_EMULATED,
+  TLS_MODEL_REAL,
+  TLS_MODEL_GLOBAL_DYNAMIC = TLS_MODEL_REAL,
   TLS_MODEL_LOCAL_DYNAMIC,
   TLS_MODEL_INITIAL_EXEC,
   TLS_MODEL_LOCAL_EXEC
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 196914)
+++ gcc/varasm.c	(working copy)
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  
 #include "tm_p.h"
 #include "debug.h"
 #include "target.h"
+#include "targhooks.h"
 #include "tree-mudflap.h"
 #include "cgraph.h"
 #include "cfglayout.h"
@@ -204,68 +205,92 @@ static GTY(()) struct rtx_constant_pool 
 static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
      htab_t emutls_htab;
 static GTY (()) tree emutls_object_type;
-
-#ifndef NO_DOT_IN_LABEL
-# define EMUTLS_VAR_PREFIX	"__emutls_v."
-# define EMUTLS_TMPL_PREFIX	"__emutls_t."
-#elif !defined NO_DOLLAR_IN_LABEL
-# define EMUTLS_VAR_PREFIX	"__emutls_v$"
-# define EMUTLS_TMPL_PREFIX	"__emutls_t$"
+/* Emulated TLS objects have the TLS model TLS_MODEL_EMULATED.  This
+   macro can be used on them to distinguish the control variable from
+   the initialization template.  */
+#define DECL_EMUTLS_VAR_P(D)  (TREE_TYPE (D) == emutls_object_type)
+
+#if !defined (NO_DOT_IN_LABEL)
+# define EMUTLS_SEPARATOR	"."
+#elif !defined (NO_DOLLAR_IN_LABEL)
+# define EMUTLS_SEPARATOR	"$"
 #else
-# define EMUTLS_VAR_PREFIX	"__emutls_v_"
-# define EMUTLS_TMPL_PREFIX	"__emutls_t_"
+# define EMUTLS_SEPARATOR	"_"
 #endif
 
-/* Create an identifier for the struct __emutls_object, given an identifier
-   of the DECL_ASSEMBLY_NAME of the original object.  */
-
 static tree
-get_emutls_object_name (tree name)
+prefix_name (const char *prefix, tree name)
 {
-  char *toname = alloca (strlen (IDENTIFIER_POINTER (name))
-			 + sizeof (EMUTLS_VAR_PREFIX));
-  strcpy (toname, EMUTLS_VAR_PREFIX);
-  strcpy (toname + sizeof (EMUTLS_VAR_PREFIX) - 1, IDENTIFIER_POINTER (name));
+  unsigned plen = strlen (prefix);
+  unsigned nlen = strlen (IDENTIFIER_POINTER (name));
+  char *toname = alloca (plen + nlen + 1);
+  
+  memcpy (toname, prefix, plen);
+  memcpy (toname + plen, IDENTIFIER_POINTER (name), nlen + 1);
 
   return get_identifier (toname);
 }
 
-/* Create the structure for struct __emutls_object.  This should match the
-   structure at the top of emutls.c, modulo the union there.  */
+/* Create an identifier for the struct __emutls_object, given an identifier
+   of the DECL_ASSEMBLY_NAME of the original object.  */
 
 static tree
-get_emutls_object_type (void)
+get_emutls_object_name (tree name)
 {
-  tree type, type_name, field, next_field, word_type_node;
-
-  type = emutls_object_type;
-  if (type)
-    return type;
-
-  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
-  type_name = get_identifier ("__emutls_object");
-  type_name = build_decl (TYPE_DECL, type_name, type);
-  TYPE_NAME (type) = type_name;
+  const char *prefix = (targetm.emutls.var_prefix
+			? targetm.emutls.var_prefix
+			: "__emutls_v" EMUTLS_SEPARATOR);
+  return prefix_name (prefix, name);
+}
 
+tree
+default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
+{
+  tree word_type_node, field, next_field;
+  
   field = build_decl (FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
   DECL_CONTEXT (field) = type;
   next_field = field;
-
-  field = build_decl (FIELD_DECL, get_identifier ("__offset"), ptr_type_node);
+    
+  field = build_decl (FIELD_DECL, get_identifier ("__offset"),
+		      ptr_type_node);
   DECL_CONTEXT (field) = type;
   TREE_CHAIN (field) = next_field;
   next_field = field;
-
+  
   word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
-  field = build_decl (FIELD_DECL, get_identifier ("__align"), word_type_node);
+  field = build_decl (FIELD_DECL, get_identifier ("__align"),
+		      word_type_node);
   DECL_CONTEXT (field) = type;
   TREE_CHAIN (field) = next_field;
   next_field = field;
-
+  
   field = build_decl (FIELD_DECL, get_identifier ("__size"), word_type_node);
   DECL_CONTEXT (field) = type;
   TREE_CHAIN (field) = next_field;
 
+  return field;
+}
+
+/* Create the structure for struct __emutls_object.  This should match the
+   structure at the top of emutls.c, modulo the union there.  */
+
+static tree
+get_emutls_object_type (void)
+{
+  tree type, type_name, field;
+
+  type = emutls_object_type;
+  if (type)
+    return type;
+
+  emutls_object_type = type = lang_hooks.types.make_type (RECORD_TYPE);
+  type_name = NULL;
+  field = targetm.emutls.var_fields (type, &type_name);
+  if (!type_name)
+    type_name = get_identifier ("__emutls_object");
+  type_name = build_decl (TYPE_DECL, type_name, type);
+  TYPE_NAME (type) = type_name;
   TYPE_FIELDS (type) = field;
   layout_type (type);
 
@@ -279,26 +304,30 @@ static tree
 get_emutls_init_templ_addr (tree decl)
 {
   tree name, to;
-  char *toname;
-
-  if (!DECL_INITIAL (decl))
+  
+  if (targetm.emutls.register_common && !DECL_INITIAL (decl)
+      && !DECL_SECTION_NAME (decl))
     return null_pointer_node;
 
   name = DECL_ASSEMBLER_NAME (decl);
-  toname = alloca (strlen (IDENTIFIER_POINTER (name))
-		   + sizeof (EMUTLS_TMPL_PREFIX));
-  strcpy (toname, EMUTLS_TMPL_PREFIX);
-  strcpy (toname + sizeof (EMUTLS_TMPL_PREFIX) - 1, IDENTIFIER_POINTER (name));
-  name = get_identifier (toname);
+  if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
+    {
+      const char *prefix = (targetm.emutls.tmpl_prefix
+			    ? targetm.emutls.tmpl_prefix
+			    : "__emutls_t" EMUTLS_SEPARATOR);
+      name = prefix_name (prefix, name);
+    }
 
   to = build_decl (VAR_DECL, name, TREE_TYPE (decl));
   SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
-
+  DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
   DECL_ARTIFICIAL (to) = 1;
   TREE_USED (to) = TREE_USED (decl);
   TREE_READONLY (to) = 1;
   DECL_IGNORED_P (to) = 1;
   DECL_CONTEXT (to) = DECL_CONTEXT (decl);
+  DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl);
+  
   DECL_WEAK (to) = DECL_WEAK (decl);
   if (DECL_ONE_ONLY (decl))
     {
@@ -358,14 +387,18 @@ emutls_decl (tree decl)
       h->to = to;
       *(struct tree_map **) loc = h;
 
+      DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
       DECL_ARTIFICIAL (to) = 1;
       DECL_IGNORED_P (to) = 1;
       TREE_READONLY (to) = 0;
-
       SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
       if (DECL_ONE_ONLY (decl))
 	make_decl_one_only (to);
       DECL_CONTEXT (to) = DECL_CONTEXT (decl);
+      if (targetm.emutls.var_align_fixed)
+	/* If we're not allowed to change the proxy object's
+	   alignment, pretend it's been set by the user.  */
+	DECL_USER_ALIGN (to) = 1;
     }
 
   /* Note that these fields may need to be updated from time to time from
@@ -423,16 +456,19 @@ emutls_common_1 (void **loc, void *xstmt
 void
 emutls_finish (void)
 {
-  tree body = NULL_TREE;
-
-  if (emutls_htab == NULL)
-    return;
+  if (!targetm.emutls.register_common)
+    {
+      tree body = NULL_TREE;
 
-  htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
-  if (body == NULL_TREE)
-    return;
+      if (emutls_htab == NULL)
+	return;
 
-  cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
+      htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
+      if (body == NULL_TREE)
+	return;
+      
+      cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
+    }
 }
 
 /* Helper routines for maintaining section_htab.  */
@@ -1135,7 +1171,12 @@ get_variable_section (tree decl, bool pr
     {
       if (DECL_THREAD_LOCAL_P (decl))
 	return tls_comm_section;
-      if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
+      /* This cannot be common bss for an emulated TLS object without
+	 a register_common hook.  */
+      else if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED
+	       && !targetm.emutls.register_common)
+	;
+      else if (TREE_PUBLIC (decl) && bss_initializer_p (decl))
 	return comm_section;
     }
 
@@ -1960,6 +2001,40 @@ assemble_variable_contents (tree decl, c
     }
 }
 
+/* Initialize emulated tls object TO, which refers to TLS variable
+   DECL and is initialized by PROXY.  */
+
+tree
+default_emutls_var_init (tree to, tree decl, tree proxy)
+{
+  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
+  constructor_elt *elt;
+  tree type = TREE_TYPE (to);
+  tree field = TYPE_FIELDS (type);
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  elt->index = field;
+  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = build_int_cst (TREE_TYPE (field),
+			      DECL_ALIGN_UNIT (decl));
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = null_pointer_node;
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = proxy;
+  
+  return build_constructor (type, v);
+}
+
 /* Assemble everything that is needed for a variable or function declaration.
    Not used for automatic variables, and not used for function definitions.
    Should not be called for variables of incomplete structure type.
@@ -1994,32 +2069,8 @@ assemble_variable (tree decl, int top_le
 	      || (DECL_INITIAL (decl)
 		  && DECL_INITIAL (decl) != error_mark_node)))
 	{
-	  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4);
-	  constructor_elt *elt;
-	  tree type = TREE_TYPE (to);
-	  tree field = TYPE_FIELDS (type);
-
-	  elt = VEC_quick_push (constructor_elt, v, NULL);
-	  elt->index = field;
-	  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
-
-	  elt = VEC_quick_push (constructor_elt, v, NULL);
-	  field = TREE_CHAIN (field);
-	  elt->index = field;
-	  elt->value = build_int_cst (TREE_TYPE (field),
-				      DECL_ALIGN_UNIT (decl));
-
-	  elt = VEC_quick_push (constructor_elt, v, NULL);
-	  field = TREE_CHAIN (field);
-	  elt->index = field;
-	  elt->value = null_pointer_node;
-
-	  elt = VEC_quick_push (constructor_elt, v, NULL);
-	  field = TREE_CHAIN (field);
-	  elt->index = field;
-	  elt->value = get_emutls_init_templ_addr (decl);
-
-	  DECL_INITIAL (to) = build_constructor (type, v);
+	  DECL_INITIAL (to) = targetm.emutls.var_init
+	    (to, decl, get_emutls_init_templ_addr (decl));
 
 	  /* Make sure the template is marked as needed early enough.
 	     Without this, if the variable is placed in a
@@ -5806,13 +5857,26 @@ categorize_decl_for_section (const_tree 
     ret = SECCAT_RODATA;
 
   /* There are no read-only thread-local sections.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
+  if (TREE_CODE (decl) == VAR_DECL && DECL_TLS_MODEL (decl))
     {
+      if (DECL_TLS_MODEL (decl) == TLS_MODEL_EMULATED)
+	{
+	  if (DECL_EMUTLS_VAR_P (decl))
+	    {
+	      if (targetm.emutls.var_section)
+		ret = SECCAT_EMUTLS_VAR;
+	    }
+	  else
+	    {
+	      if (targetm.emutls.tmpl_prefix)
+		ret = SECCAT_EMUTLS_TMPL;
+	    }
+	}
       /* Note that this would be *just* SECCAT_BSS, except that there's
 	 no concept of a read-only thread-local-data section.  */
-      if (ret == SECCAT_BSS
-	  || (flag_zero_initialized_in_bss
-	      && initializer_zerop (DECL_INITIAL (decl))))
+      else if (ret == SECCAT_BSS
+	       || (flag_zero_initialized_in_bss
+		   && initializer_zerop (DECL_INITIAL (decl))))
 	ret = SECCAT_TBSS;
       else
 	ret = SECCAT_TDATA;
@@ -5904,6 +5968,12 @@ default_elf_select_section (tree decl, i
     case SECCAT_TBSS:
       sname = ".tbss";
       break;
+    case SECCAT_EMUTLS_VAR:
+      sname = targetm.emutls.var_section;
+      break;
+    case SECCAT_EMUTLS_TMPL:
+      sname = targetm.emutls.tmpl_section;
+      break;
     default:
       gcc_unreachable ();
     }
@@ -5921,69 +5991,73 @@ default_unique_section (tree decl, int r
 {
   /* We only need to use .gnu.linkonce if we don't have COMDAT groups.  */
   bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
-  const char *prefix, *name;
-  size_t nlen, plen;
+  const char *prefix, *name, *linkonce;
   char *string;
 
   switch (categorize_decl_for_section (decl, reloc))
     {
     case SECCAT_TEXT:
-      prefix = one_only ? ".gnu.linkonce.t." : ".text.";
+      prefix = one_only ? ".t" : ".text";
       break;
     case SECCAT_RODATA:
     case SECCAT_RODATA_MERGE_STR:
     case SECCAT_RODATA_MERGE_STR_INIT:
     case SECCAT_RODATA_MERGE_CONST:
-      prefix = one_only ? ".gnu.linkonce.r." : ".rodata.";
+      prefix = one_only ? ".r" : ".rodata";
       break;
     case SECCAT_SRODATA:
-      prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2.";
+      prefix = one_only ? ".s2" : ".sdata2";
       break;
     case SECCAT_DATA:
-      prefix = one_only ? ".gnu.linkonce.d." : ".data.";
+      prefix = one_only ? ".d" : ".data";
       break;
     case SECCAT_DATA_REL:
-      prefix = one_only ? ".gnu.linkonce.d.rel." : ".data.rel.";
+      prefix = one_only ? ".d.rel" : ".data.rel";
       break;
     case SECCAT_DATA_REL_LOCAL:
-      prefix = one_only ? ".gnu.linkonce.d.rel.local." : ".data.rel.local.";
+      prefix = one_only ? ".d.rel.local" : ".data.rel.local";
       break;
     case SECCAT_DATA_REL_RO:
-      prefix = one_only ? ".gnu.linkonce.d.rel.ro." : ".data.rel.ro.";
+      prefix = one_only ? ".d.rel.ro" : ".data.rel.ro";
       break;
     case SECCAT_DATA_REL_RO_LOCAL:
-      prefix = one_only ? ".gnu.linkonce.d.rel.ro.local."
-	       : ".data.rel.ro.local.";
+      prefix = one_only ? ".d.rel.ro.local" : ".data.rel.ro.local";
       break;
     case SECCAT_SDATA:
-      prefix = one_only ? ".gnu.linkonce.s." : ".sdata.";
+      prefix = one_only ? ".s" : ".sdata";
       break;
     case SECCAT_BSS:
-      prefix = one_only ? ".gnu.linkonce.b." : ".bss.";
+      prefix = one_only ? ".b" : ".bss";
       break;
     case SECCAT_SBSS:
-      prefix = one_only ? ".gnu.linkonce.sb." : ".sbss.";
+      prefix = one_only ? ".sb" : ".sbss";
       break;
     case SECCAT_TDATA:
-      prefix = one_only ? ".gnu.linkonce.td." : ".tdata.";
+      prefix = one_only ? ".td" : ".tdata";
       break;
     case SECCAT_TBSS:
-      prefix = one_only ? ".gnu.linkonce.tb." : ".tbss.";
+      prefix = one_only ? ".tb" : ".tbss";
+      break;
+    case SECCAT_EMUTLS_VAR:
+      prefix = targetm.emutls.var_section;
+      break;
+    case SECCAT_EMUTLS_TMPL:
+      prefix = targetm.emutls.tmpl_section;
       break;
     default:
       gcc_unreachable ();
     }
-  plen = strlen (prefix);
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   name = targetm.strip_name_encoding (name);
-  nlen = strlen (name);
 
-  string = alloca (nlen + plen + 1);
-  memcpy (string, prefix, plen);
-  memcpy (string + plen, name, nlen + 1);
+  /* If we're using one_only, then there needs to be a .gnu.linkonce
+     prefix to the section name.  */
+  linkonce = one_only ? ".gnu.linkonce" : "";
+  
+  string = ACONCAT ((linkonce, prefix, ".", name, NULL));
 
-  DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
+  DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
 }
 
 /* Like compute_reloc_for_constant, except for an RTX.  The return value
Index: gcc/target-def.h
===================================================================
--- gcc/target-def.h	(revision 196914)
+++ gcc/target-def.h	(working copy)
@@ -692,6 +692,61 @@
     TARGET_CXX_ADJUST_CLASS_AT_DEFINITION	\
   }
 
+/* EMUTLS specific */
+#ifndef TARGET_EMUTLS_GET_ADDRESS
+#define TARGET_EMUTLS_GET_ADDRESS "__builtin___emutls_get_address"
+#endif
+
+#ifndef TARGET_EMUTLS_REGISTER_COMMON
+#define TARGET_EMUTLS_REGISTER_COMMON "__builtin___emutls_register_common"
+#endif
+
+#ifndef TARGET_EMUTLS_VAR_SECTION
+#define TARGET_EMUTLS_VAR_SECTION NULL
+#endif
+
+#ifndef TARGET_EMUTLS_TMPL_SECTION
+#define TARGET_EMUTLS_TMPL_SECTION NULL
+#endif
+
+#ifndef TARGET_EMUTLS_VAR_PREFIX
+#define TARGET_EMUTLS_VAR_PREFIX NULL
+#endif
+
+#ifndef TARGET_EMUTLS_TMPL_PREFIX
+#define TARGET_EMUTLS_TMPL_PREFIX NULL
+#endif
+
+#ifndef TARGET_EMUTLS_VAR_FIELDS
+#define TARGET_EMUTLS_VAR_FIELDS default_emutls_var_fields
+#endif
+
+#ifndef TARGET_EMUTLS_VAR_INIT
+#define TARGET_EMUTLS_VAR_INIT default_emutls_var_init
+#endif
+
+#ifndef TARGET_EMUTLS_VAR_ALIGN_FIXED
+#define TARGET_EMUTLS_VAR_ALIGN_FIXED false
+#endif
+
+#ifndef TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS
+#define TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS false
+#endif
+
+#define TARGET_EMUTLS				\
+  {						\
+    TARGET_EMUTLS_GET_ADDRESS,  		\
+    TARGET_EMUTLS_REGISTER_COMMON,  		\
+    TARGET_EMUTLS_VAR_SECTION,  		\
+    TARGET_EMUTLS_TMPL_SECTION,  		\
+    TARGET_EMUTLS_VAR_PREFIX,  			\
+    TARGET_EMUTLS_TMPL_PREFIX,  		\
+    TARGET_EMUTLS_VAR_FIELDS,			\
+    TARGET_EMUTLS_VAR_INIT,			\
+    TARGET_EMUTLS_VAR_ALIGN_FIXED,		\
+    TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS	\
+  }
+
 /* The whole shebang.  */
 #define TARGET_INITIALIZER			\
 {						\
@@ -783,6 +838,7 @@
   TARGET_INSTANTIATE_DECLS,			\
   TARGET_C,					\
   TARGET_CXX,					\
+  TARGET_EMUTLS,				\
   TARGET_EXTRA_LIVE_ON_ENTRY,			\
   TARGET_UNWIND_TABLES_DEFAULT,			\
   TARGET_HAVE_NAMED_SECTIONS,			\
Index: gcc/output.h
===================================================================
--- gcc/output.h	(revision 196914)
+++ gcc/output.h	(working copy)
@@ -460,7 +460,10 @@ enum section_category
 
   SECCAT_BSS,
   SECCAT_SBSS,
-  SECCAT_TBSS
+  SECCAT_TBSS,
+
+  SECCAT_EMUTLS_VAR,
+  SECCAT_EMUTLS_TMPL
 };
 
 /* Information that is provided by all instances of the section type.  */
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c	(revision 196914)
+++ gcc/c-common.c	(working copy)
@@ -5401,6 +5401,13 @@ handle_section_attribute (tree *node, tr
 		     *node);
 	      *no_add_attrs = true;
 	    }
+	  else if (TREE_CODE (decl) == VAR_DECL
+		   && !targetm.have_tls && targetm.emutls.tmpl_section
+		   && DECL_THREAD_LOCAL_P (decl))
+	    {
+	      error ("section of %q+D cannot be overridden", *node);
+	      *no_add_attrs = true;
+	    }
 	  else
 	    DECL_SECTION_NAME (decl) = TREE_VALUE (args);
 	}
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 196914)
+++ gcc/config/i386/i386.c	(working copy)
@@ -2835,6 +2835,9 @@ x86_64_elf_select_section (tree decl, in
 	  /* We don't split these for medium model.  Place them into
 	     default sections and hope for best.  */
 	  break;
+	case SECCAT_EMUTLS_VAR:
+	case SECCAT_EMUTLS_TMPL:
+	  gcc_unreachable ();
 	}
       if (sname)
 	{
@@ -2871,16 +2874,16 @@ x86_64_elf_unique_section (tree decl, in
 	case SECCAT_DATA_REL_LOCAL:
 	case SECCAT_DATA_REL_RO:
 	case SECCAT_DATA_REL_RO_LOCAL:
-          prefix = one_only ? ".gnu.linkonce.ld." : ".ldata.";
+          prefix = one_only ? ".ld" : ".ldata";
 	  break;
 	case SECCAT_BSS:
-          prefix = one_only ? ".gnu.linkonce.lb." : ".lbss.";
+          prefix = one_only ? ".lb" : ".lbss";
 	  break;
 	case SECCAT_RODATA:
 	case SECCAT_RODATA_MERGE_STR:
 	case SECCAT_RODATA_MERGE_STR_INIT:
 	case SECCAT_RODATA_MERGE_CONST:
-          prefix = one_only ? ".gnu.linkonce.lr." : ".lrodata.";
+          prefix = one_only ? ".lr" : ".lrodata";
 	  break;
 	case SECCAT_SRODATA:
 	case SECCAT_SDATA:
@@ -2892,23 +2895,28 @@ x86_64_elf_unique_section (tree decl, in
 	  /* We don't split these for medium model.  Place them into
 	     default sections and hope for best.  */
 	  break;
+	case SECCAT_EMUTLS_VAR:
+	  prefix = targetm.emutls.var_section;
+	  break;
+	case SECCAT_EMUTLS_TMPL:
+	  prefix = targetm.emutls.tmpl_section;
+	  break;
 	}
       if (prefix)
 	{
-	  const char *name;
-	  size_t nlen, plen;
+	  const char *name, *linkonce;
 	  char *string;
-	  plen = strlen (prefix);
 
 	  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
 	  name = targetm.strip_name_encoding (name);
-	  nlen = strlen (name);
-
-	  string = (char *) alloca (nlen + plen + 1);
-	  memcpy (string, prefix, plen);
-	  memcpy (string + plen, name, nlen + 1);
-
-	  DECL_SECTION_NAME (decl) = build_string (nlen + plen, string);
+	  
+	  /* If we're using one_only, then there needs to be a .gnu.linkonce
+     	     prefix to the section name.  */
+	  linkonce = one_only ? ".gnu.linkonce" : "";
+  
+	  string = ACONCAT ((linkonce, prefix, ".", name, NULL));
+	  
+	  DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
 	  return;
 	}
     }
Index: gcc/config/vxworks.c
===================================================================
--- gcc/config/vxworks.c	(revision 196914)
+++ gcc/config/vxworks.c	(working copy)
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  
 #include "toplev.h"
 #include "output.h"
 #include "tm.h"
+#include "tree.h"
 
 /* Like default_named_section_asm_out_constructor, except that even
    constructors with DEFAULT_INIT_PRIORITY must go in a numbered
@@ -56,16 +57,132 @@ vxworks_asm_out_destructor (rtx symbol, 
   assemble_addr_to_section (symbol, sec);
 }
 
+static tree
+vxworks_emutls_var_fields (tree type, tree *name)
+{
+  tree field, next_field;
+  
+  *name = get_identifier ("__tls_var");
+  
+  field = build_decl (FIELD_DECL, get_identifier ("size"),
+		      unsigned_type_node);
+  DECL_CONTEXT (field) = type;
+  next_field = field;
+
+  field = build_decl (FIELD_DECL, get_identifier ("module_id"),
+		      unsigned_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+  next_field = field;
+
+  field = build_decl (FIELD_DECL, get_identifier ("offset"),
+		      unsigned_type_node);
+  DECL_CONTEXT (field) = type;
+  TREE_CHAIN (field) = next_field;
+
+  return field;
+}
+
+static tree
+vxworks_emutls_var_init (tree var, tree decl, tree tmpl_addr)
+{
+  VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 3);
+  constructor_elt *elt;
+  
+  tree type = TREE_TYPE (var);
+  tree field = TYPE_FIELDS (type);
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  elt->index = field;
+  elt->value = fold_convert (TREE_TYPE (field), tmpl_addr);
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = build_int_cst (TREE_TYPE (field), 0);
+  
+  elt = VEC_quick_push (constructor_elt, v, NULL);
+  field = TREE_CHAIN (field);
+  elt->index = field;
+  elt->value = fold_convert (TREE_TYPE (field), DECL_SIZE_UNIT (decl));
+  
+  return build_constructor (type, v);
+}
+
 /* Do VxWorks-specific parts of OVERRIDE_OPTIONS.  */
 
 void
 vxworks_override_options (void)
 {
+  /* We don't support __thread via target hooks.  */
+  targetm.have_tls = false;
+
+  targetm.emutls.get_address = "__builtin___tls_lookup";
+  targetm.emutls.register_common = NULL;
+  targetm.emutls.var_section = ".tls_vars";
+  targetm.emutls.tmpl_section = ".tls_data";
+  targetm.emutls.var_prefix = "__tls__";
+  targetm.emutls.tmpl_prefix = "";
+  targetm.emutls.var_fields = vxworks_emutls_var_fields;
+  targetm.emutls.var_init = vxworks_emutls_var_init;
+  targetm.emutls.var_align_fixed = true;
+  targetm.emutls.debug_form_tls_address = true;
+  
   /* We can use .ctors/.dtors sections only in RTP mode.  */
   targetm.have_ctors_dtors = TARGET_VXWORKS_RTP;
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]