Add retain attribute to place symbols in SHF_GNU_RETAIN section
When building Linux kernel, ld in bninutils 2.36 with GCC 11 generates thousands of ld: warning: orphan section `.data.event_initcall_finish' from `init/main.o' being placed in section `.data.event_initcall_finish' ld: warning: orphan section `.data.event_initcall_start' from `init/main.o' being placed in section `.data.event_initcall_start' ld: warning: orphan section `.data.event_initcall_level' from `init/main.o' being placed in section `.data.event_initcall_level' Since these sections are marked with SHF_GNU_RETAIN, they are placed in separate sections. They become orphan sections since they aren't expected in the Linux kernel linker script. But orphan sections normally don't work well with the Linux kernel linker script and the resulting kernel crashed. Add the "retain" attribute to place symbols in separate SHF_GNU_RETAIN sections. Issue a warning if the configured assembler/linker doesn't support SHF_GNU_RETAIN. gcc/ PR target/99113 * varasm.c (get_section): Replace SUPPORTS_SHF_GNU_RETAIN with looking up the retain attribute. (resolve_unique_section): Likewise. (get_variable_section): Likewise. (switch_to_section): Likewise. Warn when a symbol without the retain attribute and a symbol with the retain attribute are placed in the section with the same name, instead of the used attribute. * doc/extend.texi: Document the "retain" attribute. gcc/c-family/ PR target/99113 * c-attribs.c (c_common_attribute_table): Add the "retain" attribute. (handle_retain_attribute): New function. gcc/testsuite/ PR target/99113 * c-c++-common/attr-retain-1.c: New test. * c-c++-common/attr-retain-2.c: Likewise. * c-c++-common/attr-retain-3.c: Likewise. * c-c++-common/attr-retain-4.c: Likewise. * c-c++-common/attr-retain-5.c: Likewise. * c-c++-common/attr-retain-6.c: Likewise. * c-c++-common/attr-retain-7.c: Likewise. * c-c++-common/attr-retain-8.c: Likewise. * c-c++-common/attr-retain-9.c: Likewise. * c-c++-common/pr99113.c: Likewise. * gcc.c-torture/compile/attr-retain-1.c: Likewise. * gcc.c-torture/compile/attr-retain-2.c: Likewise. * c-c++-common/attr-used.c: Don't expect SHF_GNU_RETAIN section. * c-c++-common/attr-used-2.c: Likewise. * c-c++-common/attr-used-3.c: Likewise. * c-c++-common/attr-used-4.c: Likewise. * c-c++-common/attr-used-9.c: Likewise. * gcc.c-torture/compile/attr-used-retain-1.c: Likewise. * gcc.c-torture/compile/attr-used-retain-2.c: Likewise. * c-c++-common/attr-used-5.c: Don't expect warning for the used attribute nor SHF_GNU_RETAIN section. * c-c++-common/attr-used-6.c: Likewise. * c-c++-common/attr-used-7.c: Likewise. * c-c++-common/attr-used-8.c: Likewise.
This commit is contained in:
parent
1f9db6929d
commit
6347f4a090
@ -163,6 +163,7 @@ static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_objc_nullability_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_signed_bool_precision_attribute (tree *, tree, tree, int,
|
||||
bool *);
|
||||
static tree handle_retain_attribute (tree *, tree, tree, int, bool *);
|
||||
|
||||
/* Helper to define attribute exclusions. */
|
||||
#define ATTR_EXCL(name, function, type, variable) \
|
||||
@ -328,6 +329,8 @@ const struct attribute_spec c_common_attribute_table[] =
|
||||
handle_used_attribute, NULL },
|
||||
{ "unused", 0, 0, false, false, false, false,
|
||||
handle_unused_attribute, NULL },
|
||||
{ "retain", 0, 0, true, false, false, false,
|
||||
handle_retain_attribute, NULL },
|
||||
{ "externally_visible", 0, 0, true, false, false, false,
|
||||
handle_externally_visible_attribute, NULL },
|
||||
{ "no_reorder", 0, 0, true, false, false, false,
|
||||
@ -1564,6 +1567,28 @@ handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args),
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Handle a "retain" attribute; arguments as in
|
||||
struct attribute_spec.handler. */
|
||||
|
||||
static tree
|
||||
handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
|
||||
int ARG_UNUSED (flags), bool *no_add_attrs)
|
||||
{
|
||||
tree node = *pnode;
|
||||
|
||||
if (SUPPORTS_SHF_GNU_RETAIN
|
||||
&& (TREE_CODE (node) == FUNCTION_DECL
|
||||
|| (VAR_P (node) && TREE_STATIC (node))))
|
||||
;
|
||||
else
|
||||
{
|
||||
warning (OPT_Wattributes, "%qE attribute ignored", name);
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Handle a "externally_visible" attribute; arguments as in
|
||||
struct attribute_spec.handler. */
|
||||
|
||||
|
@ -3913,8 +3913,10 @@ When applied to a member function of a C++ class template, the
|
||||
attribute also means that the function is instantiated if the
|
||||
class itself is instantiated.
|
||||
|
||||
@item retain
|
||||
@cindex @code{retain} function attribute
|
||||
For ELF targets that support the GNU or FreeBSD OSABIs, this attribute
|
||||
will also save the function from linker garbage collection. To support
|
||||
will save the function from linker garbage collection. To support
|
||||
this behavior, functions that have not been placed in specific sections
|
||||
(e.g. by the @code{section} attribute, or the @code{-ffunction-sections}
|
||||
option), will be placed in new, unique sections.
|
||||
@ -7504,8 +7506,10 @@ When applied to a static data member of a C++ class template, the
|
||||
attribute also means that the member is instantiated if the
|
||||
class itself is instantiated.
|
||||
|
||||
@item retain
|
||||
@cindex @code{retain} variable attribute
|
||||
For ELF targets that support the GNU or FreeBSD OSABIs, this attribute
|
||||
will also save the variable from linker garbage collection. To support
|
||||
will save the variable from linker garbage collection. To support
|
||||
this behavior, variables that have not been placed in specific sections
|
||||
(e.g. by the @code{section} attribute, or the @code{-fdata-sections} option),
|
||||
will be placed in new, unique sections.
|
||||
|
16
gcc/testsuite/c-c++-common/attr-retain-1.c
Normal file
16
gcc/testsuite/c-c++-common/attr-retain-1.c
Normal file
@ -0,0 +1,16 @@
|
||||
/* { dg-do compile { target R_flag_in_section } } */
|
||||
/* { dg-options "-O3" } */
|
||||
|
||||
static void function_declaration_before(void)
|
||||
__attribute__((__used__, __retain__));
|
||||
|
||||
static void function_declaration_before(void) {}
|
||||
|
||||
static void function_declaration_after(void) {}
|
||||
|
||||
static void function_declaration_after(void)
|
||||
__attribute__((__used__, __retain__));
|
||||
|
||||
/* { dg-final { scan-assembler "function_declaration_before" } } */
|
||||
/* { dg-final { scan-assembler "function_declaration_after" } } */
|
||||
/* { dg-final { scan-assembler "\.text.*,\"axR\"" { target R_flag_in_section } } } */
|
12
gcc/testsuite/c-c++-common/attr-retain-2.c
Normal file
12
gcc/testsuite/c-c++-common/attr-retain-2.c
Normal file
@ -0,0 +1,12 @@
|
||||
/* { dg-do compile { target R_flag_in_section } } */
|
||||
/* { dg-options "-Wall -O2" } */
|
||||
|
||||
static int xyzzy __attribute__((__used__, __retain__)) = 1;
|
||||
|
||||
void foo()
|
||||
{
|
||||
int x __attribute__((__retain__)); /* { dg-warning "attribute ignored|unused variable" } */
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler "xyzzy" } } */
|
||||
/* { dg-final { scan-assembler "\.data.*,\"awR\"" { target R_flag_in_section } } } */
|
7
gcc/testsuite/c-c++-common/attr-retain-3.c
Normal file
7
gcc/testsuite/c-c++-common/attr-retain-3.c
Normal file
@ -0,0 +1,7 @@
|
||||
/* { dg-do compile { target R_flag_in_section } } */
|
||||
/* { dg-options "-Wall -O2 -fcommon" } */
|
||||
|
||||
static int xyzzy __attribute__((__used__, __retain__));
|
||||
|
||||
/* { dg-final { scan-assembler "xyzzy" } } */
|
||||
/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
|
7
gcc/testsuite/c-c++-common/attr-retain-4.c
Normal file
7
gcc/testsuite/c-c++-common/attr-retain-4.c
Normal file
@ -0,0 +1,7 @@
|
||||
/* { dg-do compile { target R_flag_in_section } } */
|
||||
/* { dg-options "-Wall -O2 -fcommon" } */
|
||||
|
||||
int xyzzy __attribute__((__used__, __retain__));
|
||||
|
||||
/* { dg-final { scan-assembler "xyzzy" } } */
|
||||
/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
|
28
gcc/testsuite/c-c++-common/attr-retain-5.c
Normal file
28
gcc/testsuite/c-c++-common/attr-retain-5.c
Normal file
@ -0,0 +1,28 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
|
||||
/* { 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)
|
||||
/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
|
||||
{
|
||||
if (!free_slotinfo (&(*elemp)->next))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__attribute__ ((used, retain, 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 } } } */
|
28
gcc/testsuite/c-c++-common/attr-retain-6.c
Normal file
28
gcc/testsuite/c-c++-common/attr-retain-6.c
Normal file
@ -0,0 +1,28 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
|
||||
/* { dg-options "-Wall -O2" } */
|
||||
|
||||
struct dtv_slotinfo_list
|
||||
{
|
||||
struct dtv_slotinfo_list *next;
|
||||
};
|
||||
|
||||
extern struct dtv_slotinfo_list *list;
|
||||
|
||||
static int __attribute__ ((used, retain, 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)
|
||||
/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
|
||||
{
|
||||
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 } } } */
|
10
gcc/testsuite/c-c++-common/attr-retain-7.c
Normal file
10
gcc/testsuite/c-c++-common/attr-retain-7.c
Normal file
@ -0,0 +1,10 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
|
||||
/* { dg-options "-Wall -O2" } */
|
||||
|
||||
int __attribute__((used,retain,section(".data.foo"))) foo2 = 2;
|
||||
int __attribute__((section(".data.foo"))) foo1 = 1;
|
||||
/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-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 } } } */
|
10
gcc/testsuite/c-c++-common/attr-retain-8.c
Normal file
10
gcc/testsuite/c-c++-common/attr-retain-8.c
Normal file
@ -0,0 +1,10 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
|
||||
/* { dg-options "-Wall -O2" } */
|
||||
|
||||
int __attribute__((section(".data.foo"))) foo1 = 1;
|
||||
/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
|
||||
int __attribute__((used,retain,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 } } } */
|
29
gcc/testsuite/c-c++-common/attr-retain-9.c
Normal file
29
gcc/testsuite/c-c++-common/attr-retain-9.c
Normal file
@ -0,0 +1,29 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */
|
||||
/* { dg-options "-Wall -O2" } */
|
||||
|
||||
struct dtv_slotinfo_list
|
||||
{
|
||||
struct dtv_slotinfo_list *next;
|
||||
};
|
||||
|
||||
extern struct dtv_slotinfo_list *list;
|
||||
|
||||
static int __attribute__ ((used, retain, 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 } } } */
|
@ -9,4 +9,4 @@ void foo()
|
||||
}
|
||||
|
||||
/* { dg-final { scan-assembler "xyzzy" } } */
|
||||
/* { dg-final { scan-assembler "\.data.*,\"awR\"" { target R_flag_in_section } } } */
|
||||
/* { dg-final { scan-assembler-not "\.data.*,\"awR\"" { target R_flag_in_section } } } */
|
||||
|
@ -4,4 +4,4 @@
|
||||
static int xyzzy __attribute__((__used__));
|
||||
|
||||
/* { dg-final { scan-assembler "xyzzy" } } */
|
||||
/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
|
||||
/* { dg-final { scan-assembler-not ",\"awR\"" { target R_flag_in_section } } } */
|
||||
|
@ -4,4 +4,4 @@
|
||||
int xyzzy __attribute__((__used__));
|
||||
|
||||
/* { dg-final { scan-assembler "xyzzy" } } */
|
||||
/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */
|
||||
/* { dg-final { scan-assembler-not ",\"awR\"" { target R_flag_in_section } } } */
|
||||
|
@ -11,7 +11,6 @@ extern struct dtv_slotinfo_list *list;
|
||||
|
||||
static int __attribute__ ((section ("__libc_freeres_fn")))
|
||||
free_slotinfo (struct dtv_slotinfo_list **elemp)
|
||||
/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
|
||||
{
|
||||
if (!free_slotinfo (&(*elemp)->next))
|
||||
return 0;
|
||||
@ -25,4 +24,4 @@ static void free_mem (void)
|
||||
}
|
||||
|
||||
/* { 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 } } } */
|
||||
/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
|
||||
|
@ -19,10 +19,9 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
|
||||
|
||||
__attribute__ ((section ("__libc_freeres_fn")))
|
||||
void free_mem (void)
|
||||
/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */
|
||||
{
|
||||
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 } } } */
|
||||
/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
int __attribute__((used,section(".data.foo"))) foo2 = 2;
|
||||
int __attribute__((section(".data.foo"))) foo1 = 1;
|
||||
/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-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 } } } */
|
||||
/* { dg-final { scan-assembler-not ".data.foo,\"awR\"" { target R_flag_in_section } } } */
|
||||
|
@ -3,8 +3,7 @@
|
||||
/* { dg-options "-Wall -O2" } */
|
||||
|
||||
int __attribute__((section(".data.foo"))) foo1 = 1;
|
||||
/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-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 } } } */
|
||||
/* { dg-final { scan-assembler-not ".data.foo,\"awR\"" { target R_flag_in_section } } } */
|
||||
|
@ -25,5 +25,5 @@ static void free_mem (void)
|
||||
}
|
||||
|
||||
/* { 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 } } } */
|
||||
/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */
|
||||
/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */
|
||||
|
@ -11,4 +11,4 @@ static void function_declaration_after(void) __attribute__((__used__));
|
||||
|
||||
/* { dg-final { scan-assembler "function_declaration_before" } } */
|
||||
/* { dg-final { scan-assembler "function_declaration_after" } } */
|
||||
/* { dg-final { scan-assembler "\.text.*,\"axR\"" { target R_flag_in_section } } } */
|
||||
/* { dg-final { scan-assembler-not "\.text.*,\"axR\"" { target R_flag_in_section } } } */
|
||||
|
7
gcc/testsuite/c-c++-common/pr99113.c
Normal file
7
gcc/testsuite/c-c++-common/pr99113.c
Normal file
@ -0,0 +1,7 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-Wall -O2" } */
|
||||
|
||||
static int xyzzy __attribute__((__used__)) = 1;
|
||||
|
||||
/* { dg-final { scan-assembler "xyzzy" } } */
|
||||
/* { dg-final { scan-assembler-not "\.data.*,\"awR\"" { target R_flag_in_section } } } */
|
34
gcc/testsuite/gcc.c-torture/compile/attr-retain-1.c
Normal file
34
gcc/testsuite/gcc.c-torture/compile/attr-retain-1.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* { dg-do compile { target R_flag_in_section } } */
|
||||
/* { dg-final { scan-assembler ".text.*,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler ".bss.*,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".data.*,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".rodata.*,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */
|
||||
|
||||
void __attribute__((used,retain)) used_fn (void) { }
|
||||
void unused_fn (void) { }
|
||||
void __attribute__((hot,used,retain)) used_hot_fn (void) { }
|
||||
void __attribute__((hot)) unused_hot_fn (void) { }
|
||||
void __attribute__((cold,used,retain)) used_cold_fn (void) { }
|
||||
void __attribute__((cold)) unused_cold_fn (void) { }
|
||||
int __attribute__((used,retain)) used_bss = 0;
|
||||
int __attribute__((used,retain)) used_data = 1;
|
||||
const int __attribute__((used,retain)) used_rodata = 2;
|
||||
int __attribute__((used,retain)) used_comm;
|
||||
static int __attribute__((used,retain)) used_lcomm;
|
||||
|
||||
int unused_bss = 0;
|
||||
int unused_data = 1;
|
||||
const int unused_rodata = 2;
|
||||
int unused_comm;
|
||||
static int unused_lcomm;
|
||||
|
||||
/* Test switching back to the used,retained sections. */
|
||||
void __attribute__((used,retain)) used_fn2 (void) { }
|
||||
int __attribute__((used,retain)) used_bss2 = 0;
|
||||
int __attribute__((used,retain)) used_data2 = 1;
|
||||
const int __attribute__((used,retain)) used_rodata2 = 2;
|
||||
int __attribute__((used,retain)) used_comm2;
|
||||
static int __attribute__((used,retain)) used_lcomm2;
|
||||
|
||||
int __attribute__((used,retain,section(".data.used_foo_sec"))) used_foo = 2;
|
15
gcc/testsuite/gcc.c-torture/compile/attr-retain-2.c
Normal file
15
gcc/testsuite/gcc.c-torture/compile/attr-retain-2.c
Normal file
@ -0,0 +1,15 @@
|
||||
/* { dg-do compile { target R_flag_in_section } } */
|
||||
/* { dg-final { scan-assembler ".text.used_fn,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler ".text.used_fn2,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler ".bss.used_bss,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".bss.used_bss2,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".data.used_data,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".data.used_data2,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".rodata.used_rodata,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler ".rodata.used_rodata2,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */
|
||||
/* { dg-final { scan-assembler ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */
|
||||
/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */
|
||||
/* { dg-options "-ffunction-sections -fdata-sections" } */
|
||||
|
||||
#include "attr-retain-1.c"
|
@ -1,10 +1,10 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-require-effective-target R_flag_in_section } */
|
||||
/* { dg-final { scan-assembler ".text.*,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler ".bss.*,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".data.*,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".rodata.*,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".text.*,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".bss.*,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".data.*,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".rodata.*,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".data.used_foo_sec,\"awR\"" } } */
|
||||
|
||||
void __attribute__((used)) used_fn (void) { }
|
||||
void unused_fn (void) { }
|
||||
|
@ -1,16 +1,16 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-require-effective-target R_flag_in_section } */
|
||||
/* { dg-final { scan-assembler ".text.used_fn,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler ".text.used_fn2,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler ".bss.used_bss,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".bss.used_bss2,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".data.used_data,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".data.used_data2,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler ".rodata.used_rodata,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler ".rodata.used_rodata2,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */
|
||||
/* { dg-final { scan-assembler ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */
|
||||
/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".text.used_fn,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".text.used_fn2,\"axR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".bss.used_bss,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".bss.used_bss2,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".data.used_data,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".data.used_data2,\"awR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".rodata.used_rodata,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".rodata.used_rodata2,\"aR\"" } } */
|
||||
/* { dg-final { scan-assembler-not ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */
|
||||
/* { dg-final { scan-assembler-not ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */
|
||||
/* { dg-final { scan-assembler-not ".data.used_foo_sec,\"awR\"" } } */
|
||||
/* { dg-options "-ffunction-sections -fdata-sections" } */
|
||||
|
||||
#include "attr-used-retain-1.c"
|
||||
|
22
gcc/varasm.c
22
gcc/varasm.c
@ -297,10 +297,9 @@ get_section (const char *name, unsigned int flags, tree decl,
|
||||
slot = section_htab->find_slot_with_hash (name, htab_hash_string (name),
|
||||
INSERT);
|
||||
flags |= SECTION_NAMED;
|
||||
if (SUPPORTS_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)
|
||||
{
|
||||
@ -487,7 +486,7 @@ resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,
|
||||
if (DECL_SECTION_NAME (decl) == NULL
|
||||
&& targetm_common.have_named_sections
|
||||
&& (flag_function_or_data_sections
|
||||
|| (SUPPORTS_SHF_GNU_RETAIN && DECL_PRESERVE_P (decl))
|
||||
|| lookup_attribute ("retain", DECL_ATTRIBUTES (decl))
|
||||
|| DECL_COMDAT_GROUP (decl)))
|
||||
{
|
||||
targetm.asm_out.unique_section (decl, reloc);
|
||||
@ -1227,7 +1226,7 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
|
||||
vnode->get_constructor ();
|
||||
|
||||
if (DECL_COMMON (decl)
|
||||
&& !(SUPPORTS_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
|
||||
@ -7761,18 +7760,19 @@ switch_to_section (section *new_section, tree decl)
|
||||
{
|
||||
if (in_section == new_section)
|
||||
{
|
||||
if (SUPPORTS_SHF_GNU_RETAIN
|
||||
&& (new_section->common.flags & SECTION_NAMED)
|
||||
bool retain_p;
|
||||
if ((new_section->common.flags & SECTION_NAMED)
|
||||
&& decl != nullptr
|
||||
&& DECL_P (decl)
|
||||
&& (!!DECL_PRESERVE_P (decl)
|
||||
&& ((retain_p = !!lookup_attribute ("retain",
|
||||
DECL_ATTRIBUTES (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 (DECL_PRESERVE_P (decl))
|
||||
if (retain_p)
|
||||
{
|
||||
new_section->common.flags |= SECTION_RETAIN;
|
||||
used_decl = decl;
|
||||
@ -7786,8 +7786,8 @@ switch_to_section (section *new_section, tree decl)
|
||||
no_used_decl = decl;
|
||||
}
|
||||
warning (OPT_Wattributes,
|
||||
"%+qD without %<used%> attribute and %qD with "
|
||||
"%<used%> attribute are placed in a section with "
|
||||
"%+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);
|
||||
|
Loading…
Reference in New Issue
Block a user