/* Output variables, constants and external declarations, for GNU compiler.
- Copyright (C) 1987-2020 Free Software Foundation, Inc.
+ Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GCC.
slot = section_htab->find_slot_with_hash (name, htab_hash_string (name),
INSERT);
flags |= SECTION_NAMED;
- if (HAVE_GAS_SHF_GNU_RETAIN
- && decl != nullptr
+ if (decl != nullptr
&& DECL_P (decl)
- && DECL_PRESERVE_P (decl))
+ && lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
flags |= SECTION_RETAIN;
if (*slot == NULL)
{
if (DECL_SECTION_NAME (decl) == NULL
&& targetm_common.have_named_sections
&& (flag_function_or_data_sections
- || (HAVE_GAS_SHF_GNU_RETAIN && DECL_PRESERVE_P (decl))
+ || lookup_attribute ("retain", DECL_ATTRIBUTES (decl))
|| DECL_COMDAT_GROUP (decl)))
{
targetm.asm_out.unique_section (decl, reloc);
/* For .gnu.linkonce.t.foo we want to use .gnu.linkonce.r.foo or
.gnu.linkonce.d.rel.ro.local.foo if the jump table is relocatable. */
else if (DECL_COMDAT_GROUP (decl)
- && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
+ && startswith (name, ".gnu.linkonce.t."))
{
size_t len;
char *rname;
}
/* For .text.foo we want to use .rodata.foo. */
else if (flag_function_sections && flag_data_sections
- && strncmp (name, ".text.", 6) == 0)
+ && startswith (name, ".text."))
{
size_t len = strlen (name) + 1;
char *rname = (char *) alloca (len + strlen (sname) - 5);
return align;
}
+/* Compute reloc for get_variable_section. The return value
+ is a mask for which bit 1 indicates a global relocation, and bit 0
+ indicates a local relocation. */
+
+int
+compute_reloc_for_var (tree decl)
+{
+ int reloc;
+
+ if (DECL_INITIAL (decl) == error_mark_node)
+ reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+ else if (DECL_INITIAL (decl))
+ reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
+ else
+ reloc = 0;
+
+ return reloc;
+}
+
/* Return the section into which the given VAR_DECL or CONST_DECL
should be placed. PREFER_NOSWITCH_P is true if a noswitch
section should be used wherever possible. */
vnode->get_constructor ();
if (DECL_COMMON (decl)
- && !(HAVE_GAS_SHF_GNU_RETAIN && DECL_PRESERVE_P (decl)))
+ && !lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
{
/* If the decl has been given an explicit section name, or it resides
in a non-generic address space, then it isn't common, and shouldn't
return comm_section;
}
- if (DECL_INITIAL (decl) == error_mark_node)
- reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
- else if (DECL_INITIAL (decl))
- reloc = compute_reloc_for_constant (DECL_INITIAL (decl));
- else
- reloc = 0;
+ reloc = compute_reloc_for_var (decl);
resolve_unique_section (decl, reloc, flag_data_sections);
if (IN_NAMED_SECTION (decl))
if (SECTION_STYLE (sect) == SECTION_NOSWITCH)
return NULL;
+ if (bool (lookup_attribute ("retain", DECL_ATTRIBUTES (decl)))
+ != bool (sect->common.flags & SECTION_RETAIN))
+ return NULL;
+
return get_block_for_section (sect);
}
{
struct symtab_node *snode;
+ /* Don't create object blocks if each DECL is placed into a separate
+ section because that will uselessly create a section anchor for
+ each DECL. */
+ if (flag_data_sections)
+ return false;
+
/* Only data DECLs can be placed into object blocks. */
if (!VAR_P (decl) && TREE_CODE (decl) != CONST_DECL)
return false;
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
/* Atomic or sync builtins which have survived this far will be
resolved externally and therefore are not incorporeal. */
- if (strncmp (name, "__builtin_", 10) == 0)
+ if (startswith (name, "__builtin_"))
return true;
}
return false;
if (desc->mark < 0)
{
#ifdef ASM_OUTPUT_DEF
- const char *name = targetm.strip_name_encoding (XSTR (desc->sym, 0));
+ const char *name = XSTR (desc->sym, 0);
char label[256];
char buffer[256 + 32];
const char *p;
ASM_GENERATE_INTERNAL_LABEL (label, "LC", ~desc->mark);
- p = targetm.strip_name_encoding (label);
+ p = label;
if (desc->offset)
{
sprintf (buffer, "%s+%ld", p, (long) (desc->offset));
&& (!TYPE_DOMAIN (TREE_TYPE (local->field))
|| !TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field)))))
{
- fieldsize = array_size_for_constructor (local->val);
+ unsigned HOST_WIDE_INT fldsize
+ = array_size_for_constructor (local->val);
+ fieldsize = int_size_in_bytes (TREE_TYPE (local->val));
+ /* In most cases fieldsize == fldsize as the size of the initializer
+ determines how many elements the flexible array member has. For
+ C++ fldsize can be smaller though, if the last or several last or
+ all initializers of the flexible array member have side-effects
+ and the FE splits them into dynamic initialization. */
+ gcc_checking_assert (fieldsize >= fldsize);
/* Given a non-empty initialization, this field had better
be last. Given a flexible array member, the next field
on the chain is a TYPE_DECL of the enclosing struct. */
const_tree next = DECL_CHAIN (local->field);
gcc_assert (!fieldsize || !next || TREE_CODE (next) != FIELD_DECL);
- tree size = TYPE_SIZE_UNIT (TREE_TYPE (local->val));
- gcc_checking_assert (compare_tree_int (size, fieldsize) == 0);
}
else
fieldsize = tree_to_uhwi (DECL_SIZE_UNIT (local->field));
void
declare_weak (tree decl)
{
- gcc_assert (TREE_CODE (decl) != FUNCTION_DECL || !TREE_ASM_WRITTEN (decl));
+ /* With -fsyntax-only, TREE_ASM_WRITTEN might be set on certain function
+ decls earlier than normally, but as with -fsyntax-only nothing is really
+ emitted, there is no harm in marking it weak later. */
+ gcc_assert (TREE_CODE (decl) != FUNCTION_DECL
+ || !TREE_ASM_WRITTEN (decl)
+ || flag_syntax_only);
if (! TREE_PUBLIC (decl))
{
error ("weak declaration of %q+D must be public", decl);
flags |= SECTION_TLS | SECTION_WRITE;
if (strcmp (name, ".bss") == 0
- || strncmp (name, ".bss.", 5) == 0
- || strncmp (name, ".gnu.linkonce.b.", 16) == 0
+ || startswith (name, ".bss.")
+ || startswith (name, ".gnu.linkonce.b.")
|| strcmp (name, ".persistent.bss") == 0
|| strcmp (name, ".sbss") == 0
- || strncmp (name, ".sbss.", 6) == 0
- || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
+ || startswith (name, ".sbss.")
+ || startswith (name, ".gnu.linkonce.sb."))
flags |= SECTION_BSS;
if (strcmp (name, ".tdata") == 0
- || strncmp (name, ".tdata.", 7) == 0
- || strncmp (name, ".gnu.linkonce.td.", 17) == 0)
+ || startswith (name, ".tdata.")
+ || startswith (name, ".gnu.linkonce.td."))
flags |= SECTION_TLS;
if (strcmp (name, ".tbss") == 0
- || strncmp (name, ".tbss.", 6) == 0
- || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+ || startswith (name, ".tbss.")
+ || startswith (name, ".gnu.linkonce.tb."))
flags |= SECTION_TLS | SECTION_BSS;
if (strcmp (name, ".noinit") == 0)
/* If we have already declared this section, we can use an
abbreviated form to switch back to it -- unless this section is
- part of a COMDAT groups or with SHF_GNU_RETAIN, in which case GAS
- requires the full declaration every time. */
+ part of a COMDAT groups or with SHF_GNU_RETAIN or with SHF_LINK_ORDER,
+ in which case GAS requires the full declaration every time. */
if (!(HAVE_COMDAT_GROUP && (flags & SECTION_LINKONCE))
- && !(flags & SECTION_RETAIN)
+ && !(flags & (SECTION_RETAIN | SECTION_LINK_ORDER))
&& (flags & SECTION_DECLARED))
{
fprintf (asm_out_file, "\t.section\t%s\n", name);
/* Like compute_reloc_for_constant, except for an RTX. The return value
is a mask for which bit 1 indicates a global relocation, and bit 0
- indicates a local relocation. */
+ indicates a local relocation. Used by default_select_rtx_section
+ and default_elf_select_rtx_section. */
static int
compute_reloc_for_rtx (const_rtx x)
void
switch_to_section (section *new_section, tree decl)
{
- if (in_section == new_section)
+ bool retain_p;
+ if ((new_section->common.flags & SECTION_NAMED)
+ && decl != nullptr
+ && DECL_P (decl)
+ && ((retain_p = !!lookup_attribute ("retain",
+ DECL_ATTRIBUTES (decl)))
+ != !!(new_section->common.flags & SECTION_RETAIN)))
{
- if (HAVE_GAS_SHF_GNU_RETAIN
- && (new_section->common.flags & SECTION_NAMED)
- && decl != nullptr
- && DECL_P (decl)
- && (!!DECL_PRESERVE_P (decl)
- != !!(new_section->common.flags & SECTION_RETAIN)))
+ /* If the SECTION_RETAIN bit doesn't match, switch to a new
+ section. */
+ tree used_decl, no_used_decl;
+
+ if (retain_p)
{
- /* If the SECTION_RETAIN bit doesn't match, switch to a new
- section. */
- if (DECL_PRESERVE_P (decl))
- new_section->common.flags |= SECTION_RETAIN;
- else
- new_section->common.flags &= ~(SECTION_RETAIN
- | SECTION_DECLARED);
+ new_section->common.flags |= SECTION_RETAIN;
+ used_decl = decl;
+ no_used_decl = new_section->named.decl;
}
else
- return;
+ {
+ new_section->common.flags &= ~(SECTION_RETAIN
+ | SECTION_DECLARED);
+ used_decl = new_section->named.decl;
+ no_used_decl = decl;
+ }
+ if (no_used_decl != used_decl)
+ {
+ warning (OPT_Wattributes,
+ "%+qD without %<retain%> attribute and %qD with "
+ "%<retain%> attribute are placed in a section with "
+ "the same name", no_used_decl, used_decl);
+ inform (DECL_SOURCE_LOCATION (used_decl),
+ "%qD was declared here", used_decl);
+ }
}
+ else if (in_section == new_section)
+ return;
if (new_section->common.flags & SECTION_FORGET)
in_section = NULL;
&& (strcmp (block->sect->named.name, ".vtable_map_vars") == 0))
handle_vtv_comdat_section (block->sect, block->sect->named.decl);
else
- switch_to_section (block->sect);
+ switch_to_section (block->sect, SYMBOL_REF_DECL ((*block->objects)[0]));
gcc_checking_assert (!(block->sect->common.flags & SECTION_MERGE));
assemble_align (block->alignment);