From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by sourceware.org (Postfix) with ESMTPS id 36C3E3857801 for ; Tue, 15 Sep 2020 12:06:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 36C3E3857801 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=mittosystems.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=jozef.l@mittosystems.com Received: by mail-wr1-x42b.google.com with SMTP id z4so3048914wrr.4 for ; Tue, 15 Sep 2020 05:06:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mittosystems.com; s=google; h=date:from:to:subject:message-id:mime-version:content-disposition; bh=etA9Hi0NqTceiJijbUKPTcKL75p2fCr5TksDNklugdg=; b=PbXIbv7uJM0kqvfqt09OtWYOxBAuGH4eimfy26YFUEeyOw4Z59kqum6ru/8RPNJ4cU X1+2UJCh3u7z/bsv0irVqHuKwlfkWFHR6EOP8zPBHzoVAK0pPqg9cmK+kIui78jOWjhB jl9J2ZdRXuL2fzfQX9vwnjsjjx/26J/SkknN+Y6NQnqjs3mNebwkUVcOAX59naVvdq6F k4jPuaMXEnOKZDhCxcKH8RpWoGIao4zQURwxDhM2Mky/9R9H7bapjGzy3O6avVW1L2gj FL0YVJkfGMjusyhQjskX2O388s/2GDcz9Hem7EYkPn+fSDFCVAJKcOrE+GS5CXh9m0qz T/Zw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition; bh=etA9Hi0NqTceiJijbUKPTcKL75p2fCr5TksDNklugdg=; b=qkI/quDt/68AXSs7diddDQoRIzGik5ccWqOdMryDVGdE7jGHLctmOL2pKPQ3xX0LLg 5N/cljV+WKv+BPeN9HGODnqDe/FC/FCcpfD2gPcaco6GVIW7DModM00h8XE24C9jAJjV 6iLhpah5Wdz57ghZd6D1OcVmDNDW/yNpztQsJdUt/Jct120VoU9jFZAlYXx6H22MqQtN tKoGSvF7vK4KXl4aFunIC3WdtjcGywF/5J8RJ733f5pmtxoTZ6qfar1Dq07TKygJFRy6 Xgwe/m4ETOXVbGhXkvVNr82AtwT0AaM02+JZ7F7sHhogTtuuSylqwHKDKG7wrGDxy+RD cqkQ== X-Gm-Message-State: AOAM532FA39A2Dl1FMSkezWkDXVupWfO00F/3EO7NVY7NH1HeMNT2+8a Pk1V66G9v0CoSc8RqR5tQOa1jFu+t9QZ8Q== X-Google-Smtp-Source: ABdhPJxoHRAZpPbyD2JJE941QKdUnYipkwVw3cFqCoeWOIYsLop5+NQkbIGfpvnsOvCe/Obe6MtD8A== X-Received: by 2002:a5d:40cd:: with SMTP id b13mr21166606wrq.297.1600171595003; Tue, 15 Sep 2020 05:06:35 -0700 (PDT) Received: from jozef-acer-manjaro ([2a01:4b00:87fd:900:5e1d:5c99:56da:76e8]) by smtp.gmail.com with ESMTPSA id k22sm27155274wrd.29.2020.09.15.05.06.34 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Sep 2020 05:06:34 -0700 (PDT) Date: Tue, 15 Sep 2020 13:06:32 +0100 From: Jozef Lawrynowicz To: gnu-gabi@sourceware.org Subject: [RFC] SHF_GNU_RETAIN ELF Section Flag Message-ID: <20200915120632.bs36vkrbvmsoyvnu@jozef-acer-manjaro> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="dplfzjlaziowkcd5" Content-Disposition: inline X-Spam-Status: No, score=-10.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gnu-gabi@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gnu-gabi mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Sep 2020 12:06:41 -0000 --dplfzjlaziowkcd5 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, I'd like to propose a new ELF section flag, SHF_GNU_RETAIN, for addition to the GNU gABI. This flag instructs the linker to "retain" the section in the output file, even if garbage collection would remove it because it appears unused. The intention is to be able to apply the "retain" attribute to declarations of functions and data in the source code, and have the SHF_GNU_RETAIN flag be applied to the section containing the declaration. ====================================================== Section Attribute Flags +-------------------------------------+ | Name | Value | +-------------------------------------+ | SHF_GNU_RETAIN | 0x200000 (1 << 21) | +-------------------------------------+ SHF_GNU_RETAIN The section should not be garbage collected by the linker, even if it appears unused. ====================================================== ---------- Motivation ---------- Linker garbage collection is a useful feature to help reduce the size of linked output file, where sections are removed if they exclusively contain definitions of functions or data that are never referenced by other parts of the application. Currently, the KEEP linker script directive can be used to save a section from garbage collection. The new SHF_GNU_RETAIN flag has the same effect as KEEP, but since it is an ELF section flag, it means that this property can be propagated through the toolchain, from the compiler, through the assembler, to the linker. This enables a new "retain" attribute to be set on function and data declarations in the source code, which communicates the need to set the SHF_GNU_RETAIN flag on the containing section to downstream tools. In some situations, this has benefits over applying the KEEP directive in the linker script: - The requirement for protection from garbage collection might be application-specific, so consolidating this requirement to be contained entirely within the source code improves portability. - The user doesn't have to work out which section a function or data object declaration will be placed in, and then set the KEEP directive on that section. They can just set the attribute in the source code and leave the rest for the toolchain to handle. - Generally avoiding linker script modifications can improve the user experience, especially when the user is inexperienced with the linker script format. The boilerplate linker script code required for standard application operation can make modifications error-prone and have unintended side-effects. -------------- Implementation -------------- GCC supports a new "retain" attribute, which can be set on any declaration of function or data which could have a section. This means it can't be set on an automatic variable, for example. GAS supports a new ".retain [section name]" directive, which is used to apply SHF_GNU_RETAIN to the section named "section name". If "section name" is ommitted, SHF_GNU_RETAIN is applied to the current section the directive resides in. Alternatively, the "R" flag is recognized by the "flags" argument to the .section directive and will apply SHF_GNU_RETAIN to that section. It is intended that SHF_GNU_RETAIN does not interfere with any validation when switching to a section. It can be used to augment the section flags in a section which has already been created. When garbage collection is enabled, LD marks sections which have the SHF_GNU_RETAIN flag to save them from garbage collection. The underyling behavior is the same as if the section had the KEEP linker script directive applied. The user can always override SHF_GNU_RETAIN by placing the section in /DISCARD/. For reference, I've attached GCC and Binutils patches which implement the attribute. These are not "production ready", as there are some further tweaks to make, and more testing is required, but the functionality is working and the new tests are passing on msp430-elf, arm-eabi and x86_64-pc-linux-gnu. If this proposal is suitable for the GNU gABI, I will further improve and test the implementation, and submit the patches upstream soon. Thanks, and I look forward to hearing your thoughts. Jozef --dplfzjlaziowkcd5 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0001-Add-support-for-retain-attribute.patch" >From 308af5a66ad9c23b75804a43a7692e1884ce271b Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Tue, 8 Sep 2020 20:41:03 +0100 Subject: [PATCH] Add support for "retain" attribute --- gcc/c-family/c-attribs.c | 33 +++++++++++++ gcc/config/arm/arm.c | 2 + gcc/config/arm/unknown-elf.h | 5 +- gcc/config/elfos.h | 16 +++++++ gcc/config/i386/i386.c | 2 + gcc/config/msp430/msp430.c | 7 ++- gcc/defaults.h | 4 ++ gcc/doc/extend.texi | 23 +++++++++ gcc/testsuite/c-c++-common/attr-retain-1.c | 56 ++++++++++++++++++++++ gcc/testsuite/c-c++-common/attr-retain-2.c | 26 ++++++++++ gcc/testsuite/c-c++-common/attr-retain-3.c | 10 ++++ gcc/varasm.c | 19 +++++++- gcc/varasm.h | 3 ++ 13 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/attr-retain-1.c create mode 100644 gcc/testsuite/c-c++-common/attr-retain-2.c create mode 100644 gcc/testsuite/c-c++-common/attr-retain-3.c diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 37214831538..99839367e88 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -150,6 +150,7 @@ static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *); static tree handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *); static tree handle_copy_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) \ @@ -484,6 +485,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_noinit_attribute, attr_noinit_exclusions }, { "access", 1, 3, false, true, true, false, handle_access_attribute, NULL }, + { "retain", 0, 0, true, false, false, false, + handle_retain_attribute, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -2420,6 +2423,36 @@ handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args, decl, is_alias ? "alias" : "ifunc"); } + return NULL_TREE; +} + +/* Handle a "retain" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_retain_attribute (tree * pnode, + tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) +{ + tree node = *pnode; + + /* FIXME: Maybe it would be useful to allow the attribute to be set on types + as well... */ + if (TREE_CODE (node) == FUNCTION_DECL + || (VAR_P (node) && TREE_STATIC (node))) + { + TREE_USED (node) = 1; + DECL_PRESERVE_P (node) = 1; + if (VAR_P (node)) + DECL_READ_P (node) = 1; + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } return NULL_TREE; } diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index dd78141519e..5e36644e4a7 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -21407,6 +21407,8 @@ arm_asm_declare_function_name (FILE *file, const char *name, tree decl) ARM_DECLARE_FUNCTION_NAME (file, name, decl); ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); + if (lookup_attribute ("retain", DECL_ATTRIBUTES (decl))) + ASM_OUTPUT_RETAIN_DIRECTIVE (file, decl); ASM_DECLARE_RESULT (file, DECL_RESULT (decl)); ASM_OUTPUT_LABEL (file, name); diff --git a/gcc/config/arm/unknown-elf.h b/gcc/config/arm/unknown-elf.h index 9ad2947505f..d78d40cc00e 100644 --- a/gcc/config/arm/unknown-elf.h +++ b/gcc/config/arm/unknown-elf.h @@ -62,7 +62,7 @@ switch_to_section (get_named_section (DECL, NULL, 0)); \ else \ switch_to_section (bss_section); \ - \ + \ ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \ \ last_assemble_variable_decl = DECL; \ @@ -80,6 +80,9 @@ else \ switch_to_section (bss_section); \ \ + if (DECL && lookup_attribute ("retain", DECL_ATTRIBUTES (DECL))) \ + ASM_OUTPUT_RETAIN_DIRECTIVE (FILE, DECL); \ + \ ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \ ASM_OUTPUT_LABEL (FILE, NAME); \ fprintf (FILE, "\t.space\t%d\n", SIZE ? (int) SIZE : 1); \ diff --git a/gcc/config/elfos.h b/gcc/config/elfos.h index 74a3eafda6b..9be1948c008 100644 --- a/gcc/config/elfos.h +++ b/gcc/config/elfos.h @@ -275,6 +275,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define ASM_DECLARE_RESULT(FILE, RESULT) #endif +#ifndef ASM_OUTPUT_RETAIN_DIRECTIVE +#define ASM_OUTPUT_RETAIN_DIRECTIVE(STREAM, DECL) \ + do \ + { \ + assemble_retain (STREAM, DECL); \ + } \ + while (0) +#endif + /* These macros generate the special .type and .size directives which are used to set the corresponding fields of the linker symbol table entries in an ELF object file under SVR4. These macros also output @@ -289,6 +298,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see do \ { \ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function"); \ + if (lookup_attribute ("retain", DECL_ATTRIBUTES (DECL))) \ + ASM_OUTPUT_RETAIN_DIRECTIVE (FILE, DECL); \ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ ASM_OUTPUT_FUNCTION_LABEL (FILE, NAME, DECL); \ } \ @@ -305,6 +316,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see do \ { \ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "function"); \ + if (lookup_attribute ("retain", DECL_ATTRIBUTES (DECL))) \ + ASM_OUTPUT_RETAIN_DIRECTIVE (FILE, DECL); \ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ ASM_OUTPUT_FUNCTION_LABEL (FILE, NAME, DECL); \ } \ @@ -335,6 +348,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see else \ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ \ + if (lookup_attribute ("retain", DECL_ATTRIBUTES (DECL))) \ + ASM_OUTPUT_RETAIN_DIRECTIVE (FILE, DECL); \ + \ size_directive_output = 0; \ if (!flag_inhibit_size_directive \ && (DECL) && DECL_SIZE (DECL)) \ diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index a15807d91da..062d68765d5 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -850,6 +850,8 @@ x86_elf_aligned_decl_common (FILE *file, tree decl, assemble_name (file, name); fprintf (file, "," HOST_WIDE_INT_PRINT_UNSIGNED ",%u\n", size, align / BITS_PER_UNIT); + if (lookup_attribute ("retain", DECL_ATTRIBUTES (decl))) + ASM_OUTPUT_RETAIN_DIRECTIVE (file, decl); } #endif diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index a299ed7f9d1..dac3896e416 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -1746,6 +1746,8 @@ msp430_start_function (FILE *file, const char *name, tree decl) switch_to_section (function_section (decl)); ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); + if (lookup_attribute ("retain", DECL_ATTRIBUTES (decl))) + ASM_OUTPUT_RETAIN_DIRECTIVE (file, decl); ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); } @@ -2018,7 +2020,8 @@ msp430_output_aligned_decl_common (FILE * stream, && !has_attr (ATTR_LOWER, decl) && !has_attr (ATTR_UPPER, decl) && !has_attr (ATTR_PERSIST, decl) - && !has_attr (ATTR_NOINIT, decl)) + && !has_attr (ATTR_NOINIT, decl) + && !has_attr ("retain", decl)) { if (local) { @@ -2064,6 +2067,8 @@ msp430_output_aligned_decl_common (FILE * stream, ASM_OUTPUT_LABEL (stream, name); ASM_OUTPUT_SKIP (stream, size ? size : 1); } + if (decl && lookup_attribute ("retain", DECL_ATTRIBUTES (decl))) + ASM_OUTPUT_RETAIN_DIRECTIVE (stream, decl); } #undef TARGET_ASM_FILE_END diff --git a/gcc/defaults.h b/gcc/defaults.h index f1a38626624..9899d4abce2 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -260,6 +260,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #endif #endif +#ifndef ASM_OUTPUT_RETAIN_DIRECTIVE +#define ASM_OUTPUT_RETAIN_DIRECTIVE(STREAM, DECL) hook_void_void +#endif + /* This determines whether or not we support weak symbols. SUPPORTS_WEAK must be a preprocessor constant. */ #ifndef SUPPORTS_WEAK diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 3b37aba5795..5342dd2801d 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -3578,6 +3578,17 @@ diagnosed. Because a pure function cannot have any observable side effects it does not make sense for such a function to return @code{void}. Declaring such a function is diagnosed. +@item retain +@cindex @code{retain} function attribute +The @code{retain} attribute, attached to a function, means that function must +not be garbage collected by the linker, even if it appears unused. + +The section containing the function is marked with the SHF_GNU_RETAIN flag, +which is a GNU extension to the ELF standard. + +This attribute implies, and has the same restrictions as, the @code{used} +attribute. + @item returns_nonnull @cindex @code{returns_nonnull} function attribute The @code{returns_nonnull} attribute specifies that the function @@ -7168,6 +7179,18 @@ been fixed in GCC 4.4 but the change can lead to differences in the structure layout. See the documentation of @option{-Wpacked-bitfield-compat} for more information. +@item retain +@cindex @code{retain} variable attribute +The @code{retain} attribute, attached to a variable with static storage, means +that variable must not be garbage collected by the linker, even if it appears +unused. + +The section containing the variable is marked with the SHF_GNU_RETAIN flag, +which is a GNU extension to the ELF standard. + +This attribute implies, and has the same restrictions as, the @code{used} +attribute. + @item section ("@var{section-name}") @cindex @code{section} variable attribute Normally, the compiler places the objects it generates in sections like diff --git a/gcc/testsuite/c-c++-common/attr-retain-1.c b/gcc/testsuite/c-c++-common/attr-retain-1.c new file mode 100644 index 00000000000..2ed6f9b220c --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-1.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.a1" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.b1" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.data\\.c1" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.sa1" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.sb1" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.data\\.sc1" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.text\\.foo1" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.lsa" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.bss\\.lsb" } } */ +/* { dg-final { scan-assembler "\\.retain\t\\.data\\.lsc" } } */ + +/* Test .retain directives are emitted for declarations using the "retain" + when they are each put in their own sections. */ + +#define RETAIN __attribute__((retain)) +#define SECTION(X) __attribute__((section(X))) + +/* This group of functions and data should be garbage collected by the + linker. */ +int SECTION(".bss.a0") a0; +int SECTION(".bss.b0") b0 = 0; +int SECTION(".data.c0") c0 = 1; +static int SECTION(".bss.sa0") sa0; +static int SECTION(".bss.sb0") sb0 = 0; +static int SECTION(".data.sc0") sc0 = 1; +void SECTION(".text.foo0") foo0 (void) {} + +/* The "retain" attribute set on this group of functions and data should protect + them from linker garbage collection. */ +int RETAIN SECTION(".bss.a1") a1; +int RETAIN SECTION(".bss.b1") b1 = 0; +int RETAIN SECTION(".data.c1") c1 = 1; +static int RETAIN SECTION(".bss.sa1") sa1; +static int RETAIN SECTION(".bss.sb1") sb1 = 0; +static int RETAIN SECTION(".data.sc1") sc1 = 1; +void RETAIN SECTION(".text.foo1") foo1 (void) {} + +/* .text.foo2 should be garbage collected, but the static variables defined + inside it have the retain attribute so should not be garbage collected. */ +void SECTION(".text.foo2") +foo2 (void) +{ + static int RETAIN SECTION(".bss.lsa") lsa; + static int RETAIN SECTION(".bss.lsb") lsb = 0; + static int RETAIN SECTION(".data.lsc") lsc = 1; + lsa++; + lsb++; + lsc++; +} + +int main (void) +{ + while (1); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/attr-retain-2.c b/gcc/testsuite/c-c++-common/attr-retain-2.c new file mode 100644 index 00000000000..cd906246cbf --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-final { scan-assembler-times "\\.retain" 10 } } */ + +/* Test .retain directives are emitted for declarations using the "retain" + attribute, even when symbols don't have an explicit section. */ + +#define RETAIN __attribute__((retain)) + +int RETAIN a1; +int RETAIN b1 = 0; +int RETAIN c1 = 1; +static int RETAIN sa1; +static int RETAIN sb1 = 0; +static int RETAIN sc1 = 1; +void RETAIN foo1 (void) {} + +void +foo2 (void) +{ + static int RETAIN lsa; + static int RETAIN lsb = 0; + static int RETAIN lsc = 1; + lsa++; + lsb++; + lsc++; +} diff --git a/gcc/testsuite/c-c++-common/attr-retain-3.c b/gcc/testsuite/c-c++-common/attr-retain-3.c new file mode 100644 index 00000000000..a8c1917e38a --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ + +typedef int int_retain __attribute__((retain)); /* { dg-warning "" "'retain' attribute ignored" } */ + +void +foo (void) +{ + int __attribute__((retain)) a; /* { dg-warning "" "'retain' attribute ignored" } */ + while(a++); +} diff --git a/gcc/varasm.c b/gcc/varasm.c index ea0b59cf44a..db67329fe74 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -483,11 +483,13 @@ resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED, support is localized here. */ static void -asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED, +asm_output_aligned_bss (FILE *file, tree decl, const char *name, unsigned HOST_WIDE_INT size, int align) { switch_to_section (bss_section); + if (lookup_attribute ("retain", DECL_ATTRIBUTES (decl))) + ASM_OUTPUT_RETAIN_DIRECTIVE (file, decl); ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); #ifdef ASM_DECLARE_OBJECT_NAME last_assemble_variable_decl = decl; @@ -6225,6 +6227,21 @@ assemble_alias (tree decl, tree target) } } +/* Emit a ".retain" assembler directive, which applies the SHF_GNU_RETAIN flag + to the specified section. This indicates that the linker should not garbage + collect the section, even if it appears unused. */ +void +assemble_retain (FILE *stream, tree decl) +{ + if (DECL_SECTION_NAME (decl)) + fprintf (stream, "\t.retain\t%s\n", DECL_SECTION_NAME (decl)); + else + /* If the section name isn't readily available, just output the bare + ".retain" directive, which indicates the current section should be + retained. */ + fprintf (stream, "\t.retain\n"); +} + /* Record and output a table of translations from original function to its transaction aware clone. Note that tm_pure functions are considered to be their own clone. */ diff --git a/gcc/varasm.h b/gcc/varasm.h index 1b715ab1736..97001d8975f 100644 --- a/gcc/varasm.h +++ b/gcc/varasm.h @@ -51,6 +51,9 @@ extern void merge_weak (tree, tree); /* Make one symbol an alias for another. */ extern void assemble_alias (tree, tree); +/* Emit the .retain directive. */ +void assemble_retain (FILE *stream, tree decl); + /* Return nonzero if VALUE is a valid constant-valued expression for use in initializing a static variable; one that can be an element of a "constant" initializer. -- 2.28.0 --dplfzjlaziowkcd5 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0001-Support-SHF_GNU_RETAIN-ELF-section-flag.patch" >From c3992c8f10a89a0133be0d0c0ca896b04d4f72fd Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Wed, 9 Sep 2020 22:00:16 +0100 Subject: [PATCH] Support SHF_GNU_RETAIN ELF section flag --- bfd/elflink.c | 3 +- binutils/readelf.c | 4 + gas/config/obj-elf.c | 57 +++++++++++++ gas/doc/as.texi | 17 ++++ gas/testsuite/gas/elf/elf.exp | 5 ++ gas/testsuite/gas/elf/retain1.d | 24 ++++++ gas/testsuite/gas/elf/retain1.s | 131 +++++++++++++++++++++++++++++ gas/testsuite/gas/elf/retain2.d | 2 + gas/testsuite/gas/elf/retain2.l | 3 + gas/testsuite/gas/elf/retain2.s | 7 ++ gas/testsuite/gas/elf/retain3.d | 24 ++++++ gas/testsuite/gas/elf/retain3.s | 121 +++++++++++++++++++++++++++ gas/testsuite/gas/elf/section10.d | 4 +- include/elf/common.h | 1 + ld/testsuite/ld-elf/elf.exp | 14 ++++ ld/testsuite/ld-elf/retain1.msg | 8 ++ ld/testsuite/ld-elf/retain1.s | 134 ++++++++++++++++++++++++++++++ ld/testsuite/ld-elf/retain2.d | 5 ++ ld/testsuite/ld-elf/retain2.ld | 7 ++ ld/testsuite/ld-elf/retain2.map | 18 ++++ ld/testsuite/ld-elf/retain3.msg | 8 ++ ld/testsuite/ld-elf/retain3.s | 124 +++++++++++++++++++++++++++ 22 files changed, 718 insertions(+), 3 deletions(-) create mode 100644 gas/testsuite/gas/elf/retain1.d create mode 100644 gas/testsuite/gas/elf/retain1.s create mode 100644 gas/testsuite/gas/elf/retain2.d create mode 100644 gas/testsuite/gas/elf/retain2.l create mode 100644 gas/testsuite/gas/elf/retain2.s create mode 100644 gas/testsuite/gas/elf/retain3.d create mode 100644 gas/testsuite/gas/elf/retain3.s create mode 100644 ld/testsuite/ld-elf/retain1.msg create mode 100644 ld/testsuite/ld-elf/retain1.s create mode 100644 ld/testsuite/ld-elf/retain2.d create mode 100644 ld/testsuite/ld-elf/retain2.ld create mode 100644 ld/testsuite/ld-elf/retain2.map create mode 100644 ld/testsuite/ld-elf/retain3.msg create mode 100644 ld/testsuite/ld-elf/retain3.s diff --git a/bfd/elflink.c b/bfd/elflink.c index 0e339f3c1e..6d1a1c5105 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -13977,7 +13977,8 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) || (elf_section_data (o)->this_hdr.sh_type == SHT_FINI_ARRAY))) || (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE - && elf_next_in_group (o) == NULL ))) + && elf_next_in_group (o) == NULL) + || (elf_section_flags (o) & SHF_GNU_RETAIN))) { if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) return FALSE; diff --git a/binutils/readelf.c b/binutils/readelf.c index cb4208f7b9..00502f7058 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -5977,6 +5977,8 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags) /* 24 */ { STRING_COMMA_LEN ("GNU_MBIND") }, /* VLE specific. */ /* 25 */ { STRING_COMMA_LEN ("VLE") }, + /* GNU specific. */ + /* 26 */ { STRING_COMMA_LEN ("GNU_RETAIN") }, }; if (do_section_details) @@ -6010,6 +6012,7 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags) case SHF_EXCLUDE: sindex = 18; break; case SHF_COMPRESSED: sindex = 20; break; case SHF_GNU_MBIND: sindex = 24; break; + case SHF_GNU_RETAIN: sindex = 26; break; default: sindex = -1; @@ -6108,6 +6111,7 @@ get_elf_section_flags (Filedata * filedata, bfd_vma sh_flags) case SHF_EXCLUDE: *p = 'E'; break; case SHF_COMPRESSED: *p = 'C'; break; case SHF_GNU_MBIND: *p = 'D'; break; + case SHF_GNU_RETAIN: *p = 'R'; break; default: if ((filedata->file_header.e_machine == EM_X86_64 diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c index 9e39707801..0e8f3aa642 100644 --- a/gas/config/obj-elf.c +++ b/gas/config/obj-elf.c @@ -78,6 +78,7 @@ static void obj_elf_gnu_attribute (int); static void obj_elf_tls_common (int); static void obj_elf_lcomm (int); static void obj_elf_struct (int); +static void obj_elf_retain (int); static const pseudo_typeS elf_pseudo_table[] = { @@ -119,6 +120,9 @@ static const pseudo_typeS elf_pseudo_table[] = /* A GNU extension for object attributes. */ {"gnu_attribute", obj_elf_gnu_attribute, 0}, + /* A GNU extension for preventing linker garbage collection of sections. */ + {"retain", obj_elf_retain, 0}, + /* These are used for dwarf. */ {"2byte", cons, 2}, {"4byte", cons, 4}, @@ -857,6 +861,9 @@ obj_elf_parse_section_letters (char *str, size_t len, case 'd': *gnu_attr |= SHF_GNU_MBIND; break; + case 'R': + *gnu_attr |= SHF_GNU_RETAIN; + break; case '?': *is_clone = TRUE; break; @@ -1986,6 +1993,56 @@ obj_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED) obj_elf_vendor_attribute (OBJ_ATTR_GNU); } +/* Parse a .retain ["sectionname"] directive. + The SHF_GNU_RETAIN flag should be applied to "section name". + If section name is omitted, then the SHF_GNU_RETAIN flag should be + applied to the current section being assembled. */ +static void +obj_elf_retain (int ignored ATTRIBUTE_UNUSED) +{ + const char *name; + symbolS *secsym; + asection *bfdsec; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + { + name = now_seg->name; + if (name == NULL) + { + as_bad (_("\".retain\" directive not within a section")); + ignore_rest_of_line (); + return; + } + } + else + { + name = obj_elf_section_name (); + secsym = symbol_find (name); + if (secsym == NULL) + { + as_bad (_("section '%s' has not been declared"), name); + ignore_rest_of_line (); + return; + } + else if (secsym != NULL + && !symbol_section_p (secsym)) + { + as_bad (_("'%s' is not a section name, expected " + "\".retain [section name]\""), name); + ignore_rest_of_line (); + return; + } + } + demand_empty_rest_of_line (); + + bfdsec = bfd_get_section_by_name (stdoutput, name); + if (bfdsec != NULL) + elf_section_flags (bfdsec) |= SHF_GNU_RETAIN; + else + as_bad (_("Couldn't find BFD section for %s\n"), name); +} + void elf_obj_read_begin_hook (void) { diff --git a/gas/doc/as.texi b/gas/doc/as.texi index 112eaf810c..3ecbf88023 100644 --- a/gas/doc/as.texi +++ b/gas/doc/as.texi @@ -4468,6 +4468,7 @@ Some machine configurations provide additional directives. * Quad:: @code{.quad @var{bignums}} * Reloc:: @code{.reloc @var{offset}, @var{reloc_name}[, @var{expression}]} * Rept:: @code{.rept @var{count}} +* Retain:: @code{.retain ["@var{sectionname}"]} * Sbttl:: @code{.sbttl "@var{subheading}"} @ifset COFF * Scl:: @code{.scl @var{class}} @@ -6468,6 +6469,22 @@ is equivalent to assembling A count of zero is allowed, but nothing is generated. Negative counts are not allowed and if encountered will be treated as if they were zero. +@ifset ELF +@node Retain +@section @code{.retain ["@var{sectionname}"]} + +@cindex @code{retain} directive +@cindex SHF_GNU_RETAIN + +Apply the @var{SHF_GNU_RETAIN} flag to the section named @var{sectionname}, or +the current section the directive resides in, if this argument is +omitted. + +The SHF_GNU_RETAIN section flag indicates that the given section should not be +garbage collected by the linker, even if it appears unused. + +@end ifset + @node Sbttl @section @code{.sbttl "@var{subheading}"} diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp index 8520421ba3..3a4879e348 100644 --- a/gas/testsuite/gas/elf/elf.exp +++ b/gas/testsuite/gas/elf/elf.exp @@ -307,6 +307,11 @@ if { [is_elf_format] } then { run_dump_test "strtab" + # Tests for the .retain directive/SHF_GNU_RETAIN. + run_dump_test "retain1" + run_dump_test "retain2" + run_dump_test "retain3" + run_dump_test "bignums" run_dump_test "section-symbol-redef" diff --git a/gas/testsuite/gas/elf/retain1.d b/gas/testsuite/gas/elf/retain1.d new file mode 100644 index 0000000000..48c57f1241 --- /dev/null +++ b/gas/testsuite/gas/elf/retain1.d @@ -0,0 +1,24 @@ +#readelf: -S --wide +#name: SHF_GNU_RETAIN 1 + +#... + \[..\] .bss.a0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .bss.b0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .data.c0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .bss.sa0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .bss.sb0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .data.sc0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .text.foo0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.* + \[..\] .bss.a1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .bss.b1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .data.c1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .bss.sa1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .bss.sb1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .data.sc1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .text.foo1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.* + \[..\] .text.foo2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.* +#... + \[..\] .bss.lsa[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .bss.lsb[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .data.lsc[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* +#pass diff --git a/gas/testsuite/gas/elf/retain1.s b/gas/testsuite/gas/elf/retain1.s new file mode 100644 index 0000000000..2ea652ea35 --- /dev/null +++ b/gas/testsuite/gas/elf/retain1.s @@ -0,0 +1,131 @@ +.text + .global a0 + .section .bss.a0,"aw" + .balign 2 + .type a0, STT_OBJECT + .size a0, 2 +a0: + .zero 2 + .global b0 + .section .bss.b0,"aw" + .balign 2 + .type b0, STT_OBJECT + .size b0, 2 +b0: + .zero 2 + .global c0 + .section .data.c0,"aw" + .balign 2 + .type c0, STT_OBJECT + .size c0, 2 +c0: + .short 1 + .section .bss.sa0,"aw" + .balign 2 + .type sa0, STT_OBJECT + .size sa0, 2 +sa0: + .zero 2 + .section .bss.sb0,"aw" + .balign 2 + .type sb0, STT_OBJECT + .size sb0, 2 +sb0: + .zero 2 + .section .data.sc0,"aw" + .balign 2 + .type sc0, STT_OBJECT + .size sc0, 2 +sc0: + .short 1 + .section .text.foo0,"ax" + .balign 2 + .global foo0 + .type foo0, STT_FUNC +foo0: + .size foo0, .-foo0 + .global a1 + .section .bss.a1,"aw" + .balign 2 + .type a1, STT_OBJECT + .retain .bss.a1 + .size a1, 2 +a1: + .zero 2 + .global b1 + .section .bss.b1,"aw" + .balign 2 + .type b1, STT_OBJECT + .retain .bss.b1 + .size b1, 2 +b1: + .zero 2 + .global c1 + .section .data.c1,"aw" + .balign 2 + .type c1, STT_OBJECT + .retain .data.c1 + .size c1, 2 +c1: + .short 1 + .section .bss.sa1,"aw" + .balign 2 + .type sa1, STT_OBJECT + .retain .bss.sa1 + .size sa1, 2 +sa1: + .zero 2 + .section .bss.sb1,"aw" + .balign 2 + .type sb1, STT_OBJECT + .retain .bss.sb1 + .size sb1, 2 +sb1: + .zero 2 + .section .data.sc1,"aw" + .balign 2 + .type sc1, STT_OBJECT + .retain .data.sc1 + .size sc1, 2 +sc1: + .short 1 + .section .text.foo1,"ax" + .balign 2 + .global foo1 + .type foo1, STT_FUNC + .retain .text.foo1 +foo1: + .size foo1, .-foo1 + .section .text.foo2,"ax" + .balign 2 + .global foo2 + .type foo2, STT_FUNC +foo2: + .size foo2, .-foo2 + .section .bss.lsa,"aw" + .balign 2 + .type lsa.2, STT_OBJECT + .retain .bss.lsa + .size lsa.2, 2 +lsa.2: + .zero 2 + .section .bss.lsb,"aw" + .balign 2 + .type lsb.1, STT_OBJECT + .retain .bss.lsb + .size lsb.1, 2 +lsb.1: + .zero 2 + .section .data.lsc,"aw" + .balign 2 + .type lsc.0, STT_OBJECT + .retain .data.lsc + .size lsc.0, 2 +lsc.0: + .short 1 +.text + .balign 2 + .global main + .type main, STT_FUNC +main: + .size main, .-main diff --git a/gas/testsuite/gas/elf/retain2.d b/gas/testsuite/gas/elf/retain2.d new file mode 100644 index 0000000000..55bcb87ab3 --- /dev/null +++ b/gas/testsuite/gas/elf/retain2.d @@ -0,0 +1,2 @@ +#name: SHF_GNU_RETAIN 2 +#error_output: retain2.l diff --git a/gas/testsuite/gas/elf/retain2.l b/gas/testsuite/gas/elf/retain2.l new file mode 100644 index 0000000000..3cf31b3e25 --- /dev/null +++ b/gas/testsuite/gas/elf/retain2.l @@ -0,0 +1,3 @@ +[^:]*: Assembler messages: +[^:]*:1: Error: section '.data.foo' has not been declared +[^:]*:7: Error: 'myvar' is not a section name, expected ".retain \[section name\]" diff --git a/gas/testsuite/gas/elf/retain2.s b/gas/testsuite/gas/elf/retain2.s new file mode 100644 index 0000000000..3522546886 --- /dev/null +++ b/gas/testsuite/gas/elf/retain2.s @@ -0,0 +1,7 @@ +.retain ".data.foo" +.data +.global myvar +.type myvar, STT_OBJECT +myvar: + .byte 2 +.retain "myvar" diff --git a/gas/testsuite/gas/elf/retain3.d b/gas/testsuite/gas/elf/retain3.d new file mode 100644 index 0000000000..78a7c26c47 --- /dev/null +++ b/gas/testsuite/gas/elf/retain3.d @@ -0,0 +1,24 @@ +#readelf: -S --wide +#name: SHF_GNU_RETAIN 3 (use flags set on .section directive) + +#... + \[..\] .bss.a0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .bss.b0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .data.c0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .bss.sa0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .bss.sb0[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .data.sc0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WA.* + \[..\] .text.foo0[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.* + \[..\] .bss.a1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .bss.b1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .data.c1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .bss.sa1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .bss.sb1[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .data.sc1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .text.foo1[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AXR.* + \[..\] .text.foo2[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 AX.* +#... + \[..\] .bss.lsa[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .bss.lsb[ ]+NOBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* + \[..\] .data.lsc[ ]+PROGBITS[ ]+[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 WAR.* +#pass diff --git a/gas/testsuite/gas/elf/retain3.s b/gas/testsuite/gas/elf/retain3.s new file mode 100644 index 0000000000..a7f050a8f5 --- /dev/null +++ b/gas/testsuite/gas/elf/retain3.s @@ -0,0 +1,121 @@ +.text + .global a0 + .section .bss.a0,"aw" + .balign 2 + .type a0, STT_OBJECT + .size a0, 2 +a0: + .zero 2 + .global b0 + .section .bss.b0,"aw" + .balign 2 + .type b0, STT_OBJECT + .size b0, 2 +b0: + .zero 2 + .global c0 + .section .data.c0,"aw" + .balign 2 + .type c0, STT_OBJECT + .size c0, 2 +c0: + .short 1 + .section .bss.sa0,"aw" + .balign 2 + .type sa0, STT_OBJECT + .size sa0, 2 +sa0: + .zero 2 + .section .bss.sb0,"aw" + .balign 2 + .type sb0, STT_OBJECT + .size sb0, 2 +sb0: + .zero 2 + .section .data.sc0,"aw" + .balign 2 + .type sc0, STT_OBJECT + .size sc0, 2 +sc0: + .short 1 + .section .text.foo0,"ax" + .balign 2 + .global foo0 + .type foo0, STT_FUNC +foo0: + .size foo0, .-foo0 + .global a1 + .section .bss.a1,"awR" + .balign 2 + .type a1, STT_OBJECT + .size a1, 2 +a1: + .zero 2 + .global b1 + .section .bss.b1,"awR" + .balign 2 + .type b1, STT_OBJECT + .size b1, 2 +b1: + .zero 2 + .global c1 + .section .data.c1,"awR" + .balign 2 + .type c1, STT_OBJECT + .size c1, 2 +c1: + .short 1 + .section .bss.sa1,"awR" + .balign 2 + .type sa1, STT_OBJECT + .size sa1, 2 +sa1: + .zero 2 + .section .bss.sb1,"awR" + .balign 2 + .type sb1, STT_OBJECT + .size sb1, 2 +sb1: + .zero 2 + .section .data.sc1,"awR" + .balign 2 + .type sc1, STT_OBJECT + .size sc1, 2 +sc1: + .short 1 + .section .text.foo1,"axR" + .balign 2 + .global foo1 + .type foo1, STT_FUNC +foo1: + .size foo1, .-foo1 + .section .text.foo2,"ax" + .balign 2 + .global foo2 + .type foo2, STT_FUNC +foo2: + .size foo2, .-foo2 + .section .bss.lsa,"awR" + .balign 2 + .type lsa.2, STT_OBJECT + .size lsa.2, 2 +lsa.2: + .zero 2 + .section .bss.lsb,"awR" + .balign 2 + .type lsb.1, STT_OBJECT + .size lsb.1, 2 +lsb.1: + .zero 2 + .section .data.lsc,"awR" + .balign 2 + .type lsc.0, STT_OBJECT + .size lsc.0, 2 +lsc.0: + .short 1 +.text + .balign 2 + .global main + .type main, STT_FUNC +main: + .size main, .-main diff --git a/gas/testsuite/gas/elf/section10.d b/gas/testsuite/gas/elf/section10.d index 554a791f1d..ef91d7d086 100644 --- a/gas/testsuite/gas/elf/section10.d +++ b/gas/testsuite/gas/elf/section10.d @@ -18,7 +18,7 @@ #... [ ]*\[.*\][ ]+sec3 [ ]*PROGBITS.* -[ ]*\[.*fefff030\]: MERGE, STRINGS,.* EXCLUDE, OS \(.*ef00000\), PROC \(.*[3467]0000000\), UNKNOWN \(0+0ff000\) +[ ]*\[.*fefff030\]: MERGE, STRINGS,.* EXCLUDE, OS \(.*ed00000\), PROC \(.*[3467]0000000\), UNKNOWN \(0+0ff000\) #... [ ]*\[.*\][ ]+sec4 [ ]*LOOS\+0x11[ ].* @@ -26,7 +26,7 @@ #... [ ]*\[.*\][ ]+sec5 [ ]*LOUSER\+0x9[ ].* -[ ]*\[.*feff0000\]:.* EXCLUDE, OS \(.*ef00000\), PROC \(.*[3467]0000000\), UNKNOWN \(.*f0000\) +[ ]*\[.*feff0000\]:.* EXCLUDE, OS \(.*ed00000\), PROC \(.*[3467]0000000\), UNKNOWN \(.*f0000\) [ ]*\[.*\][ ]+.data.foo [ ]*LOUSER\+0x7f000000[ ].* [ ]*\[0+003\]: WRITE, ALLOC diff --git a/include/elf/common.h b/include/elf/common.h index 805058146a..364c58a7de 100644 --- a/include/elf/common.h +++ b/include/elf/common.h @@ -554,6 +554,7 @@ /* #define SHF_MASKOS 0x0F000000 *//* OS-specific semantics */ #define SHF_MASKOS 0x0FF00000 /* New value, Oct 4, 1999 Draft */ #define SHF_GNU_BUILD_NOTE (1 << 20) /* Section contains GNU BUILD ATTRIBUTE notes. */ +#define SHF_GNU_RETAIN (1 << 21) /* Section should not be garbage collected by the linker. */ #define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */ /* This used to be implemented as a processor specific section flag. diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp index c0d67d80d2..04027fcbed 100644 --- a/ld/testsuite/ld-elf/elf.exp +++ b/ld/testsuite/ld-elf/elf.exp @@ -225,6 +225,20 @@ if [check_gc_sections_available] { {pr25490-6.s} \ [list [list "readelf" {-SW} $pr25490_6_exp]] \ "pr25490-6.exe"] \ + [list "SHF_GNU_RETAIN 1" \ + "--gc-sections -e main --print-gc-sections" \ + "" \ + "" \ + {retain1.s} \ + {{ ld retain1.msg }} \ + "retain1.exe"] \ + [list "SHF_GNU_RETAIN 3 (use flags set on .section directive)" \ + "--gc-sections -e main --print-gc-sections" \ + "" \ + "" \ + {retain3.s} \ + {{ ld retain3.msg }} \ + "retain3.exe"] \ ] } diff --git a/ld/testsuite/ld-elf/retain1.msg b/ld/testsuite/ld-elf/retain1.msg new file mode 100644 index 0000000000..0e0f24ff10 --- /dev/null +++ b/ld/testsuite/ld-elf/retain1.msg @@ -0,0 +1,8 @@ +.*: removing unused section '.bss.a0' in file.* +.*: removing unused section '.bss.b0' in file.* +.*: removing unused section '.data.c0' in file.* +.*: removing unused section '.bss.sa0' in file.* +.*: removing unused section '.bss.sb0' in file.* +.*: removing unused section '.data.sc0' in file.* +.*: removing unused section '.text.foo0' in file.* +.*: removing unused section '.text.foo2' in file.* diff --git a/ld/testsuite/ld-elf/retain1.s b/ld/testsuite/ld-elf/retain1.s new file mode 100644 index 0000000000..05b739ba64 --- /dev/null +++ b/ld/testsuite/ld-elf/retain1.s @@ -0,0 +1,134 @@ +.text + .global a0 + .section .bss.a0,"aw" + .balign 2 + .type a0, STT_OBJECT + .size a0, 2 +a0: + .zero 2 + .global b0 + .section .bss.b0,"aw" + .balign 2 + .type b0, STT_OBJECT + .size b0, 2 +b0: + .zero 2 + .global c0 + .section .data.c0,"aw" + .balign 2 + .type c0, STT_OBJECT + .size c0, 2 +c0: + .short 1 + .section .bss.sa0,"aw" + .balign 2 + .type sa0, STT_OBJECT + .size sa0, 2 +sa0: + .zero 2 + .section .bss.sb0,"aw" + .balign 2 + .type sb0, STT_OBJECT + .size sb0, 2 +sb0: + .zero 2 + .section .data.sc0,"aw" + .balign 2 + .type sc0, STT_OBJECT + .size sc0, 2 +sc0: + .short 1 + .section .text.foo0,"ax" + .balign 2 + .global foo0 + .type foo0, STT_FUNC +foo0: + .word 0 + .size foo0, .-foo0 + .global a1 + .section .bss.a1,"aw" + .balign 2 + .type a1, STT_OBJECT + .retain .bss.a1 + .size a1, 2 +a1: + .zero 2 + .global b1 + .section .bss.b1,"aw" + .balign 2 + .type b1, STT_OBJECT + .retain .bss.b1 + .size b1, 2 +b1: + .zero 2 + .global c1 + .section .data.c1,"aw" + .balign 2 + .type c1, STT_OBJECT + .retain .data.c1 + .size c1, 2 +c1: + .short 1 + .section .bss.sa1,"aw" + .balign 2 + .type sa1, STT_OBJECT + .retain .bss.sa1 + .size sa1, 2 +sa1: + .zero 2 + .section .bss.sb1,"aw" + .balign 2 + .type sb1, STT_OBJECT + .retain .bss.sb1 + .size sb1, 2 +sb1: + .zero 2 + .section .data.sc1,"aw" + .balign 2 + .type sc1, STT_OBJECT + .retain .data.sc1 + .size sc1, 2 +sc1: + .short 1 + .section .text.foo1,"ax" + .balign 2 + .global foo1 + .type foo1, STT_FUNC + .retain .text.foo1 +foo1: + .word 0 + .size foo1, .-foo1 + .section .text.foo2,"ax" + .balign 2 + .global foo2 + .type foo2, STT_FUNC +foo2: + .word 0 + .size foo2, .-foo2 + .section .bss.lsa,"aw" + .balign 2 + .type lsa.2, STT_OBJECT + .retain .bss.lsa + .size lsa.2, 2 +lsa.2: + .zero 2 + .section .bss.lsb,"aw" + .balign 2 + .type lsb.1, STT_OBJECT + .retain .bss.lsb + .size lsb.1, 2 +lsb.1: + .zero 2 + .section .data.lsc,"aw" + .balign 2 + .type lsc.0, STT_OBJECT + .retain .data.lsc + .size lsc.0, 2 +lsc.0: + .short 1 +.text + .balign 2 + .global main + .type main, STT_FUNC +main: + .size main, .-main diff --git a/ld/testsuite/ld-elf/retain2.d b/ld/testsuite/ld-elf/retain2.d new file mode 100644 index 0000000000..207227928e --- /dev/null +++ b/ld/testsuite/ld-elf/retain2.d @@ -0,0 +1,5 @@ +# source: retain1.s +# ld: -e main -Map=retain2.map --gc-sections --script=retain2.ld +# map: retain2.map + +#pass diff --git a/ld/testsuite/ld-elf/retain2.ld b/ld/testsuite/ld-elf/retain2.ld new file mode 100644 index 0000000000..b8c9e6dfd1 --- /dev/null +++ b/ld/testsuite/ld-elf/retain2.ld @@ -0,0 +1,7 @@ +SECTIONS +{ + /DISCARD/ : + { + *(".text.foo1") + } +} diff --git a/ld/testsuite/ld-elf/retain2.map b/ld/testsuite/ld-elf/retain2.map new file mode 100644 index 0000000000..65b61f7488 --- /dev/null +++ b/ld/testsuite/ld-elf/retain2.map @@ -0,0 +1,18 @@ +# Test that .text.foo1, which has the SHF_GNU_RETAIN flag, can still be +# explicitly discarded from the output file. + +#... +Discarded input sections + + .data.* + .bss.* + .bss.a0.* + .bss.b0.* + .data.c0.* + .bss.sa0.* + .bss.sb0.* + .data.sc0.* + .text.foo0.* + .text.foo1.* + .text.foo2.* +#pass diff --git a/ld/testsuite/ld-elf/retain3.msg b/ld/testsuite/ld-elf/retain3.msg new file mode 100644 index 0000000000..0e0f24ff10 --- /dev/null +++ b/ld/testsuite/ld-elf/retain3.msg @@ -0,0 +1,8 @@ +.*: removing unused section '.bss.a0' in file.* +.*: removing unused section '.bss.b0' in file.* +.*: removing unused section '.data.c0' in file.* +.*: removing unused section '.bss.sa0' in file.* +.*: removing unused section '.bss.sb0' in file.* +.*: removing unused section '.data.sc0' in file.* +.*: removing unused section '.text.foo0' in file.* +.*: removing unused section '.text.foo2' in file.* diff --git a/ld/testsuite/ld-elf/retain3.s b/ld/testsuite/ld-elf/retain3.s new file mode 100644 index 0000000000..f1ade91c87 --- /dev/null +++ b/ld/testsuite/ld-elf/retain3.s @@ -0,0 +1,124 @@ +.text + .global a0 + .section .bss.a0,"aw" + .balign 2 + .type a0, STT_OBJECT + .size a0, 2 +a0: + .zero 2 + .global b0 + .section .bss.b0,"aw" + .balign 2 + .type b0, STT_OBJECT + .size b0, 2 +b0: + .zero 2 + .global c0 + .section .data.c0,"aw" + .balign 2 + .type c0, STT_OBJECT + .size c0, 2 +c0: + .short 1 + .section .bss.sa0,"aw" + .balign 2 + .type sa0, STT_OBJECT + .size sa0, 2 +sa0: + .zero 2 + .section .bss.sb0,"aw" + .balign 2 + .type sb0, STT_OBJECT + .size sb0, 2 +sb0: + .zero 2 + .section .data.sc0,"aw" + .balign 2 + .type sc0, STT_OBJECT + .size sc0, 2 +sc0: + .short 1 + .section .text.foo0,"ax" + .balign 2 + .global foo0 + .type foo0, STT_FUNC +foo0: + .word 0 + .size foo0, .-foo0 + .global a1 + .section .bss.a1,"awR" + .balign 2 + .type a1, STT_OBJECT + .size a1, 2 +a1: + .zero 2 + .global b1 + .section .bss.b1,"awR" + .balign 2 + .type b1, STT_OBJECT + .size b1, 2 +b1: + .zero 2 + .global c1 + .section .data.c1,"awR" + .balign 2 + .type c1, STT_OBJECT + .size c1, 2 +c1: + .short 1 + .section .bss.sa1,"awR" + .balign 2 + .type sa1, STT_OBJECT + .size sa1, 2 +sa1: + .zero 2 + .section .bss.sb1,"awR" + .balign 2 + .type sb1, STT_OBJECT + .size sb1, 2 +sb1: + .zero 2 + .section .data.sc1,"awR" + .balign 2 + .type sc1, STT_OBJECT + .size sc1, 2 +sc1: + .short 1 + .section .text.foo1,"axR" + .balign 2 + .global foo1 + .type foo1, STT_FUNC +foo1: + .word 0 + .size foo1, .-foo1 + .section .text.foo2,"ax" + .balign 2 + .global foo2 + .type foo2, STT_FUNC +foo2: + .word 0 + .size foo2, .-foo2 + .section .bss.lsa,"awR" + .balign 2 + .type lsa.2, STT_OBJECT + .size lsa.2, 2 +lsa.2: + .zero 2 + .section .bss.lsb,"awR" + .balign 2 + .type lsb.1, STT_OBJECT + .size lsb.1, 2 +lsb.1: + .zero 2 + .section .data.lsc,"awR" + .balign 2 + .type lsc.0, STT_OBJECT + .size lsc.0, 2 +lsc.0: + .short 1 +.text + .balign 2 + .global main + .type main, STT_FUNC +main: + .size main, .-main -- 2.28.0 --dplfzjlaziowkcd5--