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.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index fb50608b72c41fae81b1d2b3a655161ce8c55e8d..d75c1eea52e19806304b0605291937112bbaed41 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -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; } diff --git a/ld/testsuite/ld-aarch64/morello-sec-always-align.d b/ld/testsuite/ld-aarch64/morello-sec-always-align.d index f46ebdfb821eac114f84dee8b385d1ab1648af30..9e69e1c3d1ecdf79cc01d393ae0fd2d83e06a895 100644 --- a/ld/testsuite/ld-aarch64/morello-sec-always-align.d +++ b/ld/testsuite/ld-aarch64/morello-sec-always-align.d @@ -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