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:
parent
f509e29629
commit
feb60f0328
|
@ -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>
|
||||
|
||||
PR c/35652
|
||||
|
|
|
@ -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")
|
||||
|
||||
/* 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"
|
||||
|
|
|
@ -5476,6 +5476,13 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
|
|||
*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);
|
||||
}
|
||||
|
|
|
@ -2854,6 +2854,9 @@ x86_64_elf_select_section (tree decl, int reloc,
|
|||
/* 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)
|
||||
{
|
||||
|
@ -2890,16 +2893,16 @@ x86_64_elf_unique_section (tree decl, int reloc)
|
|||
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:
|
||||
|
@ -2911,23 +2914,28 @@ x86_64_elf_unique_section (tree decl, int reloc)
|
|||
/* 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#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,11 +57,87 @@ vxworks_asm_out_destructor (rtx symbol, int priority)
|
|||
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. */
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -50,6 +50,7 @@ through the macros defined in the @file{.h} file.
|
|||
* Floating Point:: Handling floating point for cross-compilers.
|
||||
* Mode Switching:: Insertion of mode-switching instructions.
|
||||
* Target Attributes:: Defining target-specific uses of @code{__attribute__}.
|
||||
* Emulated TLS:: Emulated TLS support.
|
||||
* MIPS Coprocessors:: MIPS coprocessor support and how to customize it.
|
||||
* PCH Target:: Validity checking for precompiled headers.
|
||||
* 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.
|
||||
@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
|
||||
@section Defining coprocessor specifics for MIPS targets.
|
||||
@cindex MIPS coprocessor-definition macros
|
||||
|
|
|
@ -9494,16 +9494,33 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
|
|||
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;
|
||||
|
@ -9514,11 +9531,11 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
|
|||
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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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, \
|
||||
|
|
28
gcc/target.h
28
gcc/target.h
|
@ -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 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
|
||||
the function, they should define this target hook and set their
|
||||
bits in the bitmap passed in. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
||||
PR testsuite/36053
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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" } */
|
|
@ -518,6 +518,13 @@ proc check_effective_target_tls {} {
|
|||
# This won't change for different subtargets so cache the result.
|
||||
|
||||
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 {
|
||||
__thread int i;
|
||||
int f (void) { return i; }
|
||||
|
|
|
@ -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
|
||||
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(())
|
||||
{
|
||||
|
|
289
gcc/varasm.c
289
gcc/varasm.c
|
@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "tm_p.h"
|
||||
#include "debug.h"
|
||||
#include "target.h"
|
||||
#include "targhooks.h"
|
||||
#include "tree-mudflap.h"
|
||||
#include "cgraph.h"
|
||||
#include "cfglayout.h"
|
||||
|
@ -194,30 +195,74 @@ static GTY(()) struct rtx_constant_pool *shared_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;
|
||||
/* 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
|
||||
# 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$"
|
||||
#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_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
|
||||
of the DECL_ASSEMBLY_NAME of the original object. */
|
||||
|
||||
static tree
|
||||
get_emutls_object_name (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));
|
||||
const char *prefix = (targetm.emutls.var_prefix
|
||||
? targetm.emutls.var_prefix
|
||||
: "__emutls_v" EMUTLS_SEPARATOR);
|
||||
return prefix_name (prefix, name);
|
||||
}
|
||||
|
||||
return get_identifier (toname);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
|
@ -226,36 +271,19 @@ get_emutls_object_name (tree name)
|
|||
static tree
|
||||
get_emutls_object_type (void)
|
||||
{
|
||||
tree type, type_name, field, next_field, word_type_node;
|
||||
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 = get_identifier ("__emutls_object");
|
||||
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;
|
||||
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
|
||||
TYPE_FIELDS (type) = field;
|
||||
layout_type (type);
|
||||
|
||||
|
@ -269,26 +297,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))
|
||||
{
|
||||
|
@ -348,14 +380,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
|
||||
|
@ -413,16 +449,19 @@ emutls_common_1 (void **loc, void *xstmts)
|
|||
void
|
||||
emutls_finish (void)
|
||||
{
|
||||
tree body = NULL_TREE;
|
||||
if (!targetm.emutls.register_common)
|
||||
{
|
||||
tree body = NULL_TREE;
|
||||
|
||||
if (emutls_htab == NULL)
|
||||
return;
|
||||
if (emutls_htab == NULL)
|
||||
return;
|
||||
|
||||
htab_traverse_noresize (emutls_htab, emutls_common_1, &body);
|
||||
if (body == NULL_TREE)
|
||||
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. */
|
||||
|
@ -1125,7 +1164,12 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
Not used for automatic variables, and not used for function definitions.
|
||||
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) != 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
|
||||
|
@ -5786,13 +5840,26 @@ categorize_decl_for_section (const_tree decl, int reloc)
|
|||
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;
|
||||
|
@ -5884,6 +5951,12 @@ default_elf_select_section (tree decl, int reloc,
|
|||
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 ();
|
||||
}
|
||||
|
@ -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. */
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue