ld: Support customized output section type
authorFangrui Song <maskray@google.com>
Wed, 16 Feb 2022 17:41:23 +0000 (17:41 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 16 Feb 2022 17:41:23 +0000 (17:41 +0000)
bfd/
    PR ld/28841
    * bfd-in2.h (struct bfd_section): Add type.
    (discarded_section): Add field.
    * elf.c (elf_fake_sections): Handle bfd_section::type.
    * section.c (BFD_FAKE_SECTION): Add field.
    * mri.c (mri_draw_tree): Update function call.

ld/
    PR ld/28841
    * ld.texi: Document new output section type.
    * ldlex.l: Add new token TYPE.
    * ldgram.y: Handle TYPE=exp.
    * ldlang.h: Add type_section to list of section types.
    * ldlang.c (lang_add_section): Handle type_section.
    (map_input_to_output_sections): Handle type_section.
    * testsuite/ld-scripts/output-section-types.t: Add tests.
    * testsuite/ld-scripts/output-section-types.d: Update.

14 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf.c
bfd/section.c
ld/ChangeLog
ld/NEWS
ld/ld.texi
ld/ldgram.y
ld/ldlang.c
ld/ldlang.h
ld/ldlex.l
ld/mri.c
ld/testsuite/ld-scripts/output-section-types.d
ld/testsuite/ld-scripts/output-section-types.t

index 97026b0138960558d5f59d281b946c63074ab2d8..e959a787d9b1dc97753575e46379ceac47530b3e 100644 (file)
@@ -1,3 +1,13 @@
+2022-02-16  Fangrui Song  <maskray@google.com>
+       Nick Clifton  <nickc@redhat.com>
+
+       PR ld/28841
+       * bfd-in2.h (struct bfd_section): Add type.
+       (discarded_section): Add field.
+       * elf.c (elf_fake_sections): Handle bfd_section::type.
+       * section.c (BFD_FAKE_SECTION): Add field.
+       * mri.c (mri_draw_tree): Update function call.
+
 2022-02-11  Michael Forney  <mforney@mforney.org>
 
         * bfd.c (bfd_set_gp_value): Remove return with expression
index 3b2a4f49a9b4f541625643ff57473a8e48d3b001..78a0a1dea420f0a35752e7485eb549f8524293ab 100644 (file)
@@ -1170,6 +1170,9 @@ typedef struct bfd_section
     This is used when support for non-contiguous memory regions is enabled.  */
  struct bfd_section *already_assigned;
 
+  /* Explicitly specified section type, if non-zero. */
+  unsigned int type;
+
 } asection;
 
 /* Relax table contains information about instructions which can
@@ -1352,8 +1355,8 @@ discarded_section (const asection *sec)
   /* symbol,                    symbol_ptr_ptr,                     */ \
      (struct bfd_symbol *) SYM, &SEC.symbol,                           \
                                                                        \
-  /* map_head, map_tail, already_assigned                           */ \
-     { NULL }, { NULL }, NULL                                          \
+  /* map_head, map_tail, already_assigned, type                     */ \
+     { NULL }, { NULL }, NULL, 0                                       \
                                                                        \
     }
 
index a67415e76e1d37b56f6844a0605eae4ce2e6880f..82b53be99f99f71974bab96b9c219cb1bf5e2d43 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -3280,7 +3280,9 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
 
   /* If the section type is unspecified, we set it based on
      asect->flags.  */
-  if ((asect->flags & SEC_GROUP) != 0)
+  if (asect->type != 0)
+    sh_type = asect->type;
+  else if ((asect->flags & SEC_GROUP) != 0)
     sh_type = SHT_GROUP;
   else
     sh_type = bfd_elf_get_default_section_type (asect->flags);
index 899438a1c5e6da683c256dac178886d0f84133f0..2de7dbf661ac7c99d0e11a5c1dab510a680fb3af 100644 (file)
@@ -737,8 +737,8 @@ CODE_FRAGMENT
 .  {* symbol,                    symbol_ptr_ptr,                     *}        \
 .     (struct bfd_symbol *) SYM, &SEC.symbol,                          \
 .                                                                      \
-.  {* map_head, map_tail, already_assigned                           *}        \
-.     { NULL }, { NULL }, NULL                                         \
+.  {* map_head, map_tail, already_assigned, type                     *}        \
+.     { NULL }, { NULL }, NULL, 0                                              \
 .                                                                      \
 .    }
 .
