extern section *get_cdtor_priority_section (int, bool);
extern bool unlikely_text_section_p (section *);
-extern void switch_to_section (section *);
+extern void switch_to_section (section *, tree = nullptr);
extern void output_section_asm_op (const void *);
extern void record_tm_clone_pair (tree, tree);
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2" } */
+
+struct dtv_slotinfo_list
+{
+ struct dtv_slotinfo_list *next;
+};
+
+extern struct dtv_slotinfo_list *list;
+
+static int __attribute__ ((section ("__libc_freeres_fn")))
+free_slotinfo (struct dtv_slotinfo_list **elemp)
+{
+ if (!free_slotinfo (&(*elemp)->next))
+ return 0;
+ return 1;
+}
+
+__attribute__ ((used, section ("__libc_freeres_fn")))
+static void free_mem (void)
+{
+ free_slotinfo (&list);
+}
+
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2" } */
+
+struct dtv_slotinfo_list
+{
+ struct dtv_slotinfo_list *next;
+};
+
+extern struct dtv_slotinfo_list *list;
+
+static int __attribute__ ((used, section ("__libc_freeres_fn")))
+free_slotinfo (struct dtv_slotinfo_list **elemp)
+{
+ if (!free_slotinfo (&(*elemp)->next))
+ return 0;
+ return 1;
+}
+
+__attribute__ ((section ("__libc_freeres_fn")))
+void free_mem (void)
+{
+ free_slotinfo (&list);
+}
+
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2" } */
+
+int __attribute__((used,section(".data.foo"))) foo2 = 2;
+int __attribute__((section(".data.foo"))) foo1 = 1;
+
+/* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2" } */
+
+int __attribute__((section(".data.foo"))) foo1 = 1;
+int __attribute__((used,section(".data.foo"))) foo2 = 2;
+
+/* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2" } */
+
+struct dtv_slotinfo_list
+{
+ struct dtv_slotinfo_list *next;
+};
+
+extern struct dtv_slotinfo_list *list;
+
+static int __attribute__ ((used, section ("__libc_freeres_fn")))
+free_slotinfo (struct dtv_slotinfo_list **elemp)
+{
+ if (!free_slotinfo (&(*elemp)->next))
+ return 0;
+ return 1;
+}
+
+__attribute__ ((section ("__libc_freeres_fn")))
+static void free_mem (void)
+/* { dg-warning "defined but not used" "" { target *-*-* } .-1 } */
+{
+ free_slotinfo (&list);
+}
+
+/* { dg-final { scan-assembler-not "__libc_freeres_fn\n" } } */
+/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
+/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
/* Return the named section structure associated with NAME. Create
a new section with the given fields if no such structure exists.
- When NOT_EXISTING, then fail if the section already exists. */
+ When NOT_EXISTING, then fail if the section already exists. Return
+ the existing section if the SECTION_RETAIN bit doesn't match. Set
+ the SECTION_WRITE | SECTION_RELRO bits on the the existing section
+ if one of the section flags is SECTION_WRITE | SECTION_RELRO and the
+ other has none of these flags in named sections and either the section
+ hasn't been declared yet or has been declared as writable. */
section *
get_section (const char *name, unsigned int flags, tree decl,
sect->common.flags |= (SECTION_WRITE | SECTION_RELRO);
return sect;
}
+ /* If the SECTION_RETAIN bit doesn't match, return and switch
+ to a new section later. */
+ if ((sect->common.flags & SECTION_RETAIN)
+ != (flags & SECTION_RETAIN))
+ return sect;
/* Sanity check user variables for flag changes. */
if (sect->named.decl != NULL
&& DECL_P (sect->named.decl)
/* Switch to the correct text section for the start of the function. */
- switch_to_section (function_section (decl));
+ switch_to_section (function_section (decl), decl);
if (crtl->has_bb_partition && !hot_label_written)
ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label);
&& (strcmp (sect->named.name, ".vtable_map_vars") == 0))
handle_vtv_comdat_section (sect, decl);
else
- switch_to_section (sect);
+ switch_to_section (sect, decl);
if (align > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
assemble_variable_contents (decl, name, dont_output_data,
the current section is NEW_SECTION. */
void
-switch_to_section (section *new_section)
+switch_to_section (section *new_section, tree decl)
{
if (in_section == new_section)
- return;
+ {
+ 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. */
+ if (DECL_PRESERVE_P (decl))
+ new_section->common.flags |= SECTION_RETAIN;
+ else
+ new_section->common.flags &= ~(SECTION_RETAIN
+ | SECTION_DECLARED);
+ }
+ else
+ return;
+ }
if (new_section->common.flags & SECTION_FORGET)
in_section = NULL;