targhooks.h (default_emutls_var_fields, [...]): Declare.

* 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/doc/tm.texi (Emulated TLS): New node.

	gcc/testsuite/
	* gcc.dg/tls/section-2.c: New.
	* gcc.dg/tls/emutls-1.c: New.
	* lib/target-supports.exp (check_effective_target_tls_native):
	Exclude vxworks.

From-SVN: r134729
This commit is contained in:
Nathan Sidwell 2008-04-27 15:35:19 +00:00 committed by Nathan Sidwell
parent f509e29629
commit feb60f0328
18 changed files with 584 additions and 135 deletions

View File

@ -1,3 +1,46 @@
2008-04-27 Nathan Sidwell <nathan@codesourcery.com>
* 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/doc/tm.texi (Emulated TLS): New node.
2008-04-26 Simon Baldwin <simonb@google.com> 2008-04-26 Simon Baldwin <simonb@google.com>
PR c/35652 PR c/35652

View File

@ -745,8 +745,16 @@ DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_ENTER, "profile_func_enter")
DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit") DEF_BUILTIN_STUB (BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit")
/* TLS emulation. */ /* TLS emulation. */
DEF_EXT_LIB_BUILTIN (BUILT_IN_EMUTLS_GET_ADDRESS, "__emutls_get_address", BT_FN_PTR_PTR, ATTR_CONST_NOTHROW_NONNULL) DEF_BUILTIN (BUILT_IN_EMUTLS_GET_ADDRESS, targetm.emutls.get_address,
DEF_EXT_LIB_BUILTIN (BUILT_IN_EMUTLS_REGISTER_COMMON, "__emutls_register_common", BT_FN_VOID_PTR_WORD_WORD_PTR, ATTR_NOTHROW_LIST) 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. */ /* Synchronization Primitives. */
#include "sync-builtins.def" #include "sync-builtins.def"

View File

@ -5476,6 +5476,13 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
*node); *node);
*no_add_attrs = true; *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 else
DECL_SECTION_NAME (decl) = TREE_VALUE (args); DECL_SECTION_NAME (decl) = TREE_VALUE (args);
} }

View File

@ -2854,6 +2854,9 @@ x86_64_elf_select_section (tree decl, int reloc,
/* We don't split these for medium model. Place them into /* We don't split these for medium model. Place them into
default sections and hope for best. */ default sections and hope for best. */
break; break;
case SECCAT_EMUTLS_VAR:
case SECCAT_EMUTLS_TMPL:
gcc_unreachable ();
} }
if (sname) if (sname)
{ {
@ -2890,16 +2893,16 @@ x86_64_elf_unique_section (tree decl, int reloc)
case SECCAT_DATA_REL_LOCAL: case SECCAT_DATA_REL_LOCAL:
case SECCAT_DATA_REL_RO: case SECCAT_DATA_REL_RO:
case SECCAT_DATA_REL_RO_LOCAL: case SECCAT_DATA_REL_RO_LOCAL:
prefix = one_only ? ".gnu.linkonce.ld." : ".ldata."; prefix = one_only ? ".ld" : ".ldata";
break; break;
case SECCAT_BSS: case SECCAT_BSS:
prefix = one_only ? ".gnu.linkonce.lb." : ".lbss."; prefix = one_only ? ".lb" : ".lbss";
break; break;
case SECCAT_RODATA: case SECCAT_RODATA:
case SECCAT_RODATA_MERGE_STR: case SECCAT_RODATA_MERGE_STR:
case SECCAT_RODATA_MERGE_STR_INIT: case SECCAT_RODATA_MERGE_STR_INIT:
case SECCAT_RODATA_MERGE_CONST: case SECCAT_RODATA_MERGE_CONST:
prefix = one_only ? ".gnu.linkonce.lr." : ".lrodata."; prefix = one_only ? ".lr" : ".lrodata";
break; break;
case SECCAT_SRODATA: case SECCAT_SRODATA:
case SECCAT_SDATA: case SECCAT_SDATA:
@ -2911,23 +2914,28 @@ x86_64_elf_unique_section (tree decl, int reloc)
/* We don't split these for medium model. Place them into /* We don't split these for medium model. Place them into
default sections and hope for best. */ default sections and hope for best. */
break; break;
case SECCAT_EMUTLS_VAR:
prefix = targetm.emutls.var_section;
break;
case SECCAT_EMUTLS_TMPL:
prefix = targetm.emutls.tmpl_section;
break;
} }
if (prefix) if (prefix)
{ {
const char *name; const char *name, *linkonce;
size_t nlen, plen;
char *string; char *string;
plen = strlen (prefix);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = targetm.strip_name_encoding (name); name = targetm.strip_name_encoding (name);
nlen = strlen (name);
string = (char *) alloca (nlen + plen + 1); /* If we're using one_only, then there needs to be a .gnu.linkonce
memcpy (string, prefix, plen); prefix to the section name. */
memcpy (string + plen, name, nlen + 1); linkonce = one_only ? ".gnu.linkonce" : "";
DECL_SECTION_NAME (decl) = build_string (nlen + plen, string); string = ACONCAT ((linkonce, prefix, ".", name, NULL));
DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
return; return;
} }
} }