index 9f7a1ac1b646f353f3eb425088ef4387c0f7c8db..63c9c71be4fa042da87bd116a0f770149f31266b 100644 (file)
@@ -1,3 +1,16 @@
+2022-02-16  Fangrui Song  <maskray@google.com>
+       Nick Clifton  <nickc@redhat.com>
+
+       PR ld/28841
+       * ld.texi: Document new output section type.
+       * ldlex.l: Add new token TYPE.
+       * ldgram.y: Handle TYPE=exp and READONLY (TYPE=exp).
+       * ldlang.h: Add type_section to list of section types.
+       * ldlang.c (lang_add_section): Handle type_section.
+       (map_input_to_output_sections): Handle type_section.
+       * testsuite/ld-scripts/output-section-types.t: Add tests.
+       * testsuite/ld-scripts/output-section-types.d: Update.
+
 2022-02-02  Nick Clifton  <nickc@redhat.com>
 
        * po/fr.po: Updated French translation.
diff --git a/ld/NEWS b/ld/NEWS
index dbb402d1f8ad6127f8e34736ea4265f23467bf6c..a498abaf0f9beba85081b6ce86f2ab6075ac0dd6 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* TYPE=<type> is now supported in an output section description to set the
+  section type value.
+
 Changes in 2.38:
 
 * Add -z pack-relative-relocs/-z no pack-relative-relocs to x86 ELF
index fc75e9b36256d92ad530bc6f700f9e19c08463d5..d57e92214108c7cb466c575e7226bdba05b43edf 100644 (file)
@@ -5483,13 +5483,23 @@ loaded into memory when the program is run.
 @item READONLY
 The section should be marked as read-only.
 @item DSECT
-@itemx COPY
-@itemx INFO
-@itemx OVERLAY
+@item COPY
+@item INFO
+@item OVERLAY
 These type names are supported for backward compatibility, and are
 rarely used.  They all have the same effect: the section should be
 marked as not allocatable, so that no memory is allocated for the
 section when the program is run.
+@item TYPE = @var{type}
+Set the section type to the integer @var{type}. When generating an ELF
+output file, type names @code{SHT_PROGBITS}, @code{SHT_STRTAB},
+@code{SHT_NOTE}, @code {SHT_NOBITS}, @code{SHT_INIT_ARRAY},
+@code{SHT_FINI_ARRAY}, and @code{SHT_PREINIT_ARRAY} are also allowed
+for @var{type}.  It is the user's responsibility to ensure that any
+special requirements of the section type are met.
+@item READONLY ( TYPE = @var{type} )
+This form of the syntax combines the @var{READONLY} type with the
+type specified by @var{type}.
 @end table
 
 @kindex NOLOAD
index 11c2f219c05d0c3b8f9cd2579faf41a831e4a396..3a904e39482640d62fda6fa3db01a52980c48191 100644 (file)
@@ -47,6 +47,7 @@
 #endif
 
 static enum section_type sectype;
+static etree_type *sectype_value;
 static lang_memory_region_type *region;
 
 static bool ldgram_had_keep = false;
@@ -139,6 +140,7 @@ static int error_index;
 %token LD_FEATURE
 %token NOLOAD DSECT COPY INFO OVERLAY
 %token READONLY
+%token TYPE
 %token DEFINED TARGET_K SEARCH_DIR MAP ENTRY
 %token <integer> NEXT
 %token SIZEOF ALIGNOF ADDR LOADADDR MAX_K MIN_K
@@ -1058,9 +1060,8 @@ section:  NAME
                        {
                          ldlex_popstate ();
                          ldlex_wild ();
-                         lang_enter_output_section_statement($1, $3, sectype,
-                                                             $5, $7, $4,
-                                                             $8, $6);
+                         lang_enter_output_section_statement ($1, $3, sectype,
+                                       sectype_value, $5, $7, $4, $8, $6);
                        }
                '{'
                statement_list_opt
@@ -1130,8 +1131,10 @@ type:
        |  COPY    { sectype = noalloc_section; }
        |  INFO    { sectype = noalloc_section; }
        |  OVERLAY { sectype = noalloc_section; }
+        |  READONLY '(' TYPE '=' exp ')' { sectype = typed_readonly_section; sectype_value = $5; }
        |  READONLY { sectype = readonly_section; }
-       ;
+       |  TYPE '=' exp { sectype = type_section; sectype_value = $3; }
+        ;
 
 atype:
                '(' type ')'
