]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Always ensure that the PCC bounds are precise for Morello
authorMatthew Malcomson <matthew.malcomson@arm.com>
Mon, 21 Feb 2022 13:18:23 +0000 (13:18 +0000)
committerMatthew Malcomson <matthew.malcomson@arm.com>
Mon, 21 Feb 2022 13:19:15 +0000 (13:19 +0000)
The mechanism by which we were ensuring the PCC bounds were made precise
for Morello happened to only work if there were some sections which
needed to be made precisely representable for Morello individually.
This was because we included the PCC bounds calculation in the `queue`
iteration that only iterated over adjustments to individual sections.

Here we move the PCC bounds calculation to after the `queue` iteration
so that we always perform this operation.

We suspect the original implementation was chosen to ensure that padding
was added in sequential section ordering.  This ordering seems to have
been in order to ensure that padding at one position would not adjust
sections that had already been adjusted (because padding one section
changes the location of the sections after it).

We have already found in previous patches that this approach was not
sufficient to ensure an adjustment being permanent.  The alignment
change to the first section that the PCC should span can change the
location of all sections after it, or the linker can simply have extra
space before .text that it removes on a call to layout_sections_again.

In the patches to fix those problems, we have adjusted the code here to
represent the padding in a way that stays stable across changes.  That
has meant that the iteration in VMA order is no longer necessary, and
that means that our movement of the PCC bounds calculation to outside of
the `queue` iteration loop can be performed.

One interesting part of this adjustment is that given a set of sections,
the length of memory that they span can change if the first sections
alignment is adjusted.
For example, if we have the below:
  sectionA   VMA 0xf   size 0x1   alignment 0x1
  sectionB   VMA 0x10  size 0x10  alignment 0x10
Then aligning sectionA to 0x10 gives the below:
  sectionA   VMA 0x10  size 0x1   alignment 0x10
  sectionB   VMA 0x20  size 0x10  alignment 0x10
The total range of the first case is [0xf -> 0x20] for a size of 0x11
and of the second case it is [0x10 -> 0x30] for a size of 0x20.

This means that we should handle the alignment adjustment for the PCC
bounds first, and must handle it in a loop to ensure that we handle the
case that this change in length requires an extra alignment.
Only then do we know the size that we want to add into the last section
in the range so that the entire bounds are correct.

bfd/elfnn-aarch64.c
ld/testsuite/ld-aarch64/morello-sec-always-align.d

index b8caf1215efb8917d66ea9a75ccb8c52e47048df..6b5ad49077f29d5c673fb2b635cd5e9d9567c4b1 100644 (file)
@@ -4899,6 +4899,7 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
   struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
   bfd_vma low = (bfd_vma) -1, high = 0;
   bfd *input_bfd;
+  unsigned align = 0;
 
   htab->layout_sections_again = layout_sections_again;
 
@@ -5030,7 +5031,6 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
      and whether they need to be padded or aligned.  */
   while (queue)
     {
-      unsigned align = 0;
       bfd_vma padding = 0;
 
       low = queue->sec->vma;
@@ -5049,30 +5049,6 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
       if (queue->sec->alignment_power < align)
        queue->sec->alignment_power = align;
 
-      /* If we have crossed all sections within the PCC range, set up alignment
-         and padding for the PCC range.  */
-      if (pcc_high_sec != NULL && pcc_low_sec != NULL
-         && (queue->next == NULL
-             || queue->next->sec->vma > pcc_high_sec->vma))
-       {
-         /* Layout sections since it affects the final range of PCC.  */
-         (*htab->layout_sections_again) ();
-
-         pcc_low = pcc_low_sec->vma;
-         pcc_high = pcc_high_sec->vma + pcc_high_sec->size + padding;
-
-         if (!c64_valid_cap_range (&pcc_low, &pcc_high, &align))
-           {
-             bfd_vma current_length =
-               (pcc_high_sec->vma + pcc_high_sec->size) - pcc_low_sec->vma;
-             bfd_vma desired_length = (pcc_high - pcc_low);
-             padding = desired_length - current_length;
-             c64_pad_section (pcc_high_sec, padding);
-           }
-         if (pcc_low_sec->alignment_power < align)
-           pcc_low_sec->alignment_power = align;
-       }
-
       (*htab->layout_sections_again) ();
 
       struct sec_change_queue *queue_free = queue;
@@ -5081,10 +5057,56 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
       free (queue_free);
     }
 