View File

@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "toplev.h" #include "toplev.h"
#include "output.h" #include "output.h"
#include "tm.h" #include "tm.h"
#include "tree.h"
/* Like default_named_section_asm_out_constructor, except that even /* Like default_named_section_asm_out_constructor, except that even
constructors with DEFAULT_INIT_PRIORITY must go in a numbered constructors with DEFAULT_INIT_PRIORITY must go in a numbered
@ -56,11 +57,87 @@ vxworks_asm_out_destructor (rtx symbol, int priority)
assemble_addr_to_section (symbol, sec); assemble_addr_to_section (symbol, sec);
} }
/* Return the list of FIELD_DECLs that make up an emulated TLS
variable's control object. TYPE is the structure these are fields
of and *NAME will be filled in with the structure tag that should
be used. */
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;
}
/* Return the CONSTRUCTOR to initialize an emulated TLS control
object. VAR is the control object. DECL is the TLS object itself
and TMPL_ADDR is the address (an ADDR_EXPR) of the initializer for
that object. */
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. */ /* Do VxWorks-specific parts of OVERRIDE_OPTIONS. */
void void
vxworks_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. */ /* We can use .ctors/.dtors sections only in RTP mode. */
targetm.have_ctors_dtors = TARGET_VXWORKS_RTP; targetm.have_ctors_dtors = TARGET_VXWORKS_RTP;

View File