index 474784c874a44a44b14fadc533b7df7694b37137..1733f8e65c4d20786a5b7ad3eb896f378c3781ed 100644 (file)
@@ -1891,8 +1891,8 @@ lang_insert_orphan (asection *s,
     address = exp_intop (0);
 
   os_tail = (lang_output_section_statement_type **) lang_os_list.tail;
-  os = lang_enter_output_section_statement (secname, address, normal_section,
-                                           NULL, NULL, NULL, constraint, 0);
+  os = lang_enter_output_section_statement (
+      secname, address, normal_section, 0, NULL, NULL, NULL, constraint, 0);
 
   if (add_child == NULL)
     add_child = &os->children;
@@ -2635,10 +2635,12 @@ lang_add_section (lang_statement_list_type *ptr,
     case normal_section:
     case overlay_section:
     case first_overlay_section:
+    case type_section:
       break;
     case noalloc_section:
       flags &= ~SEC_ALLOC;
       break;
+    case typed_readonly_section:
     case readonly_section:
       flags |= SEC_READONLY;
       break;
@@ -4209,6 +4211,7 @@ map_input_to_output_sections
     {
       lang_output_section_statement_type *tos;
       flagword flags;
+      unsigned int type = 0;
 
       switch (s->header.type)
        {
@@ -4264,6 +4267,42 @@ map_input_to_output_sections
            case readonly_section:
              flags |= SEC_READONLY;
              break;
+           case typed_readonly_section:
+             flags |= SEC_READONLY;
+             /* Fall through.  */
+           case type_section:
+             if (os->sectype_value->type.node_class == etree_name
+                 && os->sectype_value->type.node_code == NAME)
+               {
+                 const char *name = os->sectype_value->name.name;
+                 if (strcmp (name, "SHT_PROGBITS") == 0)
+                   type = SHT_PROGBITS;
+                 else if (strcmp (name, "SHT_STRTAB") == 0)
+                   type = SHT_STRTAB;
+                 else if (strcmp (name, "SHT_NOTE") == 0)
+                   type = SHT_NOTE;
+                 else if (strcmp (name, "SHT_NOBITS") == 0)
+                   type = SHT_NOBITS;
+                 else if (strcmp (name, "SHT_INIT_ARRAY") == 0)
+                   type = SHT_INIT_ARRAY;
+                 else if (strcmp (name, "SHT_FINI_ARRAY") == 0)
+                   type = SHT_FINI_ARRAY;
+                 else if (strcmp (name, "SHT_PREINIT_ARRAY") == 0)
+                   type = SHT_PREINIT_ARRAY;
+                 else
+                   einfo (_ ("%F%P: invalid type for output section `%s'\n"),
+                          os->name);
+               }
+            else
+              {
+                exp_fold_tree_no_dot (os->sectype_value);
+                if (expld.result.valid_p)
+                  type = expld.result.value;
+                else
+                  einfo (_ ("%F%P: invalid type for output section `%s'\n"),
+                         os->name);
+              }
+             break;
            case noload_section:
              if (bfd_get_flavour (link_info.output_bfd)
                  == bfd_target_elf_flavour)
@@ -4276,6 +4315,7 @@ map_input_to_output_sections
            init_os (os, flags | SEC_READONLY);
          else
            os->bfd_section->flags |= flags;
+         os->bfd_section->type = type;
          break;
        case lang_input_section_enum:
          break;
@@ -7506,6 +7546,7 @@ lang_output_section_statement_type *
 lang_enter_output_section_statement (const char *output_section_statement_name,
                                     etree_type *address_exp,
                                     enum section_type sectype,
+                                    etree_type *sectype_value,
                                     etree_type *align,
                                     etree_type *subalign,
                                     etree_type *ebase,
@@ -7523,10 +7564,12 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
       os->addr_tree = address_exp;
     }
   os->sectype = sectype;
-  if (sectype != noload_section)
-    os->flags = SEC_NO_FLAGS;
-  else
+  if (sectype == type_section || sectype == typed_readonly_section)
+    os->sectype_value = sectype_value;
+  else if (sectype == noload_section)
     os->flags = SEC_NEVER_LOAD;
+  else
+    os->flags = SEC_NO_FLAGS;
   os->block_value = 1;
 
   /* Make next things chain into subchain of this.  */
@@ -8842,7 +8885,7 @@ lang_enter_overlay_section (const char *name)
   etree_type *size;
 
   lang_enter_output_section_statement (name, overlay_vma, overlay_section,
-                                      0, overlay_subalign, 0, 0, 0);
+                                      0, 0, overlay_subalign, 0, 0, 0);
 
   /* If this is the first section, then base the VMA of future
      sections on this one.  This will work correctly even if `.' is
index 0d057c9bee9b40cf28fc410dee6ca715f97e569f..95f6e468b300c688a764df2c56cc1cf35702c5ce 100644 (file)
@@ -122,7 +122,9 @@ enum section_type
   overlay_section,
   noload_section,
   noalloc_section,
-  readonly_section
+  type_section,
+  readonly_section,
+  typed_readonly_section
 };
 
 /* This structure holds a list of program headers describing
@@ -166,6 +168,7 @@ typedef struct lang_output_section_statement_struct
   int constraint;
   flagword flags;
   enum section_type sectype;
+  etree_type *sectype_value;
   unsigned int processed_vma : 1;
   unsigned int processed_lma : 1;
   unsigned int all_input_readonly : 1;
@@ -545,7 +548,7 @@ extern void lang_add_output
   (const char *, int from_script);
 extern lang_output_section_statement_type *lang_enter_output_section_statement
   (const char *, etree_type *, enum section_type, etree_type *, etree_type *,
-   etree_type *, int, int);
+   etree_type *, etree_type *, int, int);
 extern void lang_final
   (void);
 extern void lang_relax_sections
index 78db16e3a4894a94f6b1147883cca9a66251fa35..c38b46b933673a1551e93786156a8d66561c198b 100644 (file)
@@ -323,6 +323,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <EXPRESSION>"DSECT"                    { RTOKEN(DSECT); }
 <EXPRESSION>"COPY"                     { RTOKEN(COPY); }
 <EXPRESSION>"INFO"                     { RTOKEN(INFO); }
+<EXPRESSION>"TYPE"                     { RTOKEN(TYPE); }
 <SCRIPT,EXPRESSION>"ONLY_IF_RO"                { RTOKEN(ONLY_IF_RO); }
 <SCRIPT,EXPRESSION>"ONLY_IF_RW"                { RTOKEN(ONLY_IF_RW); }
 <SCRIPT,EXPRESSION>"SPECIAL"           { RTOKEN(SPECIAL); }
index b428ab0d0bf1a2176ac4e8633c805f0b102fda73..5749870ef1ea73344bd2a53c1f7e5cfe1dd379eb 100644 (file)
--- a/ld/mri.c
+++ b/ld/mri.c
@@ -210,8 +210,8 @@ mri_draw_tree (void)
            base = p->vma ? p->vma : exp_nameop (NAME, ".");
 
          lang_enter_output_section_statement (p->name, base,
-                                              p->ok_to_load ? normal_section : noload_section,
-                                              align, subalign, NULL, 0, 0);
+           p->ok_to_load ? normal_section : noload_section, 0,
+           align, subalign, NULL, 0, 0);
          base = 0;
          tmp = (struct wildcard_list *) xmalloc (sizeof *tmp);
          tmp->next = NULL;
index ab124fa4dd7d3e6c2e37cd7028d201a9e0214543..2ecacaba57d88ce972ce30143248851035bcecac 100644 (file)
@@ -1,13 +1,17 @@
 #ld: -Toutput-section-types.t
 #source: align2a.s
-#objdump: -h
+#readelf: -S --wide
 #target: [is_elf_format]
 
 #...
-  . \.rom.*
-[      ]+ALLOC, READONLY
-  . \.ro.*
-[      ]+CONTENTS, ALLOC, LOAD, READONLY, DATA
-  . \.over.*
-[      ]+CONTENTS, READONLY
+.* .rom          +NOBITS        +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +00 +A +0 +0 +[1248]
+.* .ro           +PROGBITS      +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +00 +A +0 +0 +[1248]
+.* .over         +PROGBITS      +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +00  + +0 +0 +[1248]
+.* progbits      +PROGBITS      +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +00 +A +0 +0 +[1248]
+.* strtab        +STRTAB        +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +00 +A +0 +0 +[1248]
+.* note          +NOTE          +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +00 +A +0 +0 +[1248]
+.* init_array    +INIT_ARRAY    +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +0[48] +A +0 +0 +[1248]
+.* fini_array    +FINI_ARRAY    +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +0[48] +A +0 +0 +[1248]
+.* preinit_array +PREINIT_ARRAY +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +0[48] +A +0 +0 +[1248]
+.* .ro.note      +NOTE          +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +00 +A +0 +0 +[1248]
 #pass
index d8fdfda1a0333d1f40382f1e68cf2d29de86a3ba..18fc5c119805fa50e8e1931a8886909417b49de8 100644 (file)
@@ -2,6 +2,13 @@ SECTIONS {
   .rom  (NOLOAD)   : { LONG(1234); }
   .ro   (READONLY) : { LONG(5678); }
   .over (OVERLAY)  : { LONG(0123); }
+  progbits (TYPE=SHT_PROGBITS) : { BYTE(1) }
+  strtab (TYPE = SHT_STRTAB) : { BYTE(0) }
+  note (TYPE =SHT_NOTE) : { BYTE(8) }
+  init_array (TYPE= 14) : { QUAD(14) }
+  fini_array ( TYPE=SHT_FINI_ARRAY) : { QUAD(15) }
+  preinit_array (TYPE=SHT_PREINIT_ARRAY ) : { QUAD(16) }
+  .ro.note   (READONLY (TYPE=SHT_NOTE)) : { LONG(5678); }
   /DISCARD/        : { *(*) }
 
 }