]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Pad and align sections in more cases
authorMatthew Malcomson <matthew.malcomson@arm.com>
Mon, 21 Feb 2022 13:18:25 +0000 (13:18 +0000)
committerMatthew Malcomson <matthew.malcomson@arm.com>
Mon, 21 Feb 2022 13:19:17 +0000 (13:19 +0000)
Before this change individual sections would not be padded or aligned if
there was no C64 code or if there were no capability GOT relocations in
the binary.  This meant that if we had a data-only PURECAP shared
library with a CAPINIT relocation in it pointing at something, then the
section that relocation pointed into would not be padded accordingly.

This patch changes this so that we look for sections which may need
individual padding if we see the PURECAP elf header flag, and if there
is a `srelcaps` section (i.e. the RELATIVE capability relocations).

We keep the behaviour that we do not adjust the size of sections unless
there is a static relocation pointing at a zero-sized symbol at that
section.  That is, we do not make any adjustment to try and handle
section padding in the case where other binaries would dynamically link
against such symbols.  We do this since the "symbol pointing to section
start implies spanning entire section" decision is a hack to enable some
linker script uses, and we don't want to extend it without a known
motivating example.

Finally, this patch ignores padding PCC bounds on PURECAP binaries if
there is no C64 code in this binary, but ensures that the PCC bounds are
made precise even if there are no static relocations in the file.
We could still get the current PCC and offset it using `adr` if there
are no static relocations, but without there being any C64 code there
will be no PCC to bound and hence we don't need the bounds on a
hypothetical PCC to be precise.

bfd/elfnn-aarch64.c

index 6b5ad49077f29d5c673fb2b635cd5e9d9567c4b1..071532f480bc88b25ed3e69c5d4e174a74531441 100644 (file)
@@ -4895,15 +4895,20 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
                           void (*c64_pad_section) (asection *, bfd_vma),
                           void (*layout_sections_again) (void))
 {
-  asection *sec, *pcc_low_sec = NULL, *pcc_high_sec = NULL;
+  asection *sec;
   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;
 
-  if (!htab->c64_output)
+  /* If this is not a PURECAP binary, and has no C64 code in it, then this is
+     just a stock AArch64 binary and the section padding is not necessary.
+     We can have PURECAP shared libraries that are data-only, so just checking
+     if there is C64 code in this executable is not enough.  We can have HYBRID
+     binaries, so just checking for PURECAP is not enough.  */
+  if (!(htab->c64_output
+       || (elf_elfheader (output_bfd)->e_flags & EF_AARCH64_CHERI_PURECAP)))
     return;
 
   struct sec_change_queue *queue = NULL;
@@ -4912,7 +4917,18 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
      defined and ldscript defined symbols since we set their range to their
      output sections.  */
   for (input_bfd = info->input_bfds;
-       htab->c64_rel && input_bfd != NULL; input_bfd = input_bfd->link.next)
+       /* No point iterating over all relocations to ensure each section that
+         needs to give the bounds for a capability is padded accordingly if
+         there are no capability relocations in the GOT and there are no
+         CAPINIT relocations.
+         N.b. It is possible that when creating a dynamic object a
+         section-spanning symbol could be used by some other executable
+         linking to it when we don't have a relocation to it in the given
+         dynamic library.  Rather than pad every section which has a linker
+         defined symbol pointing into it we choose to allow such use-cases to
+         have sizes which bleed into another section.  */
+       (htab->c64_rel || htab->srelcaps) && input_bfd != NULL;
+       input_bfd = input_bfd->link.next)
     {
       Elf_Internal_Shdr *symtab_hdr;
 
@@ -4987,10 +5003,48 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
        }
     }
 
+  /* Sequentially add alignment and padding as required.  */
+  while (queue)
+    {
+      bfd_vma low = queue->sec->vma;
+      bfd_vma high = queue->sec->vma + queue->sec->size;
+
+      if (!c64_valid_cap_range (&low, &high, &align))
+       {
+         bfd_vma padding = high - low - queue->sec->size;
+         c64_pad_section (queue->sec, padding);
+       }
+      if (queue->sec->alignment_power < align)
+       queue->sec->alignment_power = align;
+
+      (*htab->layout_sections_again) ();
+
+      struct sec_change_queue *queue_free = queue;
+
+      queue = queue->next;
+      free (queue_free);
+    }
+
   /* Next, walk through output sections to find the PCC span and add a padding
      at the end to ensure that PCC bounds don't bleed into neighbouring
      sections.  For now PCC needs to encompass all code sections, .got, .plt
-     and .got.plt.  */
+     and .got.plt.
+     If there is no C64 code in this binary, then we do not need to care about
+     PCC bounds, hence skip this bit.
+     It's tempting to also avoid padding the PCC range when we have no static
+     relocations in this binary, since it would seem that we can never end up
+     trying to access something "outside" the PCC bounds (any PCC bounded
+     capability provided to an outside dynamic object would be sealed by the
+     runtime, and hence can't be offset).  Unfortunately it is still possible,
+     since an `adr c0, 0` gives an unsealed capability to the current code
+     which could then be offset by some other means.
+     While that seems unlikely to happen, having no relocations in a file also
+     seems quite unlikely, so we may as well play it safe.  */
+  if (!htab->c64_output)
+    return;
+
+  bfd_vma low = (bfd_vma) -1, high = 0;
+  asection *pcc_low_sec = NULL, *pcc_high_sec = NULL;
   for (sec = output_bfd->sections; sec != NULL; sec = sec->next)
     {
       /* XXX This is a good place to figure out if there are any readable or
@@ -5025,41 +5079,8 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
 #undef NOT_OP_SECTION
     }
 
-  /* Sequentially add alignment and padding as required.  We also need to
-     account for the PCC-related alignment and padding here since its
-     requirements could change based on the range of sections it encompasses
-     and whether they need to be padded or aligned.  */
-  while (queue)
-    {
-      bfd_vma padding = 0;
-
-      low = queue->sec->vma;
-      high = queue->sec->vma + queue->sec->size;
-
-      if (!c64_valid_cap_range (&low, &high, &align))
-       {
-         padding = high - low - queue->sec->size;
-
-         if (queue->sec != pcc_high_sec)
-           {
-             c64_pad_section (queue->sec, padding);
-             padding = 0;
-           }
-       }
-      if (queue->sec->alignment_power < align)
-       queue->sec->alignment_power = align;
-
-      (*htab->layout_sections_again) ();
-
-      struct sec_change_queue *queue_free = queue;
-
-      queue = queue->next;
-      free (queue_free);
-    }
-
-  /* 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.  */
+  /* Set the PCC range to have precise bounds to ensure that PCC relative loads
+     can not access outside of their given range.  */
   if (pcc_low_sec != NULL)
     {
       BFD_ASSERT (pcc_high_sec);
@@ -5073,12 +5094,11 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
         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).  */
+        Also, 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;
@@ -5103,9 +5123,8 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
          bfd_vma desired_length = (pcc_high_tmp - pcc_low_tmp);
          bfd_vma padding = desired_length - current_length;
          c64_pad_section (pcc_high_sec, padding);
+         (*htab->layout_sections_again) ();
        }
-      /* 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;