@ -69,7 +69,9 @@ struct cpp_reader;
to it, so it's here. */ to it, so it's here. */
enum tls_model { enum tls_model {
TLS_MODEL_NONE, 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_LOCAL_DYNAMIC,
TLS_MODEL_INITIAL_EXEC, TLS_MODEL_INITIAL_EXEC,
TLS_MODEL_LOCAL_EXEC TLS_MODEL_LOCAL_EXEC

View File

@ -50,6 +50,7 @@ through the macros defined in the @file{.h} file.
* Floating Point:: Handling floating point for cross-compilers. * Floating Point:: Handling floating point for cross-compilers.
* Mode Switching:: Insertion of mode-switching instructions. * Mode Switching:: Insertion of mode-switching instructions.
* Target Attributes:: Defining target-specific uses of @code{__attribute__}. * Target Attributes:: Defining target-specific uses of @code{__attribute__}.
* Emulated TLS:: Emulated TLS support.
* MIPS Coprocessors:: MIPS coprocessor support and how to customize it. * MIPS Coprocessors:: MIPS coprocessor support and how to customize it.
* PCH Target:: Validity checking for precompiled headers. * PCH Target:: Validity checking for precompiled headers.
* C++ ABI:: Controlling C++ ABI changes. * C++ ABI:: Controlling C++ ABI changes.
@ -9192,6 +9193,84 @@ attributes, @code{false} otherwise. By default, if a function has a
target specific attribute attached to it, it will not be inlined. target specific attribute attached to it, it will not be inlined.
@end deftypefn @end deftypefn
@node Emulated TLS
@section Emulating TLS
@cindex Emulated TLS
For targets whose psABI does not provide Thread Local Storage via
specific relocations and instruction sequences, an emulation layer is
used. A set of target hooks allows this emulation layer to be
configured for the requirements of a particular target. For instance
the psABI may infact specify TLS support in terms of an emulation
layer.
The emulation layer works by creating a control object for every TLS
object. To access the TLS object, a lookup function is provided
which, when given the address of the control object, will return the
address of the current thread's instance of the TLS object.
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_GET_ADDRESS
Contains the name of the helper function that uses a TLS control
object to locate a TLS instance. The default causes libgcc's
emulated TLS helper function to be used.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_REGISTER_COMMON
Contains the name of the helper function that should be used at
program startup to register TLS objects that are implicitly
initialized to zero. If this is @code{NULL}, all TLS objects will
have explicit initializers. The default causes libgcc's emulated TLS
registration function to be used.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_VAR_SECTION
Contains the name of the section in which TLS control variables should
be placed. The default of @code{NULL} allows these to be placed in
any section.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_TMPL_SECTION
Contains the name of the section in which TLS initializers should be
placed. The default of @code{NULL} allows these to be placed in any
section.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_VAR_PREFIX
Contains the prefix to be prepended to TLS control variable names.
The default of @code{NULL} uses a target-specific prefix.
@end deftypevr
@deftypevr {Target Hook} {const char *} TARGET_EMUTLS_TMPL_PREFIX
Contains the prefix to be prepended to TLS initializer objects. The
default of @code{NULL} uses a target-specific prefix.
@end deftypevr
@deftypefn {Target Hook} tree TARGET_EMUTLS_VAR_FIELDS (tree @var{type}, tree *@var{name})
Specifies a function that generates the FIELD_DECLs for a TLS control
object type. @var{type} is the RECORD_TYPE the fields are for and
@var{name} should be filled with the structure tag, if the default of
@code{__emutls_object} is unsuitable. The default creates a type suitable
for libgcc's emulated TLS function.
@end deftypefn
@deftypefn {Target Hook} tree TARGET_EMUTLS_VAR_INIT (tree @var{var}, tree @var{decl}, tree @var{tmpl_addr})
Specifies a function that generates the CONSTRUCTOR to initialize a
TLS control object. @var{var} is the TLS control object, @var{decl}
is the TLS object and @var{tmpl_addr} is the address of the
initializer. The default initializes libgcc's emulated TLS control object.
@end deftypefn
@deftypevr {Target Hook} {bool} TARGET_EMUTLS_VAR_ALIGN_FIXED
Specifies whether the alignment of TLS control variable objects is
fixed and should not be increased as some backends may do to optimize
single objects. The default is false.
@end deftypevr
@deftypevr {Target Hook} {bool} TARGET_EMUTLS_DEBUG_FORM_TLS_ADDRESS
Specifies whether a DWARF @code{DW_OP_form_tls_address} location descriptor
may be used to describe emulated TLS control objects.
@end deftypevr
@node MIPS Coprocessors @node MIPS Coprocessors
@section Defining coprocessor specifics for MIPS targets. @section Defining coprocessor specifics for MIPS targets.
@cindex MIPS coprocessor-definition macros @cindex MIPS coprocessor-definition macros

View File

@ -9494,15 +9494,32 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
if (DECL_THREAD_LOCAL_P (loc)) if (DECL_THREAD_LOCAL_P (loc))
{ {
rtx rtl; 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)
if (!targetm.have_tls || !targetm.asm_out.output_dwarf_dtprel) {
/* If this is not defined, we have no way to emit the
data. */
if (!targetm.asm_out.output_dwarf_dtprel)
return 0; return 0;
/* The way DW_OP_GNU_push_tls_address is specified, we can only /* The way DW_OP_GNU_push_tls_address is specified, we
look up addresses of objects in the current module. */ can only look up addresses of objects in the current
module. */
if (DECL_EXTERNAL (loc)) if (DECL_EXTERNAL (loc))
return 0; 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); rtl = rtl_for_decl_location (loc);
if (rtl == NULL_RTX) if (rtl == NULL_RTX)
@ -9514,11 +9531,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
if (! CONSTANT_P (rtl)) if (! CONSTANT_P (rtl))
return 0; 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.val_class = dw_val_class_addr;
ret->dw_loc_oprnd1.v.val_addr = rtl; 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); add_loc_descr (&ret, ret1);
have_address = 1; have_address = 1;

View File

@ -460,7 +460,10 @@ enum section_category
SECCAT_BSS, SECCAT_BSS,
SECCAT_SBSS, SECCAT_SBSS,
SECCAT_TBSS SECCAT_TBSS,
SECCAT_EMUTLS_VAR,
SECCAT_EMUTLS_TMPL
}; };
/* Information that is provided by all instances of the section type. */ /* Information that is provided by all instances of the section type. */

