aboutsummaryrefslogtreecommitdiff
path: root/ld/ldlang.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-10-03 13:25:16 -0700
committerH.J. Lu <hjl.tools@gmail.com>2018-10-03 13:25:30 -0700
commit1887ae7304dced5b081ee200a9e27fbb8f180143 (patch)
treea17cacf4b0450b002ef0c325e97b2efbc973b513 /ld/ldlang.c
parent23e463ed7c0d289e2291aaefd576bf02efd98df8 (diff)
downloadgdb-1887ae7304dced5b081ee200a9e27fbb8f180143.zip
gdb-1887ae7304dced5b081ee200a9e27fbb8f180143.tar.gz
gdb-1887ae7304dced5b081ee200a9e27fbb8f180143.tar.bz2
ELF: Group and sort output note sections by section alignments
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.
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r--ld/ldlang.c140
1 files changed, 139 insertions, 1 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 1ac5eb1..1a27787 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -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);