-  if (pcc_low_sec)
-    {
-      if (!pcc_high_sec)
-       abort ();
+  /* Always ensure that the PCC range has precise Morello bounds.
+     Whether or not there are any individual sections that need to be adjusted
+     to give precise bounds.  */
+  if (pcc_low_sec != NULL)
+    {
+      BFD_ASSERT (pcc_high_sec);
+
+      bfd_vma pcc_low_tmp;
+      bfd_vma pcc_high_tmp;
+
+      /* We have to be a little careful about the padding we introduce.  The
+        padding we could calculate here may not be the padding that we would
+        want after the very first section in the PCC bounds has been aligned
+        properly.  That change in the start address propagated through a few
+        different sections with their own alignment requirements can easily
+        change the length of the region we want the PCC to span.
+        Even more tricky, that change in length could change the alignment we
+        want.  We don't proove that the alignment requirement converges,
+        but believe that it should (there is only so much space that existing
+        alignment requirements could trigger to be added -- a section with an
+        alignment requirement of 16 can only really add 15 bytes to the
+        length).  */
+      bfd_boolean valid_range = FALSE;
+      while (TRUE) {
+         pcc_low_tmp = pcc_low_sec->vma;
+         pcc_high_tmp = pcc_high_sec->vma + pcc_high_sec->size;
+         valid_range =
+           c64_valid_cap_range (&pcc_low_tmp, &pcc_high_tmp, &align);
+         if (pcc_low_sec->alignment_power >= align)
+           break;
+         pcc_low_sec->alignment_power = align;
+         (*htab->layout_sections_again) ();
+      }
+
+      /* We have calculated the bottom and top address that we want in the
+        above call to c64_valid_cap_range.  We have also aligned the lowest
+        section in the PCC range to where we want it.  Just have to add the
+        padding remaining if needs be.  */
+      if (!valid_range)
+       {
+         BFD_ASSERT (pcc_low_tmp == pcc_low_sec->vma);
+         bfd_vma current_length =
+           (pcc_high_sec->vma + pcc_high_sec->size) - pcc_low_sec->vma;
+         bfd_vma desired_length = (pcc_high_tmp - pcc_low_tmp);
+         bfd_vma padding = desired_length - current_length;
+         c64_pad_section (pcc_high_sec, padding);
+       }
+      /* Layout sections since it affects the final range of PCC.  */
+      (*htab->layout_sections_again) ();
+
       pcc_low = pcc_low_sec->vma;
       pcc_high = pcc_high_sec->vma + pcc_high_sec->size;
     }
index f46ebdfb821eac114f84dee8b385d1ab1648af30..9e69e1c3d1ecdf79cc01d393ae0fd2d83e06a895 100644 (file)
@@ -13,7 +13,7 @@ Idx Name          Size      VMA               LMA               File off  Algn
                   CONTENTS, ALLOC, LOAD, DATA
   3 \.got\.plt      00000030  00000000000081b0  [0-9a-f]+  [0-9a-f]+  2\*\*4
                   CONTENTS, ALLOC, LOAD, DATA
-  4 \.rela\.dyn     000000b8  00000000000081e0  [0-9a-f]+  [0-9a-f]+  2\*\*3
+  4 \.rela\.dyn     00000030  00000000000081e0  [0-9a-f]+  [0-9a-f]+  2\*\*3
                   CONTENTS, ALLOC, LOAD, READONLY, DATA
 #pass