View File

@ -692,6 +692,61 @@
TARGET_CXX_ADJUST_CLASS_AT_DEFINITION \ 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. */ /* The whole shebang. */
#define TARGET_INITIALIZER \ #define TARGET_INITIALIZER \
{ \ { \
@ -783,6 +838,7 @@
TARGET_INSTANTIATE_DECLS, \ TARGET_INSTANTIATE_DECLS, \
TARGET_C, \ TARGET_C, \
TARGET_CXX, \ TARGET_CXX, \
TARGET_EMUTLS, \
TARGET_EXTRA_LIVE_ON_ENTRY, \ TARGET_EXTRA_LIVE_ON_ENTRY, \
TARGET_UNWIND_TABLES_DEFAULT, \ TARGET_UNWIND_TABLES_DEFAULT, \
TARGET_HAVE_NAMED_SECTIONS, \ TARGET_HAVE_NAMED_SECTIONS, \

View File

@ -917,6 +917,34 @@ struct gcc_target
void (*adjust_class_at_definition) (tree type); void (*adjust_class_at_definition) (tree type);
} cxx; } cxx;
/* Functions and data for emulated TLS support. */
struct emutls {
/* Name of the address and common functions. */
const char *get_address;
const char *register_common;
/* Prefixes for proxy variable and template. */
const char *var_section;
const char *tmpl_section;
/* Prefixes for proxy variable and template. */
const char *var_prefix;
const char *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 /* For targets that need to mark extra registers as live on entry to
the function, they should define this target hook and set their the function, they should define this target hook and set their
bits in the bitmap passed in. */ bits in the bitmap passed in. */

View File

@ -94,3 +94,5 @@ extern void hook_void_bitmap (bitmap);
extern bool default_handle_c_option (size_t, const char *, int); extern bool default_handle_c_option (size_t, const char *, int);
extern int default_reloc_rw_mask (void); extern int default_reloc_rw_mask (void);
extern tree default_mangle_decl_assembler_name (tree, tree); 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);

View File

@ -1,3 +1,10 @@
2008-04-27 Nathan Sidwell <nathan@codesourcery.com>
* gcc.dg/tls/section-2.c: New.
* gcc.dg/tls/emutls-1.c: New.
* lib/target-supports.exp (check_effective_target_tls_native):
Exclude vxworks.
2008-04-26 H.J. Lu <hongjiu.lu@intel.com> 2008-04-26 H.J. Lu <hongjiu.lu@intel.com>
PR testsuite/36053 PR testsuite/36053

View File

@ -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;
}

View File

@ -0,0 +1,7 @@
/* Verify that we get errors for trying to put TLS data in
sections which can't work. */
/* { dg-require-effective-target tls } */
#define A(X) __attribute__((section(X)))
__thread int i A("foo"); /* { dg-error "cannot be overridden" } */

View File

