From c212f39d9a82c6c09f4a1447d9d2ff09843827c5 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Wed, 16 Feb 2022 17:41:23 +0000 Subject: [PATCH] ld: Support customized output section type 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. --- bfd/ChangeLog | 10 ++++ bfd/bfd-in2.h | 7 ++- bfd/elf.c | 4 +- bfd/section.c | 4 +- ld/ChangeLog | 13 +++++ ld/NEWS | 3 + ld/ld.texi | 16 +++++- ld/ldgram.y | 11 ++-- ld/ldlang.c | 55 +++++++++++++++++-- ld/ldlang.h | 7 ++- ld/ldlex.l | 1 + ld/mri.c | 4 +- .../ld-scripts/output-section-types.d | 18 +++--- .../ld-scripts/output-section-types.t | 7 +++ 14 files changed, 131 insertions(+), 29 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 97026b01389..e959a787d9b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,13 @@ +2022-02-16 Fangrui Song + Nick Clifton + + 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 * bfd.c (bfd_set_gp_value): Remove return with expression diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 3b2a4f49a9b..78a0a1dea42 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -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 \ \ } diff --git a/bfd/elf.c b/bfd/elf.c index a67415e76e1..82b53be99f9 100644 --- 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); diff --git a/bfd/section.c b/bfd/section.c index 899438a1c5e..2de7dbf661a 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -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 \ . \ . } . diff --git a/ld/ChangeLog b/ld/ChangeLog index 9f7a1ac1b64..63c9c71be4f 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,16 @@ +2022-02-16 Fangrui Song + Nick Clifton + + 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 * po/fr.po: Updated French translation. diff --git a/ld/NEWS b/ld/NEWS index dbb402d1f8a..a498abaf0f9 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -1,5 +1,8 @@ -*- text -*- +* 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 diff --git a/ld/ld.texi b/ld/ld.texi index fc75e9b3625..d57e9221410 100644 --- a/ld/ld.texi +++ b/ld/ld.texi @@ -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 diff --git a/ld/ldgram.y b/ld/ldgram.y index 11c2f219c05..3a904e39482 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -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 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 ')' diff --git a/ld/ldlang.c b/ld/ldlang.c index 474784c874a..1733f8e65c4 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -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 diff --git a/ld/ldlang.h b/ld/ldlang.h index 0d057c9bee9..95f6e468b30 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -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 diff --git a/ld/ldlex.l b/ld/ldlex.l index 78db16e3a48..c38b46b9336 100644 --- a/ld/ldlex.l +++ b/ld/ldlex.l @@ -323,6 +323,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* "DSECT" { RTOKEN(DSECT); } "COPY" { RTOKEN(COPY); } "INFO" { RTOKEN(INFO); } +"TYPE" { RTOKEN(TYPE); } "ONLY_IF_RO" { RTOKEN(ONLY_IF_RO); } "ONLY_IF_RW" { RTOKEN(ONLY_IF_RW); } "SPECIAL" { RTOKEN(SPECIAL); } diff --git a/ld/mri.c b/ld/mri.c index b428ab0d0bf..5749870ef1e 100644 --- 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; diff --git a/ld/testsuite/ld-scripts/output-section-types.d b/ld/testsuite/ld-scripts/output-section-types.d index ab124fa4dd7..2ecacaba57d 100644 --- a/ld/testsuite/ld-scripts/output-section-types.d +++ b/ld/testsuite/ld-scripts/output-section-types.d @@ -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 diff --git a/ld/testsuite/ld-scripts/output-section-types.t b/ld/testsuite/ld-scripts/output-section-types.t index d8fdfda1a03..18fc5c11980 100644 --- a/ld/testsuite/ld-scripts/output-section-types.t +++ b/ld/testsuite/ld-scripts/output-section-types.t @@ -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/ : { *(*) } } -- 2.30.2