ELF: Group and sort output note sections by section alignments
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 3 Oct 2018 20:25:16 +0000 (13:25 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 3 Oct 2018 20:25:30 +0000 (13:25 -0700)
To support putting all adjacent SHT_NOTE sections with the same section
alignment into a single PT_NOTE segment, lang_insert_orphan must group
and sort output note sections by section alignments in both output
section list as well as output section statement list.

PR ld/23658
* ldlang.c (lang_insert_orphan): Group and sort output note
sections by section alignments.

ld/ChangeLog
ld/ldlang.c

index 81d2ce4e6617e56474ac051b3d91a038c6b36e76..f17a8f27d8a9135a1cdee20a25f7bbdd628177b0 100644 (file)
@@ -1,3 +1,9 @@
+2018-10-03  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/23658
+       * ldlang.c (lang_insert_orphan): Group and sort output note
+       sections by section alignments.
+
 2018-09-25  Eric Botcazou  <ebotcazou@adacore.com>
 
        * testsuite/ld-elf/pr14156b.d: Adjust for extra symbols.
index 1ac5eb1ee2d9f9ceafa09cb5855b4263589992a1..1a277871932c1870c9474508284c8a04bc9db7c3 100644 (file)
@@ -1875,6 +1875,7 @@ lang_insert_orphan (asection *s,
   if (after != NULL && os->bfd_section != NULL)
     {
       asection *snew, *as;
+      bfd_boolean place_after = place->stmt == NULL;
 
       snew = os->bfd_section;
 
@@ -1912,6 +1913,142 @@ lang_insert_orphan (asection *s,
          /* Now tack it back on in the right place.  */
          bfd_section_list_append (link_info.output_bfd, snew);
        }
+      else if ((bfd_get_flavour (link_info.output_bfd)
+               == bfd_target_elf_flavour)
+              && (bfd_get_flavour (s->owner)
+                  == bfd_target_elf_flavour)
+              && ((elf_section_type (s) == SHT_NOTE
+                   && (s->flags & SEC_LOAD) != 0)
+                  || (elf_section_type (as) == SHT_NOTE
+                      && (as->flags & SEC_LOAD) != 0)))
+       {
+         /* Make sure that output note sections are grouped and sorted
+            by alignments when inserting a note section or insert a
+            section after a note section,  */
+         asection *sec;
+         /* A specific section after which the output note section
+            should be placed.  */
+         asection *after_sec;
+         /* True if we need to insert the orphan section after a
+            specific section to maintain output note section order.  */
+         bfd_boolean after_sec_note;
+
+         /* Group and sort output note section by alignments in
+            ascending order.  */
+         after_sec = NULL;
+         if (elf_section_type (s) == SHT_NOTE
+             && (s->flags & SEC_LOAD) != 0)
+           {
+             /* Search forward for the last output note section
+                with equal or larger alignments.  */
+             asection *first_note = NULL;
+
+             for (sec = as;
+                  (sec != NULL
+                   && !bfd_is_abs_section (sec));
+                  sec = sec->next)
+               if (sec != snew
+                   && elf_section_type (sec) == SHT_NOTE
+                   && (sec->flags & SEC_LOAD) != 0)
+                 {
+                   if (!first_note)
+                     first_note = sec;
+                   if (sec->alignment_power >= s->alignment_power)
+                     after_sec = sec;
+                 }
+
+             if (after_sec)
+               after_sec_note = TRUE;
+             else
+               {
+                 /* Search backward for the first output note section
+                    as well as the last output note section with equal
+                    or larger alignments.  */
+                 after_sec = NULL;
+                 for (sec = as;
+                      (sec != NULL
+                       && !bfd_is_abs_section (sec));
+                      sec = sec->prev)
+                   if (sec != snew
+                       && elf_section_type (sec) == SHT_NOTE
+                       && (sec->flags & SEC_LOAD) != 0)
+                     {
+                       first_note = sec;
+                       if (!after_sec
+                           && sec->alignment_power >= s->alignment_power)
+                         after_sec = sec;
+                     }
+
+                 /* If this will be the first note section, it can be
+                    placed at the default location.  */
+                 after_sec_note = first_note != NULL;
+                 if (after_sec == NULL && after_sec_note)
+                   {
+                     /* If all output note sections have smaller
+                        alignments, place the section before all
+                        output note sections.  AFTER_SEC will be
+                        NULL if FIRST_NOTE is the first output
+                        section.  */
+                     after_sec = first_note->prev;
+                   }
+               }
+           }
+         else
+           {
+             /* Don't place non-note sections in the middle of note
+                sections.  */
+             after_sec_note = TRUE;
+             after_sec = as;
+             for (sec = as->next;
+                  (sec != NULL
+                   && !bfd_is_abs_section (sec));
+                  sec = sec->next)
+               if (elf_section_type (sec) == SHT_NOTE
+                   && (sec->flags & SEC_LOAD) != 0)
+                 after_sec = sec;
+           }
+
+         if (after_sec_note)
+           {
+             if (after_sec)
+               {
+                 /* Insert OS after AFTER_SEC output statement.  */
+                 lang_output_section_statement_type *stmt;
+                 for (stmt = after;
+                      stmt != NULL;
+                      stmt = stmt->next)
+                   if (stmt->bfd_section == after_sec)
+                     {
+                       place_after = TRUE;
+                       after = stmt;
+                       break;
+                     }
+               }
+
+             if (after_sec == NULL || after_sec->next != snew)
+               {
+                 /* Unlink the section.  */
+                 bfd_section_list_remove (link_info.output_bfd, snew);
+
+                 /* Place SNEW after AFTER_SEC.  If AFTER_SEC is NULL,
+                    prepend SNEW.  */
+                 if (after_sec)
+                   bfd_section_list_insert_after (link_info.output_bfd,
+                                                  after_sec, snew);
+                 else
+                   bfd_section_list_prepend (link_info.output_bfd, snew);
+               }
+           }
+         else if (as != snew && as->prev != snew)
+           {
+             /* Unlink the section.  */
+             bfd_section_list_remove (link_info.output_bfd, snew);
+
+             /* Now tack it back on in the right place.  */
+             bfd_section_list_insert_before (link_info.output_bfd,
+                                             as, snew);
+           }
+       }
       else if (as != snew && as->prev != snew)
        {
          /* Unlink the section.  */
@@ -1938,7 +2075,8 @@ lang_insert_orphan (asection *s,
        {
          lang_output_section_statement_type *newly_added_os;
 
-         if (place->stmt == NULL)
+         /* Place OS after AFTER if AFTER_NOTE is TRUE.  */
+         if (place_after)
            {
              lang_statement_union_type **where = insert_os_after (after);