@ -518,6 +518,13 @@ proc check_effective_target_tls {} {
# This won't change for different subtargets so cache the result. # This won't change for different subtargets so cache the result.
proc check_effective_target_tls_native {} { proc check_effective_target_tls_native {} {
# VxWorks uses emulated TLS machinery, but with non-standard helper
# functions, so we fail to automatically detect it.
global target_triplet
if { [regexp ".*-.*-vxworks.*" $target_triplet] } {
return 0
}
return [check_no_messages_and_pattern tls_native "!emutls" assembly { return [check_no_messages_and_pattern tls_native "!emutls" assembly {
__thread int i; __thread int i;
int f (void) { return i; } int f (void) { return i; }

View File

@ -3178,7 +3178,7 @@ extern void decl_fini_priority_insert (tree, priority_type);
/* In a VAR_DECL, nonzero if the data should be allocated from /* In a VAR_DECL, nonzero if the data should be allocated from
thread-local storage. */ thread-local storage. */
#define DECL_THREAD_LOCAL_P(NODE) \ #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(()) struct tree_var_decl GTY(())
{ {

View File

@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm_p.h" #include "tm_p.h"
#include "debug.h" #include "debug.h"
#include "target.h" #include "target.h"
#include "targhooks.h"
#include "tree-mudflap.h" #include "tree-mudflap.h"
#include "cgraph.h" #include "cgraph.h"
#include "cfglayout.h" #include "cfglayout.h"
@ -194,60 +195,65 @@ static GTY(()) struct rtx_constant_pool *shared_constant_pool;
static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map))) static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
htab_t emutls_htab; htab_t emutls_htab;
static GTY (()) tree emutls_object_type; static GTY (()) tree emutls_object_type;
/* 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)
#ifndef NO_DOT_IN_LABEL #if !defined (NO_DOT_IN_LABEL)
# define EMUTLS_VAR_PREFIX "__emutls_v." # define EMUTLS_SEPARATOR "."
# define EMUTLS_TMPL_PREFIX "__emutls_t." #elif !defined (NO_DOLLAR_IN_LABEL)
#elif !defined NO_DOLLAR_IN_LABEL # define EMUTLS_SEPARATOR "$"
# define EMUTLS_VAR_PREFIX "__emutls_v$"
# define EMUTLS_TMPL_PREFIX "__emutls_t$"
#else #else
# define EMUTLS_VAR_PREFIX "__emutls_v_" # define EMUTLS_SEPARATOR "_"
# define EMUTLS_TMPL_PREFIX "__emutls_t_"
#endif #endif
/* Create an IDENTIFIER_NODE by prefixing PREFIX to the
IDENTIFIER_NODE NAME's name. */
static tree
prefix_name (const char *prefix, tree 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 an identifier for the struct __emutls_object, given an identifier /* Create an identifier for the struct __emutls_object, given an identifier
of the DECL_ASSEMBLY_NAME of the original object. */ of the DECL_ASSEMBLY_NAME of the original object. */
static tree static tree
get_emutls_object_name (tree name) get_emutls_object_name (tree name)
{ {
char *toname = alloca (strlen (IDENTIFIER_POINTER (name)) const char *prefix = (targetm.emutls.var_prefix
+ sizeof (EMUTLS_VAR_PREFIX)); ? targetm.emutls.var_prefix
strcpy (toname, EMUTLS_VAR_PREFIX); : "__emutls_v" EMUTLS_SEPARATOR);
strcpy (toname + sizeof (EMUTLS_VAR_PREFIX) - 1, IDENTIFIER_POINTER (name)); return prefix_name (prefix, name);
return get_identifier (toname);
} }
/* Create the structure for struct __emutls_object. This should match the tree
structure at the top of emutls.c, modulo the union there. */ default_emutls_var_fields (tree type, tree *name ATTRIBUTE_UNUSED)
static tree
get_emutls_object_type (void)
{ {
tree type, type_name, field, next_field, word_type_node; tree word_type_node, field, next_field;
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;
field = build_decl (FIELD_DECL, get_identifier ("__templ"), ptr_type_node); field = build_decl (FIELD_DECL, get_identifier ("__templ"), ptr_type_node);
DECL_CONTEXT (field) = type; DECL_CONTEXT (field) = type;
next_field = field; 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; DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field; TREE_CHAIN (field) = next_field;
next_field = field; next_field = field;
word_type_node = lang_hooks.types.type_for_mode (word_mode, 1); 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; DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field; TREE_CHAIN (field) = next_field;
next_field = field; next_field = field;
@ -256,6 +262,28 @@ get_emutls_object_type (void)
DECL_CONTEXT (field) = type; DECL_CONTEXT (field) = type;
TREE_CHAIN (field) = next_field; 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; TYPE_FIELDS (type) = field;
layout_type (type); layout_type (type);
@ -269,26 +297,30 @@ static tree
get_emutls_init_templ_addr (tree decl) get_emutls_init_templ_addr (tree decl)
{ {
tree name, to; 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; return null_pointer_node;
name = DECL_ASSEMBLER_NAME (decl); name = DECL_ASSEMBLER_NAME (decl);
toname = alloca (strlen (IDENTIFIER_POINTER (name)) if (!targetm.emutls.tmpl_prefix || targetm.emutls.tmpl_prefix[0])
+ sizeof (EMUTLS_TMPL_PREFIX)); {
strcpy (toname, EMUTLS_TMPL_PREFIX); const char *prefix = (targetm.emutls.tmpl_prefix
strcpy (toname + sizeof (EMUTLS_TMPL_PREFIX) - 1, IDENTIFIER_POINTER (name)); ? targetm.emutls.tmpl_prefix
name = get_identifier (toname); : "__emutls_t" EMUTLS_SEPARATOR);
name = prefix_name (prefix, name);
}
to = build_decl (VAR_DECL, name, TREE_TYPE (decl)); to = build_decl (VAR_DECL, name, TREE_TYPE (decl));
SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
DECL_ARTIFICIAL (to) = 1; DECL_ARTIFICIAL (to) = 1;
TREE_USED (to) = TREE_USED (decl); TREE_USED (to) = TREE_USED (decl);
TREE_READONLY (to) = 1; TREE_READONLY (to) = 1;
DECL_IGNORED_P (to) = 1; DECL_IGNORED_P (to) = 1;
DECL_CONTEXT (to) = DECL_CONTEXT (decl); DECL_CONTEXT (to) = DECL_CONTEXT (decl);
DECL_SECTION_NAME (to) = DECL_SECTION_NAME (decl);
DECL_WEAK (to) = DECL_WEAK (decl); DECL_WEAK (to) = DECL_WEAK (decl);
if (DECL_ONE_ONLY (decl)) if (DECL_ONE_ONLY (decl))
{ {
@ -348,14 +380,18 @@ emutls_decl (tree decl)
h->to = to; h->to = to;
*(struct tree_map **) loc = h; *(struct tree_map **) loc = h;
DECL_TLS_MODEL (to) = TLS_MODEL_EMULATED;
DECL_ARTIFICIAL (to) = 1; DECL_ARTIFICIAL (to) = 1;
DECL_IGNORED_P (to) = 1; DECL_IGNORED_P (to) = 1;
TREE_READONLY (to) = 0; TREE_READONLY (to) = 0;
SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to)); SET_DECL_ASSEMBLER_NAME (to, DECL_NAME (to));
if (DECL_ONE_ONLY (decl)) if (DECL_ONE_ONLY (decl))
make_decl_one_only (to); make_decl_one_only (to);
DECL_CONTEXT (to) = DECL_CONTEXT (decl); 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 /* Note that these fields may need to be updated from time to time from
@ -412,6 +448,8 @@ emutls_common_1 (void **loc, void *xstmts)
void void
emutls_finish (void) emutls_finish (void)
{
if (!targetm.emutls.register_common)
{ {
tree body = NULL_TREE; tree body = NULL_TREE;
@ -424,6 +462,7 @@ emutls_finish (void)
cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY); cgraph_build_static_cdtor ('I', body, DEFAULT_INIT_PRIORITY);
} }
}
/* Helper routines for maintaining section_htab. */ /* Helper routines for maintaining section_htab. */
@ -1125,7 +1164,12 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
{ {
if (DECL_THREAD_LOCAL_P (decl)) if (DECL_THREAD_LOCAL_P (decl))
return tls_comm_section; 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; return comm_section;
} }
@ -1950,6 +1994,40 @@ assemble_variable_contents (tree decl, const char *name,
} }
} }
/* 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. /* Assemble everything that is needed for a variable or function declaration.
Not used for automatic variables, and not used for function definitions. Not used for automatic variables, and not used for function definitions.
Should not be called for variables of incomplete structure type. Should not be called for variables of incomplete structure type.
@ -1984,32 +2062,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
|| (DECL_INITIAL (decl) || (DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node))) && DECL_INITIAL (decl) != error_mark_node)))
{ {
VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, 4); DECL_INITIAL (to) = targetm.emutls.var_init
constructor_elt *elt; (to, decl, get_emutls_init_templ_addr (decl));
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);
/* Make sure the template is marked as needed early enough. /* Make sure the template is marked as needed early enough.
Without this, if the variable is placed in a Without this, if the variable is placed in a
@ -5786,11 +5840,24 @@ categorize_decl_for_section (const_tree decl, int reloc)
ret = SECCAT_RODATA; ret = SECCAT_RODATA;
/* There are no read-only thread-local sections. */ /* 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 /* Note that this would be *just* SECCAT_BSS, except that there's
no concept of a read-only thread-local-data section. */ no concept of a read-only thread-local-data section. */
if (ret == SECCAT_BSS else if (ret == SECCAT_BSS
|| (flag_zero_initialized_in_bss || (flag_zero_initialized_in_bss
&& initializer_zerop (DECL_INITIAL (decl)))) && initializer_zerop (DECL_INITIAL (decl))))
ret = SECCAT_TBSS; ret = SECCAT_TBSS;
@ -5884,6 +5951,12 @@ default_elf_select_section (tree decl, int reloc,
case SECCAT_TBSS: case SECCAT_TBSS:
sname = ".tbss"; sname = ".tbss";
break; break;
case SECCAT_EMUTLS_VAR:
sname = targetm.emutls.var_section;
break;
case SECCAT_EMUTLS_TMPL:
sname = targetm.emutls.tmpl_section;
break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
@ -5901,69 +5974,73 @@ default_unique_section (tree decl, int reloc)
{ {
/* We only need to use .gnu.linkonce if we don't have COMDAT groups. */ /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */
bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP; bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP;
const char *prefix, *name; const char *prefix, *name, *linkonce;
size_t nlen, plen;
char *string; char *string;
switch (categorize_decl_for_section (decl, reloc)) switch (categorize_decl_for_section (decl, reloc))
{ {
case SECCAT_TEXT: case SECCAT_TEXT:
prefix = one_only ? ".gnu.linkonce.t." : ".text."; prefix = one_only ? ".t" : ".text";
break; break;
case SECCAT_RODATA: case SECCAT_RODATA:
case SECCAT_RODATA_MERGE_STR: case SECCAT_RODATA_MERGE_STR:
case SECCAT_RODATA_MERGE_STR_INIT: case SECCAT_RODATA_MERGE_STR_INIT:
case SECCAT_RODATA_MERGE_CONST: case SECCAT_RODATA_MERGE_CONST:
prefix = one_only ? ".gnu.linkonce.r." : ".rodata."; prefix = one_only ? ".r" : ".rodata";
break; break;
case SECCAT_SRODATA: case SECCAT_SRODATA:
prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2."; prefix = one_only ? ".s2" : ".sdata2";
break; break;
case SECCAT_DATA: case SECCAT_DATA:
prefix = one_only ? ".gnu.linkonce.d." : ".data."; prefix = one_only ? ".d" : ".data";
break; break;
case SECCAT_DATA_REL: case SECCAT_DATA_REL:
prefix = one_only ? ".gnu.linkonce.d.rel." : ".data.rel."; prefix = one_only ? ".d.rel" : ".data.rel";
break; break;
case SECCAT_DATA_REL_LOCAL: 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; break;
case SECCAT_DATA_REL_RO: 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; break;
case SECCAT_DATA_REL_RO_LOCAL: case SECCAT_DATA_REL_RO_LOCAL:
prefix = one_only ? ".gnu.linkonce.d.rel.ro.local." prefix = one_only ? ".d.rel.ro.local" : ".data.rel.ro.local";
: ".data.rel.ro.local.";
break; break;
case SECCAT_SDATA: case SECCAT_SDATA:
prefix = one_only ? ".gnu.linkonce.s." : ".sdata."; prefix = one_only ? ".s" : ".sdata";
break; break;
case SECCAT_BSS: case SECCAT_BSS:
prefix = one_only ? ".gnu.linkonce.b." : ".bss."; prefix = one_only ? ".b" : ".bss";
break; break;
case SECCAT_SBSS: case SECCAT_SBSS:
prefix = one_only ? ".gnu.linkonce.sb." : ".sbss."; prefix = one_only ? ".sb" : ".sbss";
break; break;
case SECCAT_TDATA: case SECCAT_TDATA:
prefix = one_only ? ".gnu.linkonce.td." : ".tdata."; prefix = one_only ? ".td" : ".tdata";
break; break;
case SECCAT_TBSS: 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; break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
plen = strlen (prefix);
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
name = targetm.strip_name_encoding (name); name = targetm.strip_name_encoding (name);
nlen = strlen (name);
string = alloca (nlen + plen + 1); /* If we're using one_only, then there needs to be a .gnu.linkonce
memcpy (string, prefix, plen); prefix to the section name. */
memcpy (string + plen, name, nlen + 1); linkonce = one_only ? ".gnu.linkonce" : "";
DECL_SECTION_NAME (decl) = build_string (nlen + plen, string); string = ACONCAT ((linkonce, prefix, ".", name, NULL));
DECL_SECTION_NAME (decl) = build_string (strlen (string), string);
} }
/* Like compute_reloc_for_constant, except for an RTX. The return value /* Like compute_reloc_for_constant, except for an RTX. The return value