From 6175383249143309fdc780a02bea484f4450def7 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 3 Dec 2020 11:01:06 -0800 Subject: [PATCH] Switch to a new section if the SECTION_RETAIN bit doesn't match When definitions marked with used attribute and unmarked definitions are placed in the section with the same name, switch to a new section if the SECTION_RETAIN bit doesn't match. gcc/ PR target/98146 * output.h (switch_to_section): Add a tree argument, default to nullptr. * varasm.c (get_section): If the SECTION_RETAIN bit doesn't match, return and switch to a new section later. (assemble_start_function): Pass decl to switch_to_section. (assemble_variable): Likewise. (switch_to_section): If the SECTION_RETAIN bit doesn't match, switch to a new section. gcc/testsuite/ PR target/98146 * c-c++-common/attr-used-5.c: New test. * c-c++-common/attr-used-6.c: Likewise. * c-c++-common/attr-used-7.c: Likewise. * c-c++-common/attr-used-8.c: Likewise. * c-c++-common/attr-used-9.c: Likewise. --- gcc/output.h | 2 +- gcc/testsuite/c-c++-common/attr-used-5.c | 26 ++++++++++++++++ gcc/testsuite/c-c++-common/attr-used-6.c | 26 ++++++++++++++++ gcc/testsuite/c-c++-common/attr-used-7.c | 8 +++++ gcc/testsuite/c-c++-common/attr-used-8.c | 8 +++++ gcc/testsuite/c-c++-common/attr-used-9.c | 28 +++++++++++++++++ gcc/varasm.c | 38 ++++++++++++++++++++---- 7 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/attr-used-5.c create mode 100644 gcc/testsuite/c-c++-common/attr-used-6.c create mode 100644 gcc/testsuite/c-c++-common/attr-used-7.c create mode 100644 gcc/testsuite/c-c++-common/attr-used-8.c create mode 100644 gcc/testsuite/c-c++-common/attr-used-9.c diff --git a/gcc/output.h b/gcc/output.h index fa8ace1f394..1f9af46da1d 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -548,7 +548,7 @@ extern void switch_to_other_text_partition (void); 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); diff --git a/gcc/testsuite/c-c++-common/attr-used-5.c b/gcc/testsuite/c-c++-common/attr-used-5.c new file mode 100644 index 00000000000..9fc0d3834e9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-used-5.c @@ -0,0 +1,26 @@ +/* { 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 } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-6.c b/gcc/testsuite/c-c++-common/attr-used-6.c new file mode 100644 index 00000000000..0cb82ade5a9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-used-6.c @@ -0,0 +1,26 @@ +/* { 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 } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-7.c b/gcc/testsuite/c-c++-common/attr-used-7.c new file mode 100644 index 00000000000..fba2706ffc1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-used-7.c @@ -0,0 +1,8 @@ +/* { 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 } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-8.c b/gcc/testsuite/c-c++-common/attr-used-8.c new file mode 100644 index 00000000000..4da4aabe573 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-used-8.c @@ -0,0 +1,8 @@ +/* { 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 } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-9.c b/gcc/testsuite/c-c++-common/attr-used-9.c new file mode 100644 index 00000000000..cf3bde67622 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-used-9.c @@ -0,0 +1,28 @@ +/* { 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 } } } */ diff --git a/gcc/varasm.c b/gcc/varasm.c index c5487a78b13..cfec870e067 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -281,7 +281,12 @@ get_noswitch_section (unsigned int flags, noswitch_section_callback callback) /* 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, @@ -343,6 +348,11 @@ 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) @@ -1879,7 +1889,7 @@ assemble_start_function (tree decl, const char *fnname) /* 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); @@ -2375,7 +2385,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, && (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, @@ -7742,10 +7752,28 @@ output_section_asm_op (const void *directive) 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; -- 2.30.2