This patch series re-works the function elfNN_c64_resize_sections.
The function is called early on in linking to ensure that the range of sections
which need to be reachable via the PCC can be precisely bounded by the CHERI
capability format.
It also handles padding and alignign individual sections if there are any
relocations to symbols which will be given a size spanning the entire section
(i.e. section start linker defined symbols).
We hit a few problems in this function trying to link glibc, and discovered
some more while working on the function.
This patch series is a combination of the changes we've applied. I plan to
apply it as a series of patches rather than as one large patch to keep the
mapping between change and rationale.
Overall, the changes are about two things:
The first is making these padding and alignment adjustments to sections in such
a way that they are robust against changes earlier on in the linker script
instead of relying on making the adjustments in section-VMA order and having no
changes earlier on in the linker script after any adjustment has been made.
The fact that the PCC bounds span multiple sections means that we can't rely on
making adjustments in section-VMA order (increasing the alignment of the first
section in the PCC bounds will mean a change earlier on than any section in the
PCC bounds, while changes on the sections inside these bounds can adjust the
alignment needed on the PCC).
The second set of changes are around performing the padding and alignment
changes in more valid cases. We notice that data-only PURECAP shared libraries
(i.e. objects without C64 code) could still have relocations in them pointing
to section-start symbols (though won't need a non-existent PCC bounds to be
precise), and we fix a bug that did not account for section starting symbols
defined in the section they are supposed to mark.
A summary of the patch series:
1) Add padding by setting "dot" to the *expression* "dot + padding required"
rather than the value of "dot + padding required".
This means that adjustments to alignment of sections before the one being
padded cause changes which get propagated past this section.
We also include the padding in the section size, which trades unnecessary
zerod data in the final binary against having the precisely bounded size
clear in the final binary.
2) Set the alignment of sections to what is needed for precise bounds even if
the existing VMA happens to be aligned enough. This means that if
earlier sections are adjusted then the linker will ensure this section
stays aligned correctly.
3) Ensure that PCC bounds are precise independent of whether there are any
section-start symbols requiring specific sections to be precisely bounded.
(bugfix).
4) Pad and align sections for data-only executables if they are made from
PURECAP objects and need it due to their relocations.
5) Refactor the function based on above changes so that rather than construct
a list of adjustments to make and sorting that list before applying the
adjustments, we simply make adjustments as we find the requirement
(possible because the adjustments are now robust against adjustments on
earlier sections).
6) Testsuite updates and new tests.
7) Adjust section padding on a section if there is a section start symbol *in
that section* (as well as just before it). I.e. if there is a
__data_relro_start symbol in the .data.rel.ro section then we adjust the
.data.rel.ro section (rather than checking to see if the next section
has the same start address as the end address of the current section and
padding the next section if that's the case).
This is a little tricky since we don't know the position of a symbol within
a section at this point, but like the existing code we handle that lack of
knowledge by overfitting and adjusting any section that may be relevent.
The entire patch series has been regression tested on AArch64 bare-metal
purecap with no regressions.
Thanks,
Matthew
Entire patch series attached to cover letter.
Before this they would span sections which are SEC_CODE or some specific
known sections like the GOT and PLT.
This is not enough, since the compiler can want to access .rodata via
relative offsets to PCC. Hence we need to include READONLY sections.
Similarly, we want to include .data.rel.ro sections in the PCC bounds so
that they can be accessed via PCC -- this allows the capability
indirection table to be accessed.
We have not been noticing this until now because the default linker
script happens to order sections such that the PCC being required to
span .got and .text happens to end up including these problematic
sections.
RELRO sections are a bit interesting since the fact they are RELRO is
not recorded anywhere on the section itself. Rather it is stored in the
fact that the section is covered by the RELRO segment.
This means that we need to check if the sections VMA is within the
relevant range rather than just look at the section. This turns out to
be pretty easy since we have a structure containing the RELRO range,
however we do need to ensure that we don't mix up the uses of the
section VMA and the RELRO start and end around calls of
layout_sections_again since this call can change both.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index c44e7aa458e2d28f2fefe1ec754482923c448d69..f33388629164b59e07cdbac7bb4bce82e2f62b8b 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -4997,12 +4997,16 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
#define NOT_OP_SECTION(s) ((s) == NULL || (s)->output_section != sec)
- if ((sec->flags & SEC_CODE) == 0
+ if ((sec->flags & SEC_READONLY) == 0
&& NOT_OP_SECTION (htab->root.sgotplt)
&& NOT_OP_SECTION (htab->root.igotplt)
&& NOT_OP_SECTION (htab->root.sgot)
&& NOT_OP_SECTION (htab->root.splt)
- && NOT_OP_SECTION (htab->root.iplt))
+ && NOT_OP_SECTION (htab->root.iplt)
+ && (sec->vma < info->relro_start
+ || sec->vma >= info->relro_end))
+ continue;
+ if ((sec->flags & SEC_ALLOC) == 0)
continue;
if (sec->vma < low)
We were specifying section alignment requirements based on the alignment
that the section base happened to have. This sometimes resulted in very
strange alignment requests that were much greater than actually
required.
That is not usually a problem, but it does give unnecessary padding upon
re-adjustments due to changing the PCC bounds after individual sections
have been padded.
This patch adds an interface such that we return the alignment actually
required for exact capability bounds from c64_valid_cap_range. We then
use that alignment as our alignment requirement on the sections which
have a section-sized symbol associated with them.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 76ab691b33e459a4ca80d337bdc70a1c53d6c1e0..c44e7aa458e2d28f2fefe1ec754482923c448d69 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -4801,11 +4801,12 @@ exponent (uint64_t len)
#define ALIGN_UP(x, a) (((x) + ONES (a)) & (~ONES (a)))
static bfd_boolean
-c64_valid_cap_range (bfd_vma *basep, bfd_vma *limitp)
+c64_valid_cap_range (bfd_vma *basep, bfd_vma *limitp, unsigned *alignmentp)
{
bfd_vma base = *basep, size = *limitp - *basep;
unsigned e, old_e;
+ *alignmentp = 1;
if ((e = exponent (size)) == (unsigned) -1)
return TRUE;
@@ -4818,6 +4819,7 @@ c64_valid_cap_range (bfd_vma *basep, bfd_vma *limitp)
base = ALIGN_UP (base, e + 3);
+ *alignmentp = e+3;
if (base == *basep && *limitp == base + size)
return TRUE;
@@ -4868,17 +4870,18 @@ record_section_change (asection *sec, struct sec_change_queue **queue)
{
bfd_vma low = sec->vma;
bfd_vma high = sec->vma + sec->size;
+ unsigned alignment;
- if (!c64_valid_cap_range (&low, &high))
+ if (!c64_valid_cap_range (&low, &high, &alignment))
queue_section_padding (queue, sec);
}
/* Make sure that all capabilities that refer to sections have bounds that
won't overlap with neighbouring sections. This is needed in two specific
cases. The first case is that of PCC, which needs to span across all
- executable sections as well as the GOT and PLT sections in the output
- binary. The second case is that of linker and ldscript defined symbols that
- indicate start and/or end of sections.
+ readonly sections as well as the GOT and PLT sections in the output binary.
+ The second case is that of linker and ldscript defined symbols that indicate
+ start and/or end of sections and/or zero-sized symbols.
In both cases, overlap of capability bounds are avoided by aligning the base
of the section and if necessary, adding a pad at the end of the section so
@@ -4963,7 +4966,6 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
if (len > 8 && name[0] == '_' && name[1] == '_'
&& (!strncmp (name + 2, "start_", 6)
|| !strcmp (name + len - 6, "_start")))
-
{
bfd_vma value = os->vma + os->size;
@@ -5029,10 +5031,8 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
low = queue->sec->vma;
high = queue->sec->vma + queue->sec->size;
- if (!c64_valid_cap_range (&low, &high))
+ if (!c64_valid_cap_range (&low, &high, &align))
{
- align = __builtin_ctzl (low);
-
if (queue->sec->alignment_power < align)
queue->sec->alignment_power = align;
@@ -5057,9 +5057,8 @@ elfNN_c64_resize_sections (bfd *output_bfd, struct bfd_link_info *info,
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))
+ if (!c64_valid_cap_range (&pcc_low, &pcc_high, &align))
{
- align = __builtin_ctzl (pcc_low);
if (pcc_low_sec->alignment_power < align)
pcc_low_sec->alignment_power = align;
@@ -6533,8 +6532,9 @@ c64_fixup_frag (bfd *input_bfd, struct bfd_link_info *info,
return bfd_reloc_outofrange;
bfd_vma base = value, limit = value + size;
+ unsigned align = 0;
- if (!bounds_ok && !c64_valid_cap_range (&base, &limit))
+ if (!bounds_ok && !c64_valid_cap_range (&base, &limit, &align))
{
/* Just warn about this. It's not a requirement that bounds on
objects should be precise, so there's no reason to error out on
The permissions that a capability to an object should end up with is
based on the section it should point into. With symbols that point into
SHN_ABS sections we have nothing to base the permissions on (since these
sections don't have associated permission flags).
For the moment we are making a default of choosing Read-Write
permissions and warning the user about it. The permissions match what
Morello LLD currently does (from observation).
When Morello linkers use the symbol type to determine whether a
capability should have executable permissions or not, this should end up
being able to handle all uses (since STT_FUNC would get RX perms while
everything else gets RW perms).
In the only case we know of in the GNU team the symbol ends up with
zero-size anyway, so the choice of Read-Write doesn't seem too lax.
(Having zero-size is fine for the use-case we know of in glibc, since
that use case simply checks if the address of the symbol is non-zero.
Hence we have no need as yet to dereference the symbol).
The use case we know about are the `_nl_current_<LANG>_used` symbols
defined with `_NL_CURRENT_DEFINE` in the locale/lc-<lang>.c files in
statically linked glibc. If any case that requires non-zero size or
different permissions becomes important then something more will be
required across the toolchain.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 8b69c03c4a2f66a7f3d4a6dc88494c00ac72646b..0a455763faebf2d0c1e3cbe689d5b82163bfa43e 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -6364,7 +6364,7 @@ aarch64_relocation_aginst_gp_p (bfd_reloc_code_real_type reloc)
/* Build capability meta data, i.e. size and permissions for a capability. */
static bfd_vma
-cap_meta (size_t size, const asection *sec)
+cap_meta (size_t size, const asection *sec, bfd_boolean *guessed)
{
if (size >= (1ULL << 56))
@@ -6386,10 +6386,20 @@ cap_meta (size_t size, const asection *sec)
else if (sec->flags & SEC_ALLOC)
flags = 2;
- /* We should always be able to derive a valid set of permissions
- from the section flags. */
+ /* We should usually be able to derive a valid set of permissions
+ from the section flags. We know that when a relocation is against an
+ SHN_ABS symbol the section has no associated flags and we must guess.
+
+ As it stands we don't know of any other instances where we do not have
+ permission flags on a section. We choose to allow instances that we do
+ not know of rather than abort on them so that if the guess is correct we
+ don't hamper anyone progressing. */
if (flags == 0)
- abort ();
+ {
+ flags = 2;
+ *guessed = TRUE;
+ }
+
return size | (flags << 56);
}
@@ -6451,15 +6461,18 @@ c64_symbol_section_adjustment (struct elf_link_hash_entry *h, bfd_vma value,
static bfd_reloc_status_type
c64_fixup_frag (bfd *input_bfd, struct bfd_link_info *info,
- Elf_Internal_Sym *sym, struct elf_link_hash_entry *h,
- asection *sym_sec, bfd_byte *frag_loc, bfd_vma value,
- bfd_signed_vma addend)
+ bfd_reloc_code_real_type bfd_r_type, Elf_Internal_Sym *sym,
+ struct elf_link_hash_entry *h, asection *sym_sec,
+ asection *reloc_sec, bfd_byte *frag_loc, bfd_vma value,
+ bfd_signed_vma addend, bfd_vma r_offset)
{
BFD_ASSERT (h || sym);
bfd_vma size = sym ? sym->st_size : h->size;
asection *perm_sec = sym_sec;
bfd_boolean bounds_ok = FALSE;
+ const int aarch64_reloc_idx = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START;
+ const char *reloc_name = elfNN_aarch64_howto_table[aarch64_reloc_idx].name;
const char *sym_name;
if (sym)
@@ -6534,11 +6547,22 @@ c64_fixup_frag (bfd *input_bfd, struct bfd_link_info *info,
if (perm_sec != NULL)
{
- bfd_vma frag = cap_meta (size, perm_sec);
+ bfd_boolean permissions_guessed = FALSE;
+ bfd_vma frag = cap_meta (size, perm_sec, &permissions_guessed);
if (frag == (bfd_vma) -1)
return bfd_reloc_outofrange;
+ if (permissions_guessed)
+ {
+ _bfd_error_handler (_("%pB(%pA+%#" PRIx64 "): "
+ "warning: relocation %s against symbol '%s' in "
+ "section without permission flags '%s'. "
+ "Assuming Read-Write."),
+ input_bfd, reloc_sec, r_offset, reloc_name,
+ sym_name, perm_sec->name);
+ }
+
bfd_put_64 (input_bfd, frag, frag_loc);
}
@@ -7304,9 +7328,9 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
{
bfd_reloc_status_type ret;
- ret = c64_fixup_frag (input_bfd, info, sym, h,
- sym_sec, base_got->contents + off + 8,
- orig_value, 0);
+ ret = c64_fixup_frag (input_bfd, info, bfd_r_type, sym, h,
+ sym_sec, s, base_got->contents + off + 8,
+ orig_value, 0, off);
if (ret != bfd_reloc_continue)
return ret;
@@ -7509,8 +7533,9 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
bfd_reloc_status_type ret;
- ret = c64_fixup_frag (input_bfd, info, sym, h, sym_sec,
- hit_data + 8, value, signed_addend);
+ ret = c64_fixup_frag (input_bfd, info, bfd_r_type, sym, h, sym_sec,
+ input_section, hit_data + 8, value,
+ signed_addend, rel->r_offset);
if (ret != bfd_reloc_continue)
return ret;
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 9168a810fc57783dd122ce40b6385dddc6888042..01f65dc934de3f012b6e134ff2ccebd1f4207650 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -249,6 +249,7 @@ run_dump_test_lp64 "emit-relocs-morello-5"
run_dump_test_lp64 "emit-relocs-morello-6"
run_dump_test_lp64 "emit-relocs-morello-6b"
run_dump_test_lp64 "emit-relocs-morello-7"
+run_dump_test_lp64 "emit-relocs-morello-8"
run_dump_test_lp64 "emit-morello-reloc-markers-1"
run_dump_test_lp64 "emit-morello-reloc-markers-2"
run_dump_test_lp64 "emit-morello-reloc-markers-3"
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-8.d b/ld/testsuite/ld-aarch64/emit-relocs-morello-8.d
new file mode 100644
index 0000000000000000000000000000000000000000..e907f7de72e084263acd208374c09e91d6bd065f
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-8.d
@@ -0,0 +1,18 @@
+#source: emit-relocs-morello-8.s
+#source: emit-relocs-morello-8b.s
+#as: -march=morello+c64
+#ld: -static -pie
+#objdump: -DR -j .data.rel.ro
+#warning: .*relocation R_MORELLO_CAPINIT against symbol 'absolute_sym' in section without permission flags '\*ABS\*'\. Assuming Read-Write\.
+
+.*: file format .*
+
+
+Disassembly of section \.data\.rel\.ro:
+
+0.* <\.LC1>:
+ .*: 00001000 udf #4096
+ 101e0: R_MORELLO_RELATIVE \*ABS\*
+ .*: 00000000 udf #0
+ .*: 00000004 udf #4
+ .*: 02000000 add c0, c0, #0x0
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-8.s b/ld/testsuite/ld-aarch64/emit-relocs-morello-8.s
new file mode 100644
index 0000000000000000000000000000000000000000..4a42962a67534e13217a18048daf7279a89201b4
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-8.s
@@ -0,0 +1,16 @@
+ .arch morello+crc+c64
+ .text
+ .align 2
+ .global _start
+_start:
+ adrp c0, .LC1
+ add c0, c0, :lo12:.LC1
+ ldr c0, [c0]
+
+ .section .data.rel.ro.local,"aw"
+ .align 4
+ .type .LC1, %object
+ .size .LC1, 16
+.LC1:
+ .chericap absolute_sym
+ .ident "GCC: (unknown) 11.0.0 20200826 (experimental)"
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-8b.s b/ld/testsuite/ld-aarch64/emit-relocs-morello-8b.s
new file mode 100644
index 0000000000000000000000000000000000000000..fa12fb43b4e349c0949bb08b9648935032368110
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-8b.s
@@ -0,0 +1,5 @@
+ .arch morello+crc+c64
+ .text
+ .global absolute_sym
+absolute_sym = 0x1000
+ .size absolute_sym, 4
Error linking binaries with differing e_flags.
This commit is partly changing two existing (believed buggy) behaviours
in elfNN_aarch64_merge_private_bfd_data and partly accounting for a
capability-specific requirement.
The existing behaviours in elfNN_aarch64_merge_private_bfd_data were:
1) It returned `TRUE` by default. This effectively ignored the ELF
flags on the binaries, despite there being code looking at them.
2) We do not mark the output BFD as initialised until we see flags with
non-default architecture and flags. This can't tell the difference
between linking default objects to non-default objects if the default
objects are given first on the command line.
The capability-specific requirement is:
- This function originally returned early if the object file getting
merged into the existing output object file is not dynamic and has no
code sections. The code reasoned that differing ELF flags did not
matter in this case since there was no code that would be expecting
it.
For capabilities the binary compatibility is still important.
Data sections now contain capabilities as pointers, got sections now
have a different got element size.
Hence we avoid this short-circuit if any of the flags we're checking
are the CHERI_PURECAP flag.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index b460ea4764965da3b770ff6528730b4248377b16..1a65e6e5a64e115a99be8a707651ea1786b3fcdc 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -8715,7 +8715,7 @@ elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
bfd *obfd = info->output_bfd;
flagword out_flags;
flagword in_flags;
- bfd_boolean flags_compatible = TRUE;
+ bfd_boolean flags_compatible = FALSE;
asection *sec;
/* Check if we have the same endianess. */
@@ -8736,6 +8736,8 @@ elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
if (!elf_flags_init (obfd))
{
+ elf_flags_init (obfd) = TRUE;
+
/* If the input is the default architecture and had the default
flags then do not bother setting the flags for the output
architecture, instead allow future merges to do this. If no
@@ -8746,7 +8748,6 @@ elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
&& elf_elfheader (ibfd)->e_flags == 0)
return TRUE;
- elf_flags_init (obfd) = TRUE;
elf_elfheader (obfd)->e_flags = in_flags;
if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
@@ -8770,11 +8771,17 @@ elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
Also check to see if there are no code sections in the input.
In this case there is no need to check for code specific flags.
XXX - do we need to worry about floating-point format compatability
- in data sections ? */
+ in data sections ?
+
+ We definitely need to check for data sections if one set of flags is
+ targetting the PURECAP abi and another is not. Pointers being
+ capabilities in data sections can not be glossed over. */
if (!(ibfd->flags & DYNAMIC))
{
bfd_boolean null_input_bfd = TRUE;
- bfd_boolean only_data_sections = TRUE;
+ bfd_boolean only_data_sections
+ = !(in_flags & EF_AARCH64_CHERI_PURECAP
+ || out_flags & EF_AARCH64_CHERI_PURECAP);
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index c40eba959421ac6d5e97f11d95a5900fa8e5b2bf..9168a810fc57783dd122ce40b6385dddc6888042 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -255,6 +255,7 @@ run_dump_test_lp64 "emit-morello-reloc-markers-3"
run_dump_test_lp64 "morello-sizeless-local-syms"
run_dump_test_lp64 "morello-sizeless-global-syms"
run_dump_test_lp64 "morello-sizeless-got-syms"
+run_dump_test_lp64 "morello-disallow-merged-binaries"
run_dump_test_lp64 "morello-capinit"
run_dump_test_lp64 "morello-stubs"
diff --git a/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries-code.s b/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries-code.s
new file mode 100644
index 0000000000000000000000000000000000000000..83a7291c911f83f5ae611a3db7afbf95e2f0b10d
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries-code.s
@@ -0,0 +1,11 @@
+ .file "very-basic-test.c"
+ .text
+ .align 2
+ .global _start
+ .type _start, %function
+_start:
+ adrp c0, :got:extobj
+ ldr c0, [c0, #:got_lo12:extobj]
+ ldr w0, [c0]
+ ret
+ .size _start, .-_start
diff --git a/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries-data.s b/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries-data.s
new file mode 100644
index 0000000000000000000000000000000000000000..a9be82acddbb258ca8a27ea4b16adb62c786411d
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries-data.s
@@ -0,0 +1,8 @@
+ .text
+ .global extobj
+ .data
+ .align 2
+ .type extobj, %object
+ .size extobj, 4
+extobj:
+ .word 1
diff --git a/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries.d b/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries.d
new file mode 100644
index 0000000000000000000000000000000000000000..ddb44c59764c71a5ea23a381ae02615f52a8e571
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-disallow-merged-binaries.d
@@ -0,0 +1,4 @@
+#source: morello-disallow-merged-binaries-data.s -march=morello
+#source: morello-disallow-merged-binaries-code.s -march=morello+c64
+#ld: -static
+#error: .*failed to merge target specific data.*
The reasoning behind only warning for symbols which have a size which
cannot be precisely bounded is that there is nothing *requiring* precise
bounds, GCC knowingly avoids changing the size of some symbols for
precise bounds (TLS and symbols with user-specified alignment and
user-specified section), and LLD only warns on imprecise bounds rather
than erroring.
N.b. the reasoning for GCC avoiding padding in these cases is explained
in the commit message of b302420cb55 in the GCC branch
vendors/ARM/heads/morello.
All in all it's not something that we want in our toolchain as a
requirement, and it's not something that other toolchains have as a
requirement, so there doesn't seem to be much of a reason to include it.
In order to make this warning a little nicer for anyone reading it, we
add the name of the symbol to the warning. Update the testsuite to
account for this.
Co-Author: Alex Coplan <alex.coplan(a)arm.com>
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index cd54beec7b7d9f6b6977634dcd82501b80ab6cd4..939fac197d5dab3dcee8b9d820957e68419ca0af 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -6460,6 +6460,18 @@ c64_fixup_frag (bfd *input_bfd, struct bfd_link_info *info,
asection *perm_sec = sym_sec;
bfd_boolean bounds_ok = FALSE;
+ const char *sym_name;
+
+ if (sym)
+ {
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd);
+ sym_name = (bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name));
+ }
+ else
+ sym_name = h->root.root.string;
+
if (size == 0 && sym_sec)
{
bounds_ok = TRUE;
@@ -6492,11 +6504,13 @@ c64_fixup_frag (bfd *input_bfd, struct bfd_link_info *info,
if (!bounds_ok && !c64_valid_cap_range (&base, &limit))
{
+ /* Just warn about this. It's not a requirement that bounds on
+ objects should be precise, so there's no reason to error out on
+ such an object. */
/* xgettext:c-format */
- _bfd_error_handler (_("%pB: capability range may exceed object bounds"),
- input_bfd);
- bfd_set_error (bfd_error_bad_value);
- return bfd_reloc_notsupported;
+ _bfd_error_handler
+ (_("%pB: capability range for '%s' may exceed object bounds"),
+ input_bfd, sym_name);
}
if (perm_sec && perm_sec->flags & SEC_CODE)
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-5.d b/ld/testsuite/ld-aarch64/emit-relocs-morello-5.d
index 05bbef145e03786dbb489b40441e78fbff69ddb5..7fa7909bdffd47c6877df709ad74d17bf0fc9c1f 100644
--- a/ld/testsuite/ld-aarch64/emit-relocs-morello-5.d
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-5.d
@@ -1,6 +1,4 @@
#source: emit-relocs-morello-5.s
#as: -march=morello+c64
#ld: -static
-#error: .*: capability range may exceed object bounds
-#error: .*: in function `_start':.*
-#error: .*: dangerous relocation: unsupported relocation
+#warning: .*: capability range for 'bigarray' may exceed object bounds
Hi,
This is a respin of the following patch:
https://op-lists.linaro.org/archives/list/gnu-morello@op-lists.linaro.org/t…
In this version we drop the adjustment of the bounds given to symbols
without size information: we now leave these with zero bounds and drop
the diagnostic to allow the linker to accept capability relocations
against such symbols.
The new proposed commit message is below.
Regression tested on aarch64-none-elf, OK for the Morello branch?
Thanks,
Alex
------------------------------------------------------------------------
This patch has two main goals:
- Relax an existing diagnostic to permit the linker to accept
capability relocations against symbols without size information.
- Adjust the capability base and bounds for symbols which point into
sections which may be accessed via the PCC.
The Morello ABI accesses global data using ADR and ADRP, and has no
special indirection to jump to other functions. Given this, the PCC
must maintain its bounds and base so that during execution loading
global data and jumping to other functions can be done without worrying
about the current PCC permissions and bounds.
To implement this, all capabilities that could be loaded into the PCC
(via BLR or similar) must have a bounds and base according to the PCC.
This must span all global data and text sections (i.e. .got, .text,
.got.plt and the like).
There is already code finding the range that the PCC should span, this
patch records the information in a variable that we can query later.
There are two places where we create a relocation requesting a
capability to be initialised at runtime. When handling relocations
which request a capability from the GOT, and when handling a CAPINIT
relocation. This patch adjusts both.
We can't tell from inspection which symbols would be loaded into the
PCC, but we know that those symbols must point into a section which is
executable. For now, we do this operation for all symbols which point
into an executable section.
Most RELATIVE relocations don't use the addend. Rather the VA and size
we want are put in the relative fragment and the addend is zero.
This is because the *base* of the capability usually matches the VA we
want that capability initialised to.
In these possibly-code symbols we want the base of the capability bounds
to be the base of the PCC, and the VA to be something very different.
Hence we make use of the addend in the RELA relocations to encode this
offset.
Note on implementation:
c64_fixup_frag takes the base and size of a capability we want to
request from the runtime and checks that these are exactly representable
in a capability. This patch changes many of the capabilities we request
from the runtime to have the same bounds (those of the PCC). We leave
the check to look at the bounds requested by the symbol rather than to
check the PCC bounds multiple times. That means that if a symbol that
points into an executable section has incorrect bounds then this will
trigger a linker error even though it will cause no security problem
when this executes. This is a trade-off between getting extra checks
that the compiler is handling object bounds sizes and erroring on
non-problematic code.
We have a compatibility hack that if a symbol is defined in the linker
script to be directly after a given section but is *named* something
like __.*_start or __start_.* then we treat it as if it is defined at
the very start of the next section. The new behaviour introduced in
this patch needs to take account of the above compatibility hack.
This patch also updates the testsuite according to these changes.
In some places the original test no longer checks what it wanted, since
the base of all symbols pointing into executable sections are now the
same. There we add extra symbols and things to check so we ensure that
this behaviour of PCC bounds is seen and that the original behaviour is
still seen on non-executable sections.
This commit also includes a few tidy-ups:
We adjust the base and limit that are checked in c64_fixup_frag.
Originally this would calculate the base as value + addend. As
discussed above the way we treat capabilities in Morello is such that
the value determines the base and the addend determines the initial
value pointing from that base. Hence the check that these capabilities
had correct bounds was not correct.
We add an extra assertion in final_link_relocate for robustness
purposes. There is an existing bug in the assembler where GOT
relocations against local symbols can be turned into relocations against
the relevant section symbol plus an addend. This is problematic for
multiple reasons, one being that the linker implementation does not have
any way to associate different GOT entries with the same symbol but
multiple offsets. In fact the linker ignores any offset. Here we
simply add an assertion that this never happens. It turns a silent
pre-existing error into a noisy one.
2022-02-01 Alex Coplan <alex.coplan(a)arm.com>
Matthew Malcomson <matthew.malcomson(a)arm.com>
bfd/ChangeLog:
* elfnn-aarch64.c (pcc_low): New.
(pcc_high): New.
(elfNN_c64_resize_sections): Update new global variables
pcc_{low,high} instead of local variables to track PCC span.
(enum c64_section_perm_type): New.
(c64_symbol_section_adjustment): New.
(c64_fixup_frag): Rework to calculate size appropriately for
symbols that need adjustment.
(c64_symbol_adjust): New. Use it ...
(elfNN_aarch64_final_link_relocate): ... here.
ld/ChangeLog:
* testsuite/ld-aarch64/aarch64-elf.exp: Add new tests.
* testsuite/ld-aarch64/emit-relocs-morello-6.d: New test.
* testsuite/ld-aarch64/emit-relocs-morello-6.s: Assembly.
* testsuite/ld-aarch64/emit-relocs-morello-6b.d: New test.
* testsuite/ld-aarch64/emit-relocs-morello-7.d: New test.
* testsuite/ld-aarch64/emit-relocs-morello-7.ld: Linker script thereof.
* testsuite/ld-aarch64/emit-relocs-morello-7.s: Assembly.
* testsuite/ld-aarch64/morello-capinit.d: New test.
* testsuite/ld-aarch64/morello-capinit.ld: Linker script.
* testsuite/ld-aarch64/morello-capinit.s: Assembly.
* testsuite/ld-aarch64/morello-sizeless-global-syms.d: New test.
* testsuite/ld-aarch64/morello-sizeless-global-syms.s: Assembly.
* testsuite/ld-aarch64/morello-sizeless-got-syms.d: New test.
* testsuite/ld-aarch64/morello-sizeless-got-syms.s: Assembly.
* testsuite/ld-aarch64/morello-sizeless-local-syms.d: New test.
* testsuite/ld-aarch64/morello-sizeless-local-syms.s: Assembly.