morello-binutils: Use global GOT type to determine GOT action
In final_link_relocate we currently use whether the relocation we're
looking at is a Morello relocation to decide whether we should treat the
GOT entry as a Morello GOT entry or not.
This is problematic since we can have an AArch64 relocation against a
capability GOT entry (even if it isn't a very useful thing to have).
The current patch decides whether we need to emit a MORELLO RELATIVE
relocation in the GOT based on whether the GOT as a whole contains
capabilities rather than based on whether the first relocation against
this GOT is a Morello relocation.
Until now we did not see any problem from this. Here we add a testcase
that triggers the problem.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 68c88bce0b475a6af2097c3993f9a5753a774fdb..244b837f4458051fc0bce7e878a63a0b5278c26b 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -7220,9 +7220,6 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
base_got = globals->root.sgot;
bfd_boolean is_dynamic = elf_hash_table (info)->dynamic_sections_created;
- bfd_boolean c64_reloc =
- (bfd_r_type == BFD_RELOC_MORELLO_LD128_GOT_LO12_NC
- || bfd_r_type == BFD_RELOC_MORELLO_ADR_GOT_PAGE);
if (signed_addend != 0)
{
@@ -7267,9 +7264,9 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
BFD_ASSERT (!WILL_CALL_FINISH_DYNAMIC_SYMBOL
(is_dynamic, bfd_link_pic (info), h));
relative_reloc = TRUE;
- c64_needs_frag_fixup = c64_reloc ? TRUE : FALSE;
+ c64_needs_frag_fixup = globals->c64_rel ? TRUE : FALSE;
}
- else if (!c64_reloc || !c64_needs_relocation (info, h))
+ else if (!globals->c64_rel || !c64_needs_relocation (info, h))
{
/* Symbol references via GOT in C64 should always have
relocations of some kind unless they are undefined weak
@@ -7308,7 +7305,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
c64_needs_frag_fixup = TRUE;
}
- if (c64_reloc
+ if (globals->c64_rel
&& c64_symbol_adjust (h, value, sym_sec, info, &frag_value))
signed_addend = (value | h->target_internal) - frag_value;
else
@@ -7354,7 +7351,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
{
bfd_vma frag_value;
- if (c64_reloc
+ if (globals->c64_rel
&& c64_symbol_adjust (h, value, sym_sec, info, &frag_value))
signed_addend = (value | sym->st_target_internal) - frag_value;
else
@@ -7375,7 +7372,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
dynamic relocations). */
if (bfd_link_pic (info)
|| (!bfd_link_pic (info) && bfd_link_executable (info)
- && c64_reloc))
+ && globals->c64_rel))
{
/* We have not handled the case for weak undefined symbols in
this clause. That is because we believe there can not be
@@ -7390,7 +7387,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
would not see it in this clause. */
BFD_ASSERT (!weak_undef_p);
relative_reloc = TRUE;
- c64_needs_frag_fixup = c64_reloc ? TRUE : FALSE;
+ c64_needs_frag_fixup = globals->c64_rel ? TRUE : FALSE;
}
symbol_got_offset_mark (input_bfd, h, r_symndx);
@@ -7410,7 +7407,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
if (c64_needs_frag_fixup)
{
- BFD_ASSERT (c64_reloc);
+ BFD_ASSERT (globals->c64_rel);
/* For a C64 relative relocation, also add size and permissions into
the frag. */
bfd_reloc_status_type ret;
@@ -7433,7 +7430,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
s = globals->root.srelgot;
- if (c64_reloc)
+ if (globals->c64_rel)
{
rtype = MORELLO_R (RELATIVE);
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 95c0e1bfec10bfb3810d88c5ae27c279dcbbb3b5..5af3bbfa84151cbfca25dd5580407def9387fba0 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -281,6 +281,7 @@ 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-relocs-morello-9"
+run_dump_test_lp64 "emit-relocs-morello-10"
run_dump_test_lp64 "emit-relocs-morello-hidden"
run_dump_test_lp64 "emit-morello-reloc-markers-1"
run_dump_test_lp64 "emit-morello-reloc-markers-2"
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-10.d b/ld/testsuite/ld-aarch64/emit-relocs-morello-10.d
new file mode 100644
index 0000000000000000000000000000000000000000..9f423e8b2adff0e331d9e6340ffe85c6c4f5ac5c
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-10.d
@@ -0,0 +1,12 @@
+# Checking that we have two RELATIVE relocations, indicating that both the
+# CAPINIT and the GOT entry were given a RELATIVE relocation. As opposed to
+# before when the linker generated one RELATIVE relocation and an
+# R_AARCH64_NONE relocation.
+#as: -march=morello+c64
+#ld:
+#readelf: --relocs
+
+Relocation section '\.rela\.dyn' at offset .* contains 2 entries:
+ Offset Info Type Sym\. Value Sym\. Name \+ Addend
+[0-9a-f]+ [0-9a-f]+ R_MORELLO_RELATIV 0
+[0-9a-f]+ [0-9a-f]+ R_MORELLO_RELATIV 0
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-10.s b/ld/testsuite/ld-aarch64/emit-relocs-morello-10.s
new file mode 100644
index 0000000000000000000000000000000000000000..b04bfe8d17aa291abaed77f9c547f4e9d2a8c36f
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-10.s
@@ -0,0 +1,21 @@
+ .data
+str:
+ .string "Hello there big bad world!"
+ .size str,.-str
+ .global ptr
+ptr:
+ .8byte str
+ .align 4
+ .type cap STT_OBJECT
+ .global cap
+cap:
+ .chericap str
+
+ .text
+ .globl _start
+ .type _start STT_FUNC
+_start:
+ ldr x2, [x2, :got_lo12:cap]
+ adrp c2, :got:cap
+ ldr c2, [c2, :got_lo12:cap]
+ ldr c2, [x2, :got_lo12:cap]
Originally we believed we had accounted for these symbols within the
existing if conditional. It turns out that with `-pie
--no-dynamic-linker` on the command line (which causes the `link_info`
member `dynamic_undefined_weak` to be set to 0) such symbols can bypass
elfNN_aarch64_allocate_dynrelocs putting these symbols into the dynamic
symbol table. Hence we can have such symbols without a dynamic index
and our existing conditionals need to be adjusted.
On further inspection we notice that GOT entries for *hidden* undefined
weak symbols were still getting RELATIVE relocations. This is quite
unnecessary since it's known that the entry should be the NULL
capability, but on top of that it relies on the runtime to have a
special case to not add the load displacement to RELATIVE relocations
with completely zero fragments.
We make two logical adjustments.
The first is that in our handling of CAPINIT relocations we add a
clause to avoid emitting a relocation for any undefined weak symbol
which we know for certain should end up with the NULL capability at
runtime. In this clause we ensure that the fragment is completely zero.
The second is around handling GOT entries. For these we ensure that
elfNN_aarch64_allocate_dynrelocs does not allocate a dynamic relocation
for the GOT entry of such symbols and that
elfNN_aarch64_final_link_relocate leaves the GOT entry empty and without
any relocation.
N.b. in implementing this change the conditionals became quite
confusing. We split them up quite unnecessarily into different else/if
statements for clarity at the expense of verbosity.
We also add tests to check the behaviour of undefined weak symbols for
dynamically linked PDE's/PIE's/static executables/shared objects.
N.b.2 We also add an extra assert in final_link_relocate. This function
deals with GOT entries for symbols both in the internal hash table and
not in the hash table. Binutils decides whether symbols should be in
the hash table or not based on their binding. WEAK binding symbols are
put in the hash table. That said, final_link_relocate has a
`weak_undef_p` local flag to describe whether a given symbol is weak
undefined or not. This flag is defined for both symbols in the hash
table and symbols not in the hash table.
I believe that the only time we have weak_undef_p set in
final_link_relocate when the relevant symbol is not in the hash table is
when we have "removed" a relocation from our work list by modifying it
to be a R_AARCH64_NONE relocation against the STN_UNDEF symbol (e.g.
during TLS relaxation).
Such cases would not fall into the GOT relocation clause. Hence I don't
think we can ever see weak_undef_p symbols which are not in the hash
table in this clause. It's worth an assertion to catch the possibility
that this is wrong.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index dd1c28ad7e4352d9407b1b7a1d863a0cb293a9a4..68c88bce0b475a6af2097c3993f9a5753a774fdb 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -292,6 +292,16 @@
(((htab)->root.srelplt == NULL) ? 0 \
: (htab)->root.srelplt->reloc_count * GOT_ENTRY_SIZE (htab))
+/* The only time that we want the value of a symbol but do not want a
+ relocation for it in Morello is when that symbol is undefined weak. In this
+ case we just need the zero capability and there's no point emitting a
+ relocation for it when we can get an untagged zero capability by just
+ loading some zeros. */
+#define c64_needs_relocation(info, h) \
+ (!((h)->root.type == bfd_link_hash_undefweak \
+ && (UNDEFWEAK_NO_DYNAMIC_RELOC ((info), (h)) \
+ || !elf_hash_table ((info))->dynamic_sections_created)))
+
/* The first entry in a procedure linkage table looks like this
if the distance between the PLTGOT and the PLT is < 4GB use
these PLT entries. Note that the dynamic linker gets &PLTGOT[2]
@@ -7240,58 +7250,61 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
NOTE: one symbol may be referenced by several relocations, we
should only generate one RELATIVE relocation for that symbol.
- Therefore, check GOT offset mark first.
-
- NOTE2: Symbol references via GOT in C64 should always have
- relocations of some kind. Here we try to catch any such GOT
- reference which would not otherwise be caught by
- finish_dynamic_symbol. */
- if (((h->dynindx == -1
- && !h->forced_local
- && h->root.type != bfd_link_hash_undefweak
- && bfd_link_pic (info))
- || (!bfd_link_pic (info)
- && !WILL_CALL_FINISH_DYNAMIC_SYMBOL
- (is_dynamic, bfd_link_pic (info), h)
- && bfd_link_executable (info) && c64_reloc))
+ Therefore, check GOT offset mark first. */
+ if (h->dynindx == -1
+ && !h->forced_local
+ && h->root.type != bfd_link_hash_undefweak
+ && bfd_link_pic (info)
&& !symbol_got_offset_mark_p (input_bfd, h, r_symndx))
{
- /* If we would call finish_dynamic_symbol for this symbol then we
- should not be introducing a relocation for the GOT entry
- (that function handles creating relocations for the GOT entry
- in the usual case, this bit of code is to handle special
- cases where the relocation would not otherwise be generated).
- */
+ /* Here we look for symbols which are not going to have their
+ relocations added by finish_dynamic_symbol, but which still
+ need a dynamic relocation because we're compiling for PIC.
+
+ Action on this clause and the one below is the same.
+ Written that way to make the three different cases and their
+ interpretation clear. */
BFD_ASSERT (!WILL_CALL_FINISH_DYNAMIC_SYMBOL
(is_dynamic, bfd_link_pic (info), h));
relative_reloc = TRUE;
c64_needs_frag_fixup = c64_reloc ? TRUE : FALSE;
}
- /* If this is a dynamic symbol that binds locally then the generic
- code and elfNN_aarch64_finish_dynamic_symbol will already handle
- creating the RELATIVE reloc pointing into the GOT for this symbol.
- That means that this function does not need to handle *creating*
- such a relocation. This function does already handle setting the
- base value as the fragment for that relocation, hence we should
- ensure that we set the fragment correctly for C64 code (i.e.
- including the required permissions and bounds). */
- else if (c64_reloc
- && WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dynamic,
- bfd_link_pic (info), h)
+ else if (!c64_reloc || !c64_needs_relocation (info, h))
+ {
+ /* Symbol references via GOT in C64 should always have
+ relocations of some kind unless they are undefined weak
+ symbols which cannot be provided at runtime. In those cases
+ we need a plain zero.
+
+ This clause catches the case when we're not relocating for
+ GOT, or when we're relocating an undefined weak symbol. */
+ }
+ else if (!bfd_link_pic (info)
+ && !WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dynamic,
+ bfd_link_pic (info), h)
+ && bfd_link_executable (info)
+ && !symbol_got_offset_mark_p (input_bfd, h, r_symndx))
+ {
+ /* This clause is here to catch any c64 entries in the GOT which
+ need a relocation, but whose relocation will not be provided
+ by finish_dynamic_symbol. */
+ relative_reloc = TRUE;
+ c64_needs_frag_fixup = TRUE;
+ }
+ else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dynamic,
+ bfd_link_pic (info), h)
&& bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h))
{
- /* We believe that if `h` were undefined weak it would not have
- SYMBOL_REFERENCES_LOCAL return true. However this is not 100%
- clear based purely on the members that we check in the code.
- The reason it matters is if we could have a
- SYMBOL_REFERENCES_LOCAL symbol which is also
- !UNDEFWEAK_NO_DYNAMIC_RELOC then the check above would
- determine that we need to fix up the fragment for the RELATIVE
- relocation that elfNN_aarch64_finish_dynamic_symbol will
- create, but in actual fact elfNN_aarch64_finish_dynamic_symbol
- would not create that relocation. */
- BFD_ASSERT (!UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+ /* If this is a dynamic symbol that binds locally then the
+ generic code and elfNN_aarch64_finish_dynamic_symbol will
+ already handle creating the RELATIVE reloc pointing into the
+ GOT for this symbol. That means that this function does not
+ need to handle *creating* such a relocation. We already
+ handle setting the base value in the fragment for that
+ relocation below, but we also need to make sure we set the
+ rest of the fragment correctly for C64 code (i.e. including
+ the required permissions and bounds). */
c64_needs_frag_fixup = TRUE;
}
@@ -7364,6 +7377,18 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
|| (!bfd_link_pic (info) && bfd_link_executable (info)
&& c64_reloc))
{
+ /* We have not handled the case for weak undefined symbols in
+ this clause. That is because we believe there can not be
+ weak undefined symbols as we reach this clause. We believe
+ that any symbol with WEAK binding in an object file would be
+ put into the hash table (and hence go into the `h != NULL`
+ clause above). The only time that `weak_undef_p` should be
+ set for something not in the hash table is when we have
+ removed a relocation by marking it as against the undefined
+ symbol (e.g. during TLS relaxation). We only ever do that
+ while also setting the relocation to R_AARCH64_NONE, so we
+ would not see it in this clause. */
+ BFD_ASSERT (!weak_undef_p);
relative_reloc = TRUE;
c64_needs_frag_fixup = c64_reloc ? TRUE : FALSE;
}
@@ -7613,12 +7638,25 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
outrel.r_addend = signed_addend;
+ if (h && !c64_needs_relocation (info, h))
+ {
+ /* If we know this symbol does not need a C64 dynamic relocation
+ then it must be because this is an undefined weak symbol which
+ can not find a definition at runtime.
+
+ To handle that we just ensure that we've put a zero into the
+ binary file at this point and mark the relocation as resolved.
+ */
+ value = 0;
+ *unresolved_reloc_p = FALSE;
+ break;
+ }
/* Emit a dynamic relocation if we are handling a symbol which the
dynamic linker will be told about. */
- if (h != NULL
- && h->dynindx != -1
- && globals->root.dynamic_sections_created
- && !SYMBOL_REFERENCES_LOCAL (info, h))
+ else if (h != NULL
+ && h->dynindx != -1
+ && globals->root.dynamic_sections_created
+ && !SYMBOL_REFERENCES_LOCAL (info, h))
{
outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
/* Dynamic symbols will be handled by the dynamic loader. Hence
@@ -9674,6 +9712,10 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
break;
case BFD_RELOC_MORELLO_CAPINIT:
+ if (h && !c64_needs_relocation (info, h))
+ /* If this symbol does not need a relocation, then there's no
+ reason to increase the srelcaps size for a relocation. */
+ break;
if (htab->srelcaps == NULL)
{
if (htab->root.dynobj == NULL)
@@ -10232,23 +10274,37 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
{
h->got.offset = htab->root.sgot->size;
htab->root.sgot->size += GOT_ENTRY_SIZE (htab);
- if (((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
- && (bfd_link_pic (info)
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
- /* Undefined weak symbol in static PIE resolves to 0 without
- any dynamic relocations. */
- && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
- /* Any capability relocations required in a dynamic binary
- should go in the srelgot. */
- || (htab->c64_rel && dyn))
+
+ if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
+ && (bfd_link_pic (info)
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ {
+ htab->root.srelgot->size += RELOC_SIZE (htab);
+ }
+ else if (!htab->c64_rel || !c64_needs_relocation (info, h))
+ {
+ /* Either not relocating for C64, and hence all problematic
+ relocations are handled above, or this is an undefined weak
+ symbol that we know will not be resolved to anything by the
+ runtime do not need a relocation. */
+ }
+ else if (dyn)
{
+ /* Any capability relocations required in a dynamic binary
+ should go in the srelgot. N.b. many capability relocations
+ would be caught by the first clause in this if chain. */
htab->root.srelgot->size += RELOC_SIZE (htab);
}
- else if (bfd_link_executable (info) && htab->c64_rel)
+ else if (bfd_link_executable (info))
{
/* If we have a capability relocation that is not handled by the
- case above then this must be a statically linked executable. */
+ case above then this must be a statically linked executable.
+ We want capability relocations in a statically linked
+ executable to go in the srelcaps section. */
BFD_ASSERT (!bfd_link_pic (info) && !dyn);
htab->srelcaps->size += RELOC_SIZE (htab);
}
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 235df2872084b5115239b671c5107b56a36b446f..f6d579dab0ad88ee9e778a09cf7e3bf69a2f0be7 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -301,6 +301,15 @@ if { [ld_assemble_flags $as -march=morello+c64 $srcdir/$subdir/morello-dynamic-r
run_dump_test_lp64 "morello-dataptr-code-and-data"
}
+if { [ld_assemble_flags $as -march=morello+c64 $srcdir/$subdir/morello-weakdefinitions.s tmpdir/morello-weakdefinitions.o]
+ && [ld_link $ld tmpdir/morello-weakdefinitions.so "--shared tmpdir/morello-weakdefinitions.o"] } {
+ run_dump_test_lp64 "morello-undefweak-relocs-PDE"
+}
+run_dump_test_lp64 "morello-undefweak-relocs-no-dyn-linker"
+run_dump_test_lp64 "morello-undefweak-relocs-PIE"
+run_dump_test_lp64 "morello-undefweak-relocs-static"
+run_dump_test_lp64 "morello-undefweak-relocs-static-relocs"
+
run_dump_test_lp64 "morello-static-got"
run_dump_test_lp64 "morello-dynamic-got"
run_dump_test_lp64 "morello-dt-init-fini"
diff --git a/ld/testsuite/ld-aarch64/morello-undefweak-relocs-PDE.d b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-PDE.d
new file mode 100644
index 0000000000000000000000000000000000000000..a209418cf2406e2d64afd95f6092c45c9122aec5
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-PDE.d
@@ -0,0 +1,61 @@
+# Exercise a corner case of handling morello GOT relocations against weak undef
+# symbols.
+#
+# What we want to check is:
+# 1) The adrp/ldr insns point to the relevant entries in the GOT.
+# 2) There are relocations for all except the hidden weak undef symbol in the
+# GOT (the only symbol which can never be given a value at runtime since
+# it is hidden).
+# 3) The GOT entry for this weak undefined symbol is zero.
+# 4) The values in .data are initialized as zero.
+# 5) There are relocations to initialize the non-hidden .data variables and
+# no relocation to initialize the value of the hidden symbol.
+#
+# (1) is checked by ensuring that the adrp/ldr combinations point to increments
+# of 0x10 past the start of the got section.
+# (2) and (3) are checked by the fact that objdump prints nothing except
+# relocations for the non-hidden symbols after the first line in the .got
+# section.
+# (4) and (5) is checked by the fact that objdump prints nothing except
+# relocations for the non-hidden symbols for the data section contents.
+#source: morello-undefweak-relocs.s
+#as: -march=morello+c64
+#ld: tmpdir/morello-weakdefinitions.so
+#objdump: -DR -j .got -j .data -j .text
+
+.*: file format .*
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+#record: GOTPAGE
+.* adrp c0, ([0-9a-f]+) .*
+#record: GOTOFFSET
+.* ldr c0, \[c0, #([0-9]+)\]
+#check: PAGEG string tolower $GOTPAGE
+#check: GOTOFF2 expr "$GOTOFFSET - 0x10"
+#check: GOTOFF3 expr "$GOTOFFSET - 0x20"
+.* adrp c0, PAGEG .*
+.* ldr c0, \[c0, #GOTOFF2\]
+.* adrp c0, PAGEG .*
+.* ldr c0, \[c0, #GOTOFF3\]
+.* ret c30
+
+Disassembly of section \.got:
+
+.* <_GLOBAL_OFFSET_TABLE_>:
+#check: GOTSTART format %x [expr "0x$GOTPAGE + $GOTOFFSET - 0x30"]
+#check: GOTGLOBAL format %x [expr "0x$GOTPAGE + $GOTOFFSET"]
+#check: GOTLOCAL format %x [expr "0x$GOTPAGE + $GOTOFFSET - 0x20"]
+ *GOTSTART: .*
+ \.\.\.
+ GOTLOCAL: R_MORELLO_GLOB_DAT localsym
+ GOTGLOBAL: R_MORELLO_GLOB_DAT globalsym
+
+Disassembly of section \.data:
+
+.* <.*>:
+ \.\.\.
+ [0-9a-f]*: R_MORELLO_CAPINIT globalsym
+ [0-9a-f]*: R_MORELLO_CAPINIT localsym
diff --git a/ld/testsuite/ld-aarch64/morello-undefweak-relocs-PIE.d b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-PIE.d
new file mode 100644
index 0000000000000000000000000000000000000000..1ef2021def59fd021599acbbc0df4cf4916a3c73
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-PIE.d
@@ -0,0 +1,61 @@
+# Exercise a corner case of handling morello GOT relocations against weak undef
+# symbols.
+#
+# What we want to check is:
+# 1) The adrp/ldr insns point to the relevant entries in the GOT.
+# 2) There are relocations for all except the hidden weak undef symbol in the
+# GOT (the only symbol which can never be given a value at runtime since
+# it is hidden).
+# 3) The GOT entry for this weak undefined symbol is zero.
+# 4) The values in .data are initialized as zero.
+# 5) There are relocations to initialize the non-hidden .data variables and
+# no relocation to initialize the value of the hidden symbol.
+#
+# (1) is checked by ensuring that the adrp/ldr combinations point to increments
+# of 0x10 past the start of the got section.
+# (2) and (3) are checked by the fact that objdump prints nothing except
+# relocations for the non-hidden symbols after the first line in the .got
+# section.
+# (4) and (5) is checked by the fact that objdump prints nothing excepet
+# relocations for the non-hidden symbols for the data section contents.
+#source: morello-undefweak-relocs.s
+#as: -march=morello+c64
+#ld: -pie
+#objdump: -DR -j .got -j .data -j .text
+
+.*: file format .*
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+#record: GOTPAGE
+.* adrp c0, ([0-9a-f]+) .*
+#record: GOTOFFSET
+.* ldr c0, \[c0, #([0-9]+)\]
+#check: PAGEG string tolower $GOTPAGE
+#check: GOTOFF2 expr "$GOTOFFSET - 0x10"
+#check: GOTOFF3 expr "$GOTOFFSET - 0x20"
+.* adrp c0, PAGEG .*
+.* ldr c0, \[c0, #GOTOFF2\]
+.* adrp c0, PAGEG .*
+.* ldr c0, \[c0, #GOTOFF3\]
+.* ret c30
+
+Disassembly of section \.got:
+
+.* <.got>:
+#check: GOTSTART format %x [expr "0x$GOTPAGE + $GOTOFFSET - 0x30"]
+#check: GOTGLOBAL format %x [expr "0x$GOTPAGE + $GOTOFFSET"]
+#check: GOTLOCAL format %x [expr "0x$GOTPAGE + $GOTOFFSET - 0x20"]
+ *GOTSTART: .*
+ \.\.\.
+ GOTLOCAL: R_MORELLO_GLOB_DAT localsym
+ GOTGLOBAL: R_MORELLO_GLOB_DAT globalsym
+
+Disassembly of section \.data:
+
+.* <.*>:
+ \.\.\.
+ [0-9a-f]*: R_MORELLO_CAPINIT globalsym
+ [0-9a-f]*: R_MORELLO_CAPINIT localsym
diff --git a/ld/testsuite/ld-aarch64/morello-undefweak-relocs-no-dyn-linker.d b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-no-dyn-linker.d
new file mode 100644
index 0000000000000000000000000000000000000000..8e562d41f9d3c87fa48dcd524fcb4d95ec765a83
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-no-dyn-linker.d
@@ -0,0 +1,50 @@
+# Exercise a corner case of handling morello GOT relocations against weak undef
+# symbols.
+#
+# What we want to check is:
+# 1) The adrp/ldr insns point to the relevant entries in the GOT.
+# 2) There are no relocations in the GOT.
+# 3) The GOT entries used by these weak undefined symbols are all zero.
+# 4) The values in .data are all zero.
+#
+# (1) is checked by ensuring that the adrp/ldr combinations point to increments
+# of 0x10 past the start of the got section.
+# (2) and (3) are checked by the fact that objdump prints nothing after the
+# first entry in the .got section (the pointer to the dynamic section).
+# (4) is checked by the fact that objdump prints nothing for the data section
+# contents.
+#source: morello-undefweak-relocs.s
+#as: -march=morello+c64
+#ld: -pie --no-dynamic-linker
+#objdump: -DR -j .got -j .data -j .text
+
+.*: file format .*
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+#record: GOTPAGE
+.* adrp c0, ([0-9a-f]+) .*
+#record: GOTOFFSET
+.* ldr c0, \[c0, #([0-9]+)\]
+#check: PAGEG string tolower $GOTPAGE
+#check: GOTOFF2 expr "$GOTOFFSET - 0x10"
+#check: GOTOFF3 expr "$GOTOFFSET - 0x20"
+.* adrp c0, PAGEG .*
+.* ldr c0, \[c0, #GOTOFF2\]
+.* adrp c0, PAGEG .*
+.* ldr c0, \[c0, #GOTOFF3\]
+.* ret c30
+
+Disassembly of section \.got:
+
+.* <.got>:
+#check: GOTSTART format %x [expr "0x$GOTPAGE + $GOTOFFSET - 0x30"]
+ GOTSTART: .*
+ \.\.\.
+
+Disassembly of section \.data:
+
+.* <.*>:
+ \.\.\.
diff --git a/ld/testsuite/ld-aarch64/morello-undefweak-relocs-static-relocs.d b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-static-relocs.d
new file mode 100644
index 0000000000000000000000000000000000000000..7c81233db93d4a462c1792dc94fbe1e9fb13f532
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-static-relocs.d
@@ -0,0 +1,16 @@
+# Exercise handling morello relocations against weak undef symbols.
+#
+# What we want to check is:
+# 1) The adrp/ldr instructions point to entries in the GOT.
+# 2) There are no relocations in the GOT.
+# 3) The GOT entries for weak undefined symbols are zero.
+# 4) The values in .data are zero.
+#
+# The testcase morello-undefweak-relocs-static.d checks all except that there
+# are no relocations in the file. This testcase checks that last part.
+#source: morello-undefweak-relocs.s
+#as: -march=morello+c64
+#ld: -static
+#readelf: --relocs
+
+There are no relocations in this file.
diff --git a/ld/testsuite/ld-aarch64/morello-undefweak-relocs-static.d b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-static.d
new file mode 100644
index 0000000000000000000000000000000000000000..a7c5556d7b9d86946a346f2a0f7ccbaa2ba57bd0
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-undefweak-relocs-static.d
@@ -0,0 +1,51 @@
+# Exercise handling morello relocations against weak undef symbols.
+#
+# What we want to check is:
+# 1) The adrp/ldr instructions point to entries in the GOT.
+# 2) There are no relocations in the GOT.
+# 3) The GOT entries for weak undefined symbols are zero.
+# 4) The values in .data are zero.
+#
+# (1) is checked by ensuring that the adrp/ldr combinations point to increments
+# of 0x10 past the start of the got section.
+# (3) is checked by the fact that objdump prints for the .got section.
+# (4) is checked by the fact that objdump prints nothing for the data section
+# contents.
+#
+# Since objdump refuses to print out dynamic relocations for non-dynamic
+# executables, we check (2) in a separate testcase.
+#source: morello-undefweak-relocs.s
+#as: -march=morello+c64
+#ld: -static
+#objdump: -D -j .got -j .data -j .text
+
+
+.*: file format .*
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+#record: GOTPAGE
+.* adrp c0, ([0-9a-f]+) .*
+#record: GOTOFFSET
+.* ldr c0, \[c0, #([0-9]+)\]
+#check: PAGEG string tolower $GOTPAGE
+#check: GOTOFF2 expr "$GOTOFFSET - 0x10"
+#check: GOTOFF3 expr "$GOTOFFSET - 0x20"
+.* adrp c0, PAGEG .*
+.* ldr c0, \[c0, #GOTOFF2\]
+.* adrp c0, PAGEG .*
+.* ldr c0, \[c0, #GOTOFF3\]
+.* ret c30
+
+Disassembly of section \.got:
+
+#check: GOTSTART format %x [expr "0x$GOTPAGE + $GOTOFFSET - 0x30"]
+0*GOTSTART <_GLOBAL_OFFSET_TABLE_>:
+ \.\.\.
+
+Disassembly of section \.data:
+
+.* <.*>:
+ \.\.\.
diff --git a/ld/testsuite/ld-aarch64/morello-undefweak-relocs.s b/ld/testsuite/ld-aarch64/morello-undefweak-relocs.s
new file mode 100644
index 0000000000000000000000000000000000000000..7912c01aaa4fdce5ef3e8af526cfa8a0eda3d3ae
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-undefweak-relocs.s
@@ -0,0 +1,21 @@
+ .weak globalsym
+ .global globalsym
+ .weak localsym
+ .weak hiddensym
+ .hidden hiddensym
+
+ .data
+ .chericap globalsym
+ .chericap localsym
+ .chericap hiddensym
+
+ .text
+ .globl _start
+_start:
+ adrp c0, :got:globalsym
+ ldr c0, [c0, #:got_lo12:globalsym]
+ adrp c0, :got:hiddensym
+ ldr c0, [c0, #:got_lo12:hiddensym]
+ adrp c0, :got:localsym
+ ldr c0, [c0, #:got_lo12:localsym]
+ ret
diff --git a/ld/testsuite/ld-aarch64/morello-weakdefinitions.s b/ld/testsuite/ld-aarch64/morello-weakdefinitions.s
new file mode 100644
index 0000000000000000000000000000000000000000..5fba13ec7d48d5aecf0b89089689420a65a457b6
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-weakdefinitions.s
@@ -0,0 +1,18 @@
+# N.b. It should not matter what is contained in this file for the tests we
+# run. What we want to show is that the behavior of weak undefined symbols is
+# correct for dynamically linked PDE's. That requires linking to a shared
+# object which is the point of this separate assembly file.
+ .global globalsym
+ .type globalsym, %object
+globalsym:
+ .xword 100
+
+ .global hiddensym
+ .type hiddensym, %object
+hiddensym:
+ .xword 100
+
+ .global localsym
+ .type localsym, %object
+localsym:
+ .xword 100
Until now CAPINIT relocations were only emitted for position independent
code. For a data relocation against a symbol in some other shared
object this was problematic since we don't know the address that said
symbol will be at. We ended up emitting a broken RELATIVE relocation.
This also happened to be problematic for function pointers, since a
CAPINIT relocation did not ensure that a PLT entry was created in this
binary. When a PLT entry was not created we again had a broken RELATIVE
relocation.
We could have fixed the problem with function pointers by ensuring that
a CAPINIT relocation caused a PLT entry to be emitted and the RELATIVE
relocation hence to point to that PLT entry. Here we choose to always
emit a CAPINIT relocation and let the dynamic linker resolve that to a
local PLT entry if one exists, but if one does not exist let the dynamic
linker resolve it to the actual function in some other shared library.
Alongside this change we ensure that we leave 0 as the value in the
fragment for a CAPINIT relocation. The dynamic linker already has to
decide which symbol to use, and it would have the value of the local
symbol available if it chooses to use it. Hence there is no reason for
the static linker to leave the value of one option in the fragment of
this CAPINIT relocation.
This patch also introduces quite a few new testcases.
These are to check that we should only add a special PLT entry as the
canonical address for pointer equality when a function pointer is
accessed via code relocations -- and we ensure this does not happen for
accessing data pointers or accesses via CAPINIT data relocations.
Outside of the new testcases, we also adjust
emit-relocs-morello-3{,-a64c}.d. These testcases checked for a CAPINIT
relocation in a shared object. Now we no longer populate that fragment
we need to adjust the testcase accordingly.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 16447f15b05af3165b8bb2354437aa337ea3e304..dd1c28ad7e4352d9407b1b7a1d863a0cb293a9a4 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -7611,36 +7611,53 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
if (outrel.r_offset & 0xf)
return bfd_reloc_overflow;
- bfd_reloc_status_type ret;
-
- 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;
-
outrel.r_addend = signed_addend;
- value |= (h != NULL ? h->target_internal : sym->st_target_internal);
- /* Emit a dynamic relocation if we are building PIC. */
+ /* Emit a dynamic relocation if we are handling a symbol which the
+ dynamic linker will be told about. */
if (h != NULL
&& h->dynindx != -1
- && bfd_link_pic (info)
+ && globals->root.dynamic_sections_created
&& !SYMBOL_REFERENCES_LOCAL (info, h))
- outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
+ {
+ outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
+ /* Dynamic symbols will be handled by the dynamic loader. Hence
+ there is no need to fill a fragment with a value even if there
+ is a value that we would use assuming no interception. */
+ value = 0;
+ }
else
- outrel.r_info = ELFNN_R_INFO (0, MORELLO_R (RELATIVE));
-
- /* Symbols without size information get bounds to the
- whole section: adjust the base of the capability to the
- start of the section and set the addend to obtain the
- correct address for the symbol. */
- bfd_vma new_value;
- if (c64_symbol_adjust (h, value, sym_sec, info, &new_value))
{
- outrel.r_addend += (value - new_value);
- value = new_value;
+ /* This relocation will point into the object we are building
+ (either because this is a statically linked executable and
+ hence there is only one object it could point at, or because
+ we know it will resolve locally even though this is
+ dynamically linked).
+
+ Hence we want to emit a RELATIVE relocation rather than a
+ CAPINIT one. */
+ bfd_reloc_status_type ret;
+
+ value |= (h != NULL ? h->target_internal : sym->st_target_internal);
+ 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;
+
+ outrel.r_info = ELFNN_R_INFO (0, MORELLO_R (RELATIVE));
+
+ /* Symbols without size information get bounds to the
+ whole section: adjust the base of the capability to the
+ start of the section and set the addend to obtain the
+ correct address for the symbol. */
+ bfd_vma new_value;
+ if (c64_symbol_adjust (h, value, sym_sec, info, &new_value))
+ {
+ outrel.r_addend += (value - new_value);
+ value = new_value;
+ }
}
asection *s = globals->srelcaps;
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 19070408e990abbe50050b1cba183a6e4bf24934..235df2872084b5115239b671c5107b56a36b446f 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -91,6 +91,15 @@ proc aarch64_required_func_addend { base result } {
return [format %x [expr "0x$result + 1 - 0x$base"]];
}
+# Return the hexadecimal addition of the two given values. Values should be
+# provided in hexadecimal without the leading 0x prefix.
+#
+# Used in a testsuite to check that the combination of some ADRP/ADD constants
+# do indeed point at a variable later on in the dump.
+proc aarch64_page_plus_offset { page offset } {
+ return [format %x [expr "0x$page + 0x$offset"] ];
+}
+
set eh-frame-merge-lp64 [list [list "EH Frame merge" \
[concat "-m " [aarch64_choose_lp64_emul] \
" -Ttext 0x8000"] \
@@ -282,6 +291,14 @@ if { [ld_assemble_flags $as -march=morello+c64 $srcdir/$subdir/morello-dynamic-r
run_dump_test_lp64 "morello-dynamic-link-rela-dyn"
run_dump_test_lp64 "morello-dynamic-link-rela-dyn2"
run_dump_test_lp64 "morello-dynamic-local-got"
+ run_dump_test_lp64 "morello-funcptr-in-code"
+ run_dump_test_lp64 "morello-funcptr-through-data"
+ run_dump_test_lp64 "morello-funcptr-through-data-pie"
+ run_dump_test_lp64 "morello-funcptr-code-and-data"
+ run_dump_test_lp64 "morello-dataptr-in-code"
+ run_dump_test_lp64 "morello-dataptr-through-data"
+ run_dump_test_lp64 "morello-dataptr-through-data-pie"
+ run_dump_test_lp64 "morello-dataptr-code-and-data"
}
run_dump_test_lp64 "morello-static-got"
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-3-a64c.d b/ld/testsuite/ld-aarch64/emit-relocs-morello-3-a64c.d
index d596a53df90e6a73ee950e91187ecf72c86d7e13..f57aa48ca3feb1ab75d6162bb4c882ef0c86309f 100644
--- a/ld/testsuite/ld-aarch64/emit-relocs-morello-3-a64c.d
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-3-a64c.d
@@ -36,12 +36,9 @@ Disassembly of section .data:
.*: 00000000 .*
.* <cap>:
-.*: [0-9a-f]+ .*
+ \.\.\.
.*: R_MORELLO_CAPINIT str
-.*: 00000000 .*
-.*: 0000001b .*
-.*: 02000000 .*
.* <cap2>:
- ...
+ \.\.\.
.*: R_MORELLO_CAPINIT str2
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-3.d b/ld/testsuite/ld-aarch64/emit-relocs-morello-3.d
index fe248be367e98bc0720042b0c2ed9bab76427c86..7266ca94469966d71ef5fc3e6104f02125a74a08 100644
--- a/ld/testsuite/ld-aarch64/emit-relocs-morello-3.d
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-3.d
@@ -36,12 +36,9 @@ Disassembly of section .data:
.*: 00000000 .*
.* <cap>:
-.*: [0-9a-f]+ .*
+ \.\.\.
.*: R_MORELLO_CAPINIT str
-.*: 00000000 .*
-.*: 0000001b .*
-.*: 02000000 .*
.* <cap2>:
- ...
+ \.\.\.
.*: R_MORELLO_CAPINIT str2
diff --git a/ld/testsuite/ld-aarch64/morello-dataptr-code-and-data.d b/ld/testsuite/ld-aarch64/morello-dataptr-code-and-data.d
new file mode 100644
index 0000000000000000000000000000000000000000..6d19f2310ebc2d7ea53821247f0989e3b38b60f8
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dataptr-code-and-data.d
@@ -0,0 +1,35 @@
+# Want to double-check that when creating a PDE which loads a data pointer
+# in an external library using an adrp/ldr code sequence and also via a CAPINIT
+# relocation, we generate both a COPY relocation and a CAPINIT relocation.
+#
+# We want to make sure the COPY relocation is used by the text. We can not
+# check that the dynamic loader would initialize the CAPINIT relocation with
+# the address of that COPY relocation, so that's left.
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#objdump: -dR -j .data -j .bss -j .text
+
+.*: file format .*
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+#record: PAGE
+.*: .* adrp c0, ([0-9a-f]*).*
+#record: OFFSET
+.*: .* add c0, c0, #0x([0-9a-f]*)
+.*: .* ldr w0, \[c0\]
+.*: .* ret c30
+
+Disassembly of section \.data:
+#...
+ .*: R_MORELLO_CAPINIT var
+
+Disassembly of section \.bss:
+
+#check: VAR_LOCATION aarch64_page_plus_offset $PAGE $OFFSET
+0*VAR_LOCATION <var>:
+ \.\.\.
+ VAR_LOCATION: R_AARCH64_COPY var
+
diff --git a/ld/testsuite/ld-aarch64/morello-dataptr-code-and-data.s b/ld/testsuite/ld-aarch64/morello-dataptr-code-and-data.s
new file mode 100644
index 0000000000000000000000000000000000000000..85ae06b69093839674540cd69e9779b0a62fec18
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dataptr-code-and-data.s
@@ -0,0 +1,16 @@
+ .arch morello+crc+c64
+ .text
+ .p2align 4,,11
+ .global _start
+ .type _start, %function
+_start:
+ .cfi_startproc purecap
+ adrp c0, var
+ add c0, c0, #:lo12:var
+ ldr w0, [c0]
+ ret
+ .cfi_endproc
+ .size _start, .-_start
+ .data
+varptr:
+ .chericap var
diff --git a/ld/testsuite/ld-aarch64/morello-dataptr-in-code.d b/ld/testsuite/ld-aarch64/morello-dataptr-in-code.d
new file mode 100644
index 0000000000000000000000000000000000000000..4f54626d9b0699f8df0fb3670ff2de782690a620
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dataptr-in-code.d
@@ -0,0 +1,31 @@
+# Want to double-check that when creating a PDE which references a data pointer
+# in an external library in code with an adrp/add, we generate a COPY
+# relocation and access that the data said relocation will initialize.
+#
+# We check this by ensuring that there is a new `var` symbol in the .bss of the
+# PDE, that the adrp/add addresses point to that symbol, and that there is a
+# COPY relocation at that symbol for its initialisation.
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#objdump: -dR -j .plt -j .bss -j .text
+
+.*: file format .*
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+#record: PAGE
+.*: .* adrp c0, ([0-9a-f]*).*
+#record: OFFSET
+.*: .* add c0, c0, #0x([0-9a-f]*)
+.*: .* ldr w0, \[c0\]
+.*: .* ret c30
+
+Disassembly of section \.bss:
+
+#check: VAR_LOCATION aarch64_page_plus_offset $PAGE $OFFSET
+0*VAR_LOCATION <var>:
+ \.\.\.
+ VAR_LOCATION: R_AARCH64_COPY var
+
diff --git a/ld/testsuite/ld-aarch64/morello-dataptr-in-code.s b/ld/testsuite/ld-aarch64/morello-dataptr-in-code.s
new file mode 100644
index 0000000000000000000000000000000000000000..9babed420907e8a71b2a5e052dacfc2e443f78f7
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dataptr-in-code.s
@@ -0,0 +1,13 @@
+ .arch morello+crc+c64
+ .text
+ .p2align 4,,11
+ .global _start
+ .type _start, %function
+_start:
+ .cfi_startproc purecap
+ adrp c0, var
+ add c0, c0, #:lo12:var
+ ldr w0, [c0]
+ ret
+ .cfi_endproc
+ .size _start, .-_start
diff --git a/ld/testsuite/ld-aarch64/morello-dataptr-through-data-pie.d b/ld/testsuite/ld-aarch64/morello-dataptr-through-data-pie.d
new file mode 100644
index 0000000000000000000000000000000000000000..2270c33557617ac02d4291a7cb07299316446ce8
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dataptr-through-data-pie.d
@@ -0,0 +1,12 @@
+# Want to double-check that when creating a PIE which loads a data pointer
+# in an external library using a CAPINIT relocation we end up with a
+# straight-forward CAPINIT relocation in the final binary requesting the
+# dynamic loader to provide a capability pointing to that bit of data.
+#source: morello-dataptr-through-data.s
+#as: -march=morello+c64
+#ld: -pie tmpdir/morello-dynamic-relocs.so
+#readelf: --relocs
+
+Relocation section '\.rela\.dyn' at offset .* contains 1 entry:
+ Offset Info Type Sym\. Value Sym\. Name \+ Addend
+.* .* R_MORELLO_CAPINIT .* var \+ 0
diff --git a/ld/testsuite/ld-aarch64/morello-dataptr-through-data.d b/ld/testsuite/ld-aarch64/morello-dataptr-through-data.d
new file mode 100644
index 0000000000000000000000000000000000000000..0c42017ae48fea415d02e74c1b7a94c609d81183
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dataptr-through-data.d
@@ -0,0 +1,11 @@
+# Want to double-check that when creating a PDE which loads a data pointer
+# in an external library using a CAPINIT relocation we end up with a
+# straight-forward CAPINIT relocation in the final binary requesting the
+# dynamic loader to provide a capability pointing to that bit of data.
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#readelf: --relocs
+
+Relocation section '\.rela\.dyn' at offset .* contains 1 entry:
+ Offset Info Type Sym\. Value Sym\. Name \+ Addend
+.* .* R_MORELLO_CAPINIT .* var \+ 0
diff --git a/ld/testsuite/ld-aarch64/morello-dataptr-through-data.s b/ld/testsuite/ld-aarch64/morello-dataptr-through-data.s
new file mode 100644
index 0000000000000000000000000000000000000000..9b56a256f4bdc9c4e9810260c71444d82b8fd1f6
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dataptr-through-data.s
@@ -0,0 +1,13 @@
+ .arch morello+crc+c64
+ .text
+ .p2align 4,,11
+ .global _start
+ .type _start, %function
+_start:
+ .cfi_startproc purecap
+ ret
+ .cfi_endproc
+ .size _start, .-_start
+ .data
+varptr:
+ .chericap var
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-relocs-lib.s b/ld/testsuite/ld-aarch64/morello-dynamic-relocs-lib.s
index 80e84e5bc847a99b21c1da515749a3362842a641..2b4e058cc0383e0dbb98ca8fdf7e97fab92bb3da 100644
--- a/ld/testsuite/ld-aarch64/morello-dynamic-relocs-lib.s
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-relocs-lib.s
@@ -1,5 +1,11 @@
.arch morello+crc+c64
.text
+ .p2align 4,,11
+ .global memcpy
+ .type memcpy,%function
+memcpy:
+ ret
+ .size memcpy, .-memcpy
.global var
.bss
.align 2
diff --git a/ld/testsuite/ld-aarch64/morello-funcptr-code-and-data.d b/ld/testsuite/ld-aarch64/morello-funcptr-code-and-data.d
new file mode 100644
index 0000000000000000000000000000000000000000..c8cfff8268e940d2bfc4a7f669c8c9e3e595cf26
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-funcptr-code-and-data.d
@@ -0,0 +1,26 @@
+# Want to double-check that when creating a PDE which references a function
+# pointer in an external library with a CAPINIT and also references the
+# function pointer in code with an adrp/add, we generate a CAPINIT
+# entry in that PDE and also generate a PLT entry.
+# We check this by ensuring that there is a memcpy@plt entry in the PLT, that
+# there is the associated MORELLO jump slot relocation in the .got.plt, and
+# there is a CAPINIT relocation.
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#objdump: -dR -j .plt -j .data -j .got.plt
+
+.*: file format .*
+
+Disassembly of section \.plt:
+#...
+.* <memcpy@plt>:
+#...
+Disassembly of section \.got\.plt:
+#...
+.*: R_MORELLO_JUMP_SLOT memcpy
+#...
+Disassembly of section \.data:
+
+.* <p>:
+ \.\.\.
+ .*: R_MORELLO_CAPINIT memcpy
diff --git a/ld/testsuite/ld-aarch64/morello-funcptr-code-and-data.s b/ld/testsuite/ld-aarch64/morello-funcptr-code-and-data.s
new file mode 100644
index 0000000000000000000000000000000000000000..489fa7c114f190433f98c411549a8574e91777f2
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-funcptr-code-and-data.s
@@ -0,0 +1,21 @@
+ .arch morello+crc+c64
+ .text
+ .p2align 4,,11
+ .global _start
+ .type _start, %function
+_start:
+ .cfi_startproc purecap
+ adrp c0, memcpy
+ ldr c0, [c0, #:lo12:memcpy]
+ ldr w0, [c0]
+ ret
+ .cfi_endproc
+ .size _start, .-_start
+ .global p
+ .section .data.rel,"aw"
+ .align 4
+ .type p, %object
+ .size p, 16
+p:
+ .chericap memcpy
+
diff --git a/ld/testsuite/ld-aarch64/morello-funcptr-in-code.d b/ld/testsuite/ld-aarch64/morello-funcptr-in-code.d
new file mode 100644
index 0000000000000000000000000000000000000000..9bcb7d3397ad3a3527bf8e542884706f8e0bb954
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-funcptr-in-code.d
@@ -0,0 +1,21 @@
+# Want to double-check that when creating a PDE which loads a function pointer
+# in an external library using an adrp/ldr code sequence, we generate a PLT
+# entry in that PDE and use that PLT entry as the address that is loaded in the
+# code.
+# We check this by ensuring that there is a memcpy@plt entry in the PLT, and
+# that the .got.plt has a MORELLO jump slot relocation in it.
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#objdump: -dR -j .plt -j .got.plt
+
+.*: file format .*
+
+
+Disassembly of section \.plt:
+#...
+.* <memcpy@plt>:
+#...
+Disassembly of section \.got\.plt:
+#...
+.*: R_MORELLO_JUMP_SLOT memcpy
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-funcptr-in-code.s b/ld/testsuite/ld-aarch64/morello-funcptr-in-code.s
new file mode 100644
index 0000000000000000000000000000000000000000..6bc38a12c7a6e6f90a39ce76a31b6da5d80fe023
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-funcptr-in-code.s
@@ -0,0 +1,13 @@
+ .text
+ .p2align 4,,11
+ .global _start
+ .type _start, %function
+_start:
+ .cfi_startproc purecap
+ adrp c0, memcpy
+ add c0, c0, #:lo12:memcpy
+ ldr w0, [c0]
+ ret
+ .cfi_endproc
+ .size _start, .-_start
+
diff --git a/ld/testsuite/ld-aarch64/morello-funcptr-through-data-pie.d b/ld/testsuite/ld-aarch64/morello-funcptr-through-data-pie.d
new file mode 100644
index 0000000000000000000000000000000000000000..5f5b20198e911cd24a45c340568c86b2883a0d62
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-funcptr-through-data-pie.d
@@ -0,0 +1,19 @@
+# Want to double-check that when creating a PIE which references a function
+# pointer in an external library with a CAPINIT and does not reference the
+# function pointer in code with an adrp/add, we generate a CAPINIT
+# entry in that PIE and do not generate a PLT entry.
+# We check this by ensuring that there is no memcpy@plt entry in the PLT, and
+# by checking there is a CAPINIT relocation.
+#source: morello-funcptr-through-data.s
+#as: -march=morello+c64
+#ld: -pie tmpdir/morello-dynamic-relocs.so
+#objdump: -dR -j .plt -j .data
+
+.*: file format .*
+
+Disassembly of section \.data:
+
+.* <p>:
+ \.\.\.
+ .*: R_MORELLO_CAPINIT memcpy
+
diff --git a/ld/testsuite/ld-aarch64/morello-funcptr-through-data.d b/ld/testsuite/ld-aarch64/morello-funcptr-through-data.d
new file mode 100644
index 0000000000000000000000000000000000000000..1b0d13f3da79991865e6f02c1a9bcfd7d1a190b8
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-funcptr-through-data.d
@@ -0,0 +1,17 @@
+# Want to double-check that when creating a PDE which references a function
+# pointer in an external library with a CAPINIT and does not reference the
+# function pointer in code with an adrp/add, we generate a CAPINIT
+# entry in that PDE and do not generate a PLT entry.
+# We check this by ensuring that there is no memcpy@plt entry in the PLT, and
+# by checking there is a CAPINIT relocation.
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#objdump: -dR -j .plt -j .data
+
+.*: file format .*
+
+Disassembly of section \.data:
+
+.* <p>:
+ \.\.\.
+ .*: R_MORELLO_CAPINIT memcpy
diff --git a/ld/testsuite/ld-aarch64/morello-funcptr-through-data.s b/ld/testsuite/ld-aarch64/morello-funcptr-through-data.s
new file mode 100644
index 0000000000000000000000000000000000000000..1782a7fa94a22e44b1c86955a549d25afb2f4418
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-funcptr-through-data.s
@@ -0,0 +1,18 @@
+ .arch morello+crc+c64
+ .text
+ .p2align 4,,11
+ .global _start
+ .type _start, %function
+_start:
+ .cfi_startproc purecap
+ ret
+ .cfi_endproc
+ .size _start, .-_start
+ .global p
+ .section .data.rel,"aw"
+ .align 4
+ .type p, %object
+ .size p, 16
+p:
+ .chericap memcpy
+
Each symbol that has a reference in the GOT has an associated got_type.
For capabilities we currently have a new got_type of GOT_CAP for
capability entries in the GOT.
We do not allow capability entries in the GOT for an A64 (or hybrid)
binary, and only allow capability entries in the GOT for a purecap
binary. Hence there is no need to maintain a per-symbol indication of
whether the associated GOT entry for this symbol is a capability or not.
There is already an existing flag on the hash table to indicate whether
the GOT contains capabilities or addresses. We can replace every use of
the existing GOT_CAP with a check of this flag.
Doing such a transformation means we can not express an invalid state
(there is no longer any way to express a GOT which contains some
addresses and some capabilities). It also solves a bug where we
introduce a PLT to be the canonical address of a function after having
seen a R_AARCH64_LDST128_ABS_LO12_NC relocation. The existing manner of
deciding whether an entry in the GOT should be a capability or address
based on the relocation we generated it from could not work in a binary
when we only have this relocation. It should be determined based on the
flags of the input object files we saw (i.e. are these purecap object
files or not).
N.b. this also fixes an observed problem that could have been fixed in
the existing regime. In this case the JUMP_SLOT of a PLT entry added to
be the canonical address of a function which was addressed directly in
code (with both a Morello and AArch64 relocation) had got_type of
GOT_UNKNOWN (because it was simply not marked) and hence
elfNN_aarch64_create_small_pltn_entry was generating an AArch64
relocation because the GOT entry was not GOT_CAP.
This patch also adjusts the "should this GOT contain capabilities" flag
to report yes/no based on the EF_AARCH64_CHERI_PURECAP flag of the
inputs rather than based on whether we've seen any morello relocations
pointing into the GOT.
NOTE: We do not remove the existing times where we set this flag based
on MORELLO relocations. This is left for a future patch when we look
into the handling of hybrid code and the GOT.
N.b. this required two changes in the testsuite.
morello-capinit.d required updating since the size of the GOT section
was previously incorrectly calculated. There is no GOT relocation in
this testcase, which meant that the existing method of finding the size
of the dummy first GOT entry was incorrect (gave the size of an AArch64
entry). Since the size of the GOT is now different the PCC bounds is
now different, and we hence need to update the values checking for the
PCC bounds in this testcase.
We take this opportunity to make the testcase more robust by using the
new record/check testsuite feature. This means the testcase now passes
on other targets (i.e. both bare-metal and for none-linux).
emit-relocs-morello.d had a minor change for the same reason. Since the
alignment requirement of the GOT changed this changed the start position
too. When the start position changed objdump decided not to output an
extra line of 0000000.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 76216f8f00125e8c22cacbe8b5610b4b1d105eb4..16447f15b05af3165b8bb2354437aa337ea3e304 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -3000,7 +3000,6 @@ elfNN_aarch64_mkobject (bfd *abfd)
#define GOT_TLS_GD 2
#define GOT_TLS_IE 4
#define GOT_TLSDESC_GD 8
-#define GOT_CAP 16
#define GOT_TLS_GD_ANY_P(type) ((type & GOT_TLS_GD) || (type & GOT_TLSDESC_GD))
@@ -5915,7 +5914,7 @@ aarch64_reloc_got_type (bfd_reloc_code_real_type r_type)
case BFD_RELOC_MORELLO_ADR_GOT_PAGE:
case BFD_RELOC_MORELLO_LD128_GOT_LO12_NC:
- return GOT_CAP;
+ return GOT_NORMAL;
case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
@@ -5930,7 +5929,7 @@ aarch64_reloc_got_type (bfd_reloc_code_real_type r_type)
case BFD_RELOC_MORELLO_TLSDESC_ADR_PAGE20:
case BFD_RELOC_MORELLO_TLSDESC_CALL:
case BFD_RELOC_MORELLO_TLSDESC_LD128_LO12:
- return GOT_TLSDESC_GD | GOT_CAP;
+ return GOT_TLSDESC_GD | GOT_NORMAL;
case BFD_RELOC_AARCH64_TLSDESC_ADD:
case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
@@ -6775,8 +6774,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
|| bfd_link_executable (info))
{
/* This symbol is resolved locally. */
- outrel.r_info = (elf_aarch64_hash_entry (h)->got_type
- == GOT_CAP
+ outrel.r_info = (globals->c64_rel
? ELFNN_R_INFO (0, MORELLO_R (IRELATIVE))
: ELFNN_R_INFO (0, AARCH64_R (IRELATIVE)));
outrel.r_addend = (h->root.u.def.value
@@ -8827,6 +8825,15 @@ elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
return TRUE;
elf_elfheader (obfd)->e_flags = in_flags;
+ /* Determine if we are linking purecap or not based on the flags of the
+ input binaries. Among other things this decides the size of GOT
+ entries. */
+ if (in_flags & EF_AARCH64_CHERI_PURECAP)
+ {
+ struct elf_aarch64_link_hash_table *globals;
+ globals = elf_aarch64_hash_table (info);
+ globals->c64_rel = 1;
+ }
if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
&& bfd_get_arch_info (obfd)->the_default)
@@ -9295,12 +9302,6 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
case BFD_RELOC_MORELLO_CALL26:
case BFD_RELOC_MORELLO_JUMP26:
- /* For dynamic symbols record caller information so that we can
- decide what kind of PLT stubs to emit. */
- if (h != NULL)
- elf_aarch64_hash_entry (h)->got_type = GOT_CAP;
- /* Fall through. */
-
case BFD_RELOC_AARCH64_ADD_LO12:
case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
case BFD_RELOC_MORELLO_ADR_GOT_PAGE:
@@ -9581,9 +9582,8 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* We will already have issued an error message if there
is a TLS/non-TLS mismatch, based on the symbol type.
So just combine any TLS types needed. */
- if (old_got_type != GOT_UNKNOWN && old_got_type != GOT_NORMAL
- && got_type != GOT_NORMAL && old_got_type != GOT_CAP
- && got_type != GOT_CAP)
+ if (old_got_type != GOT_UNKNOWN && old_got_type != GOT_NORMAL &&
+ got_type != GOT_NORMAL)
got_type |= old_got_type;
/* If the symbol is accessed by both IE and GD methods, we
@@ -9593,13 +9593,6 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
if ((got_type & GOT_TLS_IE) && GOT_TLS_GD_ANY_P (got_type))
got_type &= ~ (GOT_TLSDESC_GD | GOT_TLS_GD);
- /* Prefer the capability reference. */
- if ((old_got_type & GOT_CAP) && (got_type & GOT_NORMAL))
- {
- got_type &= ~GOT_NORMAL;
- got_type |= GOT_CAP;
- }
-
if (old_got_type != got_type)
{
if (h != NULL)
@@ -9623,9 +9616,6 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info,
case BFD_RELOC_MORELLO_CALL26:
case BFD_RELOC_MORELLO_JUMP26:
htab->c64_rel = 1;
- if (h != NULL)
- elf_aarch64_hash_entry (h)->got_type = GOT_CAP;
-
/* Fall through. */
case BFD_RELOC_AARCH64_CALL26:
case BFD_RELOC_AARCH64_JUMP26:
@@ -10221,8 +10211,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if (got_type == GOT_UNKNOWN)
{
}
- else if (got_type == GOT_NORMAL
- || got_type == GOT_CAP)
+ else if (got_type == GOT_NORMAL)
{
h->got.offset = htab->root.sgot->size;
htab->root.sgot->size += GOT_ENTRY_SIZE (htab);
@@ -10235,11 +10224,11 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
/* Any capability relocations required in a dynamic binary
should go in the srelgot. */
- || ((got_type == GOT_CAP) && dyn))
+ || (htab->c64_rel && dyn))
{
htab->root.srelgot->size += RELOC_SIZE (htab);
}
- else if (bfd_link_executable (info) && (got_type == GOT_CAP))
+ else if (bfd_link_executable (info) && htab->c64_rel)
{
/* If we have a capability relocation that is not handled by the
case above then this must be a statically linked executable. */
@@ -10279,7 +10268,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)
/* On Morello support only TLSDESC_GD to TLSLE relaxation;
for everything else we must emit a dynamic relocation. */
- || got_type & GOT_CAP))
+ || htab->c64_rel))
{
if (got_type & GOT_TLSDESC_GD)
{
@@ -10562,8 +10551,7 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd,
}
if (got_type & GOT_TLS_IE
- || got_type & GOT_NORMAL
- || got_type & GOT_CAP)
+ || got_type & GOT_NORMAL)
{
locals[i].got_offset = htab->root.sgot->size;
htab->root.sgot->size += GOT_ENTRY_SIZE (htab);
@@ -10586,17 +10574,16 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd,
htab->root.srelgot->size += RELOC_SIZE (htab) * 2;
if (got_type & GOT_TLS_IE
- || got_type & GOT_NORMAL
- || got_type & GOT_CAP)
+ || got_type & GOT_NORMAL)
htab->root.srelgot->size += RELOC_SIZE (htab);
}
/* Static binary; put relocs into srelcaps. */
else if (bfd_link_executable (info)
&& !htab->root.dynamic_sections_created
- && (got_type & GOT_CAP))
+ && htab->c64_rel)
htab->srelcaps->size += RELOC_SIZE (htab);
/* Else capability relocation needs to go into srelgot. */
- else if (got_type & GOT_CAP)
+ else if (htab->c64_rel)
htab->root.srelgot->size += RELOC_SIZE (htab);
}
else
@@ -10917,7 +10904,7 @@ elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
{
/* If an STT_GNU_IFUNC symbol is locally defined, generate
R_AARCH64_IRELATIVE instead of R_AARCH64_JUMP_SLOT. */
- rela.r_info = (elf_aarch64_hash_entry (h)->got_type == GOT_CAP
+ rela.r_info = (htab->c64_rel
? ELFNN_R_INFO (0, MORELLO_R (IRELATIVE))
: ELFNN_R_INFO (0, AARCH64_R (IRELATIVE)));
rela.r_addend = (h->root.u.def.value
@@ -10927,7 +10914,7 @@ elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h,
else
{
/* Fill in the entry in the .rela.plt section. */
- rela.r_info = (elf_aarch64_hash_entry (h)->got_type == GOT_CAP
+ rela.r_info = (htab->c64_rel
? ELFNN_R_INFO (h->dynindx, MORELLO_R (JUMP_SLOT))
: ELFNN_R_INFO (h->dynindx, AARCH64_R (JUMP_SLOT)));
rela.r_addend = 0;
@@ -11047,11 +11034,8 @@ elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
}
}
- bfd_boolean is_c64 = elf_aarch64_hash_entry (h)->got_type == GOT_CAP;
-
if (h->got.offset != (bfd_vma) - 1
- && (elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL
- || elf_aarch64_hash_entry (h)->got_type == GOT_CAP)
+ && elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL
/* Undefined weak symbol in static PIE resolves to 0 without
any dynamic relocations. */
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
@@ -11104,7 +11088,7 @@ elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
bfd_vma value = h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset;
- if (is_c64)
+ if (htab->c64_rel)
{
rela.r_info = ELFNN_R_INFO (0, MORELLO_R (RELATIVE));
bfd_vma base_value = 0;
@@ -11127,7 +11111,8 @@ elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
bfd_put_NN (output_bfd, (bfd_vma) 0,
htab->root.sgot->contents + h->got.offset);
rela.r_info = ELFNN_R_INFO (h->dynindx,
- (is_c64 ? MORELLO_R (GLOB_DAT)
+ (htab->c64_rel
+ ? MORELLO_R (GLOB_DAT)
: AARCH64_R (GLOB_DAT)));
rela.r_addend = 0;
}
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello.d b/ld/testsuite/ld-aarch64/emit-relocs-morello.d
index 4613b776edbe5b900386da94b450b3f16d416440..1a9be9b60bb9fcf15d74e65e9ebe224ac3d769b8 100644
--- a/ld/testsuite/ld-aarch64/emit-relocs-morello.d
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello.d
@@ -21,7 +21,7 @@ Disassembly of section .got:
.* <.got>:
.*: [0-9a-f]+ .*
-.*: 00000000 .*
+ \.\.\.
Disassembly of section .data:
diff --git a/ld/testsuite/ld-aarch64/morello-capinit.d b/ld/testsuite/ld-aarch64/morello-capinit.d
index 0050df311ac03275d00d69bb57ad7ab48f92eeea..edb0f42d9eeb83e4cd81018ab3de1932d07bbb45 100644
--- a/ld/testsuite/ld-aarch64/morello-capinit.d
+++ b/ld/testsuite/ld-aarch64/morello-capinit.d
@@ -1,6 +1,6 @@
-# This testsuite is used largely to check our handling of linker script defined
+# This testcase is used largely to check our handling of linker script defined
# symbols. In the general case we want to be able to access the entire output
-# section following this symbol (i.e. we treat this symbol as a start symbol).
+# section following the symbol (i.e. we treat the symbol as a start symbol).
#
# There is an exception for a symbol that points into an executable section --
# we want this to have the bounds of the PCC as we see it.
@@ -8,6 +8,12 @@
# There is also an exception for a symbol which is *outside* of an output
# section where we have a compatibility hack to try and guess whether it
# represents the start of the next section or end of the previous section.
+#
+# Rather than check the PCC bounds exactly, we check that the PCC bounds are
+# consistent for all symbols pointing into the text section (which allows for
+# variation between aarch64-linux-gnu and aarch64-none-elf coming from an extra
+# GNU_HASH section or a differing start position of the text causing a
+# differing bounds action).
#source: morello-capinit.s
#as: -march=morello+c64
#ld: -static -pie -T morello-capinit.ld
@@ -22,35 +28,37 @@ Disassembly of section \.inspectionsection:
.*: [0-9a-f]+ .*
.*: R_MORELLO_RELATIVE \*ABS\*
.*: 00000000 .*
-.*: 00000278 .*
+#record: PCC_BOUNDS
+.*: ([0-9a-f]+) .*
.*: 04000000 .*
+#check: PCC_SIZE string tolower $PCC_BOUNDS
[0-9a-f]+ <ct_start>:
.*: [0-9a-f]+ .*
.*: R_MORELLO_RELATIVE \*ABS\*
.*: 00000000 .*
-.*: 00000278 .*
+.*: PCC_SIZE .*
.*: 04000000 .*
[0-9a-f]+ <ct1_start>:
.*: [0-9a-f]+ .*
.*: R_MORELLO_RELATIVE \*ABS\*\+0x[0-9a-f]+
.*: 00000000 .*
-.*: 00000278 .*
+.*: PCC_SIZE .*
.*: 04000000 .*
[0-9a-f]+ <ct1_end>:
.*: [0-9a-f]+ .*
.*: R_MORELLO_RELATIVE \*ABS\*\+0x[0-9a-f]+
.*: 00000000 .*
-.*: 00000278 .*
+.*: PCC_SIZE .*
.*: 04000000 .*
[0-9a-f]+ <ct_end>:
.*: [0-9a-f]+ .*
.*: R_MORELLO_RELATIVE \*ABS\*\+0x[0-9a-f]+
.*: 00000000 .*
-.*: 00000278 .*
+.*: PCC_SIZE .*
.*: 04000000 .*
[0-9a-f]+ <cd_outer_start>:
For dynamic symbol GOT entries, the linker emits relocations for that
entry in finish_dynamic_symbol.
Since Morello capabilities always need dynamic relocations to initialise
GOT entries at runtime, we need to emit relocations for any capability
GOT entries. Two examples which are not needed for non-Morello linking
are static linking and for global symbols defined and referenced in a
PDE.
In order to ensure we emit those relocations we catch them in the
existing clause of final_link_relocate that looks for GOT entries that
require relocations which are not handled by finish_dynamic_symbol.
Before this patch, the clause under which those relocations were emitted
would include dynamic GOT entries in dynamically linked position
dependent executables.
These symbols hence had RELATIVE relocations emitted to initialise them
in the executables GOT by final_link_relocate, and GLOB_DAT relocations
emitted to initialise them by finish_dynamic_symbol.
The RELATIVE relocation is incorrect to use, since the static linker
does not know the value of this symbol at runtime (i.e. it does not know
the location in memory that the the shared library will be loaded).
This patch ensures that the clause in final_link_relocate does not
catch such dynamic GOT entries by ensuring that we only catch symbols
when we would not otherwise call finish_dynamic_symbol.
N.b. we also add an assertion in the condition-guarded block, partly to
catch similar problems earlier, but mainly to make it clear that
`relative_reloc` should not be set when finish_dynamic_symbol will be
called.
N.b.2 The bfd_link_pic check is a little awkward to understand.
Due to the definition of WILL_CALL_FINISH_DYNAMIC_SYMBOL, the only time
that `!bfd_link_pic (info) && !WILL_CALL_FINISH_DYNAMIC_SYMBOL` is false
and
`!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dynamic, bfd_link_pic (info), h)`
is true is when the below holds:
is_dynamic && !h->forced_local && h->dynindx == -1
This clause is looking for local GOT relocations that are not in the
dynamic symbol table, in a binary that will have dynamic sections.
This situation is the case that this clause was originally added to
handle (before the Morello specific code was added). It is the case
when we need a RELATIVE relocation because we have a PIC object, but
finish_dynamic_symbol would not be called on the symbol.
Since all capability GOT entries need relocations to initialise them it
would seem unnecessary to include the bfd_link_pic check in our Morello
clause. However the existing clause handling these relocations for
AArch64 specifically avoids adding a relocation for
bfd_link_hash_undefweak symbols. By keeping the `!bfd_link_pic (info)`
clause in the Morello part of this condition we ensure such undefweak
symbols are still avoided.
I do not believe it is possible to trigger the above case that requires
this `bfd_link_pic` clause (where we have a GOT relocation against a
symbol satisfying):
h->dynindx == -1 && !h->forced_local
&& h->root.type == bfd_link_hash_undefweak
&& bfd_link_pic (info) && bfd_link_executable (info)
I believe this is because when creating an undefweak symbol that has a
GOT reference we hit the clause in elfNN_aarch64_allocate_dynrelocs
which ensures that such symbols are put in `.dynsym` (and hence have a
`h->dynindx != -1`). A useful commit to reference for understanding
this is ff07562f1e.
Hence there is no testcase for this part. We do add some code that
exercises the relevant case (but does not exercise this particular
clause) into the morello-dynamic-link-rela-dyn testcase.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 88573828da7461238a20013aefb538a296ced99e..76216f8f00125e8c22cacbe8b5610b4b1d105eb4 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -7244,17 +7244,28 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
should only generate one RELATIVE relocation for that symbol.
Therefore, check GOT offset mark first.
- NOTE2: Symbol references via GOT in C64 static binaries without
- PIC should always have relative relocations, so we do that here
- early. */
+ NOTE2: Symbol references via GOT in C64 should always have
+ relocations of some kind. Here we try to catch any such GOT
+ reference which would not otherwise be caught by
+ finish_dynamic_symbol. */
if (((h->dynindx == -1
&& !h->forced_local
&& h->root.type != bfd_link_hash_undefweak
&& bfd_link_pic (info))
- || (!bfd_link_pic (info) && bfd_link_executable (info)
- && c64_reloc))
+ || (!bfd_link_pic (info)
+ && !WILL_CALL_FINISH_DYNAMIC_SYMBOL
+ (is_dynamic, bfd_link_pic (info), h)
+ && bfd_link_executable (info) && c64_reloc))
&& !symbol_got_offset_mark_p (input_bfd, h, r_symndx))
{
+ /* If we would call finish_dynamic_symbol for this symbol then we
+ should not be introducing a relocation for the GOT entry
+ (that function handles creating relocations for the GOT entry
+ in the usual case, this bit of code is to handle special
+ cases where the relocation would not otherwise be generated).
+ */
+ BFD_ASSERT (!WILL_CALL_FINISH_DYNAMIC_SYMBOL
+ (is_dynamic, bfd_link_pic (info), h));
relative_reloc = TRUE;
c64_needs_frag_fixup = c64_reloc ? TRUE : FALSE;
}
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index ba0b65a8aba4dacbcb0dd353bc2f81743780f2c7..19070408e990abbe50050b1cba183a6e4bf24934 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -278,6 +278,7 @@ run_dump_test_lp64 "c64-ehdr-sized-reloc"
# we need to specify different `ld` command lines for different objects.
if { [ld_assemble_flags $as -march=morello+c64 $srcdir/$subdir/morello-dynamic-relocs-lib.s tmpdir/morello-dynamic-relocs-lib.o]
&& [ld_link $ld tmpdir/morello-dynamic-relocs.so "--shared tmpdir/morello-dynamic-relocs-lib.o"] } {
+ run_dump_test_lp64 "morello-dynamic-relocs"
run_dump_test_lp64 "morello-dynamic-link-rela-dyn"
run_dump_test_lp64 "morello-dynamic-link-rela-dyn2"
run_dump_test_lp64 "morello-dynamic-local-got"
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.s b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.s
index 3cffb35a8b82e93aa45acc841f0f661a320f4849..cf6f0bfea613926049595d225c4d685b46bc9ac5 100644
--- a/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.s
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.s
@@ -6,6 +6,8 @@
_start:
.LFB0:
.cfi_startproc purecap
+ adrp c0, :got:undefweakval
+ ldr c0, [c0, #:got_lo12:undefweakval]
adrp c0, :got:weakval
ldr c0, [c0, #:got_lo12:weakval]
adrp c0, :got:globval
@@ -39,3 +41,4 @@ weakval:
.byte 0x1
.byte 0x1
.size weakval, .-weakval
+ .weak undefweakval
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn2.d b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn2.d
index 9de0c5f4f362ba8fb2d6c83624f22b4feae839f2..dcdd02606c38e6f1ad8c551a88577c2da2e9bbc1 100644
--- a/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn2.d
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn2.d
@@ -3,12 +3,20 @@
#source: morello-dynamic-link-rela-dyn.s
#as: -march=morello+c64
#ld: tmpdir/morello-dynamic-relocs.so
-#readelf: --relocs
+#readelf: --relocs --dyn-sym
-Relocation section '\.rela\.dyn' at offset .* contains 5 entries:
+Relocation section '\.rela\.dyn' at offset .* contains 6 entries:
Offset Info Type Sym\. Value Sym\. Name \+ Addend
.* 00000000e803 R_MORELLO_RELATIV 0
.* 00000000e803 R_MORELLO_RELATIV 0
.* 00000000e803 R_MORELLO_RELATIV 0
.* 00000000e803 R_MORELLO_RELATIV 0
-.* 00010000e801 R_MORELLO_GLOB_DA 0000000000000000 var \+ 0
+.* 00010000e801 R_MORELLO_GLOB_DA 0000000000000000 undefweakval \+ 0
+.* 00020000e801 R_MORELLO_GLOB_DA 0000000000000000 var \+ 0
+
+Symbol table '\.dynsym' contains [34] entries:
+ Num: Value Size Type Bind Vis Ndx Name
+ 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
+ 1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND undefweakval
+ 2: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND var
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-relocs.d b/ld/testsuite/ld-aarch64/morello-dynamic-relocs.d
new file mode 100644
index 0000000000000000000000000000000000000000..c7cfbd91626c97a1429f6b4a16606031dac8e256
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-relocs.d
@@ -0,0 +1,16 @@
+# Test here is to ensure that we only emit one relocation into the GOT for the
+# one use of a GOT entry. This is already checked by the fact that the last
+# linker command would hit an assertion failure if it were not the case.
+# We check that there is only one relocation in the resulting binary anway,
+# since double-checking is always nice.
+#
+# N.b. aarch64-elf.exp compiles a shared libary for this test under
+# tmpdir/morello-dynamic-relocs.so. We use that shared library for the test in
+# the `ld` command below.
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#readelf: --relocs
+
+Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
+ Offset Info Type Sym\. Value Sym\. Name \+ Addend
+[0-9a-f]+ [0-9a-f]+ R_MORELLO_GLOB_DA 0000000000000000 var \+ 0
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-relocs.s b/ld/testsuite/ld-aarch64/morello-dynamic-relocs.s
new file mode 100644
index 0000000000000000000000000000000000000000..6a4e862471b63d3740171374aba0c885b6278762
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-relocs.s
@@ -0,0 +1,15 @@
+ .arch morello+crc+c64
+ .text
+ .align 2
+ .global _start
+ .type _start, %function
+_start:
+.LFB0:
+ .cfi_startproc purecap
+ adrp c0, :got:var
+ ldr c0, [c0, #:got_lo12:var]
+ str wzr, [c0]
+ ret
+ .cfi_endproc
+.LFE0:
+ .size _start, .-_start
This patch clears up some confusing checks around where to place
capability relocations initialising GOT entries.
Our handling of capability entries for the GOT had a common mistake in
the predicates that we used. Statically linked executables need to have
all capability relocations contiguous in order to be able to mark their
start and end with __rela_dyn_{start,end} symbols. These symbols are
used by the runtime to find dynamic capability relocations that must be
performed. They are not needed when dynamically linking as then it is
the responsibility of the dynamic loader to perform these relocations.
We generally used `bfd_link_executable (info) && !bfd_link_pic (info)`
to check for statically linked executables. This predicate includes
dynamically linked PDE's. In most cases seen we do not want to include
dynamically linked PDE's.
This problem manifested in a few different ways. When the srelcaps
section was non-empty we would generate the __rela_dyn_{start,end}
symbols -- which meant that these would be unnecessarily emitted for
dynamically linked PDE's. In one case we erroneously increased the size
of this section on seeing non-capability relocations, and since no
relocations were actually added we would see a set of uninitialised
relocations.
Here we inspected all places in the code handling the srelcaps section
and identified 5 problems. We add tests for those problems which can
be seen (some of the problems are only problems once others have been
fixed) and fix them all.
Below we describe what was happening for each of the problems in turn:
---
Avoid non-capability relocations during srelcaps sizing
elfNN_aarch64_allocate_dynrelocs increases the size for relocation
sections based on the number of dynamic symbol relocations.
When increasing the size of the section in which we store capability
relocations (recorded as srelcaps in the link hash table) our
conditional erroneously included non-capability relocations. We were
hence allocating space in a section like .rela.dyn for relocations
populating the GOT with addresses of non-capability symbols in a
statically linked executable (for non-Morello compilation).
This change widens the original if clause so it should catch CAP
relocations that should go in srelgot, and tightens the fallback else if
clause in allocate_dynrelocs to only act on capability entries in the
GOT, since those are the only ones not already caught which still need
relocations to populate.
Implementation notes:
While not necessary, we also stop the fallback conditional checking
!bfd_link_pic and instead put an assertion that we only ever enter the
conditions block in the case of !bfd_link_pic && !dynamic.
This is done to emphasise that this condition is there to account for
all the capability GOT entries for the hash table which need relocations
and are not caught by the existing code. The fact that this should only
happen when building static executables seems like an emergent property
rather than the thing we would want to check against.
This is tested with no-morello-syms-static.
---
size_dynamic_sections use srelcaps for statically linked executables
and srelgot for dynamically linked binaries.
When creating a statically linked executable the srelcaps section will
always be initialised and that is where we should put all capability
relocations. When creating a dynamically linked executable the srelcaps
may or may not be initialised (depending on if we saw CAPINIT
relocations) and either way we should put GOT relocations into the
srelgot section.
Though there is no functional change to look for, this code path is
exercised with the morello-static-got test and
morello-dynamic-link-rela-dyn for statically linked and dynamically
linked PDE's respectively.
---
Capability GOT relocations go in .rela.got for dynamically linked PDEs
final_link_relocate generates GOT relocations for entries in the GOT
that are not handled by the generic ELF relocation code. For Morello
we require relocations for any entry in the GOT that needs to be a
capability.
For *static* linking we keep track of a section specifically for
capability relocations. This is done in order to be able to emit
__rela_dyn_{start,end} symbols at the start and end of an array of these
relocations (see commit 40bbb79e5a3 for when this was introduced and
commit 8d4edc5f8 for when we ensured that MORELLO_RELATIVE relocations
into the GOT were included in this section).
The clause in final_link_relocate that decides whether we should put
MORELLO_RELATIVE relocations for initialising capability GOT entries
into this special section currently includes dynamically linked PDE's.
This is unnecessary, since for dynamically linked binaries we do not
want to emit such __rela_dyn_{start,end} symbols.
While this behaviuor is in general harmless (especially since both
input sections srelcaps and srelgot have the same output section in the
default linker scripts), this commit changes it for clarity of the code.
We now only put these relocations initialising GOT entries into the
srelcaps section if we require it for some reason. The only time we do
require this is when statically linking binaries and we need the
__rela_dyn_* symbols. Otherwise we put these entries into the `srelgot`
section which exists for holding GOT entries together.
Since this diff is not about a functional change we do not include a
testcase. However we do ensure that the testcase
morello-dynamic-link-rela-dyn is written so as to exercise the codepath
which has changed.
---
Only ensure that srelcaps is initialised when required
In commit 8d4edc5f8 we started to ensure that capability relocations for
initialising GOT entries were stored next to dynamic RELATIVE
relocations arising from CAPINIT static relocations.
This was done in order to ensure that all relocations creating a
capability were stored next to each other, allowing us to mark the range
of capability relocations with __rela_dyn_{start,end} symbols.
We only need to do this for statically linked executables, for
dynamically linked executables the __rela_dyn_{start,end} symbols are
unnecessary.
When doing this, and there were no CAPINIT relocations that initialised
the srelcaps section, we set that srelcaps section to the same section
as srelgot. Despite what the comment above this clause claimed we
mistakenly did this action when dynamically linking a PDE (i.e. we did
not *just* do this for static non-PIE binaries).
With recent changes that ensure we do not put anything in this srelcaps
section when not statically linking this makes no difference, but
changing the clause to correctly check for static linking is a nice
cleanup to have.
Since there is no observable change expected this diff has no
testcase, but the code path is exercised with morello-dynamic-got.
---
Only emit __rela_dyn_* symbols for statically linked exes
The intention of the code to emit these symbols in size_dynamic_sections
was only to emit symbols for statically linked executables. We recently
noticed that the condition that has been used for this also included
dynamically linked PDE's.
Here we adjust the condition so that we only emit these symbols for
statically linked executables.
This allows initailisation code in glibc to be written much simpler,
since it does not need to determine whether the relocations have been
handled by the dynamic loader or not -- if the __rela_dyn_* symbols
exist then this is definitely a statically linked executable and the
relocations have not been handled by the dynamic loader.
This is tested with morello-dynamic-link-rela-dyn.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 49c489744e860ea36709d13b78dbb8bd3c617adf..4f4f4f7418808fb032b1b6657073d4c6527f0565 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -7211,6 +7211,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
off = symbol_got_offset (input_bfd, h, r_symndx);
base_got = globals->root.sgot;
+ bfd_boolean is_dynamic = elf_hash_table (info)->dynamic_sections_created;
bfd_boolean c64_reloc =
(bfd_r_type == BFD_RELOC_MORELLO_LD128_GOT_LO12_NC
|| bfd_r_type == BFD_RELOC_MORELLO_ADR_GOT_PAGE);
@@ -7235,8 +7236,6 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
{
bfd_vma addend = 0;
bfd_vma frag_value;
- bfd_boolean is_dynamic
- = elf_hash_table (info)->dynamic_sections_created;
/* If a symbol is not dynamic and is not undefined weak, bind it
locally and generate a RELATIVE relocation under PIC mode.
@@ -7415,7 +7414,12 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
{
rtype = MORELLO_R (RELATIVE);
- if (bfd_link_executable (info) && !bfd_link_pic (info))
+ /* Ensure that Morello RELATIVE relocations for static non-PIE
+ binaries are all stored in the same input section. This is
+ done so that we can mark that section with
+ __rela_dyn_{start,end} symbols for the runtime to find and
+ initialise relocations with. */
+ if (bfd_link_executable (info) && !is_dynamic)
s = globals->srelcaps;
outrel.r_addend = signed_addend;
@@ -9084,7 +9088,7 @@ aarch64_elf_init_got_section (bfd *abfd, struct bfd_link_info *info)
}
/* Track capability initialisation for static non-PIE binaries. */
- if (bfd_link_executable (info) && !bfd_link_pic (info)
+ if (bfd_link_executable (info) && !globals->root.dynamic_sections_created
&& globals->srelcaps == NULL)
globals->srelcaps = globals->root.srelgot;
@@ -10222,18 +10226,26 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
{
h->got.offset = htab->root.sgot->size;
htab->root.sgot->size += GOT_ENTRY_SIZE (htab);
- if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
- && (bfd_link_pic (info)
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
- /* Undefined weak symbol in static PIE resolves to 0 without
- any dynamic relocations. */
- && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ if (((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
+ && (bfd_link_pic (info)
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ /* Any capability relocations required in a dynamic binary
+ should go in the srelgot. */
+ || ((got_type == GOT_CAP) && dyn))
{
htab->root.srelgot->size += RELOC_SIZE (htab);
}
- else if (bfd_link_executable (info) && !bfd_link_pic (info))
- htab->srelcaps->size += RELOC_SIZE (htab);
+ else if (bfd_link_executable (info) && (got_type == GOT_CAP))
+ {
+ /* If we have a capability relocation that is not handled by the
+ case above then this must be a statically linked executable. */
+ BFD_ASSERT (!bfd_link_pic (info) && !dyn);
+ htab->srelcaps->size += RELOC_SIZE (htab);
+ }
}
else
{
@@ -10579,8 +10591,13 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd,
htab->root.srelgot->size += RELOC_SIZE (htab);
}
/* Static binary; put relocs into srelcaps. */
- else if (bfd_link_executable (info) && (got_type & GOT_CAP))
+ else if (bfd_link_executable (info)
+ && !htab->root.dynamic_sections_created
+ && (got_type & GOT_CAP))
htab->srelcaps->size += RELOC_SIZE (htab);
+ /* Else capability relocation needs to go into srelgot. */
+ else if (got_type & GOT_CAP)
+ htab->root.srelgot->size += RELOC_SIZE (htab);
}
else
{
@@ -10606,7 +10623,7 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd,
info);
if (bfd_link_executable (info)
- && !bfd_link_pic (info)
+ && !htab->root.dynamic_sections_created
&& htab->srelcaps
&& htab->srelcaps->size > 0)
{
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 3e9cf4147f3012a12a0535bee3f6f7bc4c109a12..26d96d79249a007a6e57b6c7b3ea06ccf522d5d8 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -276,11 +276,16 @@ run_dump_test_lp64 "c64-ehdr-sized-reloc"
# Test for morello dynamic relocs can not be written in the usual manner since
# we need to specify different `ld` command lines for different objects.
-if { [ld_assemble $as $srcdir/$subdir/morello-dynamic-relocs-lib.s tmpdir/morello-dynamic-relocs-lib.o]
+if { [ld_assemble_flags $as -march=morello+c64 $srcdir/$subdir/morello-dynamic-relocs-lib.s tmpdir/morello-dynamic-relocs-lib.o]
&& [ld_link $ld tmpdir/morello-dynamic-relocs.so "--shared tmpdir/morello-dynamic-relocs-lib.o"] } {
run_dump_test_lp64 "morello-dynamic-relocs"
+ run_dump_test_lp64 "morello-dynamic-link-rela-dyn"
+ run_dump_test_lp64 "morello-dynamic-link-rela-dyn2"
+ run_dump_test_lp64 "morello-dynamic-local-got"
}
+run_dump_test_lp64 "morello-static-got"
+run_dump_test_lp64 "morello-dynamic-got"
run_dump_test_lp64 "morello-dt-init-fini"
run_dump_test_lp64 "morello-capinit"
@@ -300,6 +305,8 @@ run_dump_test_lp64 "morello-tlsdesc"
run_dump_test_lp64 "morello-tlsdesc-static"
run_dump_test_lp64 "morello-tlsdesc-staticpie"
+run_dump_test "no-morello-syms-static"
+
run_dump_test "reloc-overflow-bad"
# test addend correctness when --emit-relocs specified for non-relocatable obj.
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-got.d b/ld/testsuite/ld-aarch64/morello-dynamic-got.d
new file mode 100644
index 0000000000000000000000000000000000000000..810eb1033ef7003420791eeeca147170f0f97477
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-got.d
@@ -0,0 +1,12 @@
+# This testcase is just to exercise some code rather than to test for an
+# observable. We may as well check that the __rela_dyn_start symbol does not
+# exists.
+#source: morello-static-got.s
+#as: -march=morello+c64
+#ld: -shared
+#readelf: --symbols
+
+#failif
+#...
+.* __rela_dyn_start
+#...
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.d b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.d
new file mode 100644
index 0000000000000000000000000000000000000000..ee25827e8aa7ec88b56fa112610cc30350729530
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.d
@@ -0,0 +1,20 @@
+# Test here is to ensure that __rela_dyn_* symbols are not emitted for
+# dynamically linked objects. The code that was acting when we noticed this
+# problem was correctly avoiding the behaviour for shared objects, but not for
+# dynamically linked PDE's. Hence that's what this testcase is added for.
+#
+# N.b. aarch64-elf.exp compiles a shared libary for this test under
+# tmpdir/morello-dynamic-relocs.so. We use that shared library for the test in
+# the `ld` command below.
+#
+# This testcase is written partly to ensure a particular code path is
+# exercised. That is the purpose of the local `val` symbol that we have a GOT
+# relocation to.
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#readelf: --symbols
+
+#failif
+#...
+.* __rela_dyn_start
+#...
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.s b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.s
new file mode 100644
index 0000000000000000000000000000000000000000..3cffb35a8b82e93aa45acc841f0f661a320f4849
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn.s
@@ -0,0 +1,41 @@
+ .arch morello+crc+c64
+ .text
+ .align 2
+ .global _start
+ .type _start, %function
+_start:
+.LFB0:
+ .cfi_startproc purecap
+ adrp c0, :got:weakval
+ ldr c0, [c0, #:got_lo12:weakval]
+ adrp c0, :got:globval
+ ldr c0, [c0, #:got_lo12:globval]
+ adrp c0, :got:val
+ ldr c0, [c0, #:got_lo12:val]
+ adrp c0, :got:var
+ ldr c0, [c0, #:got_lo12:var]
+ str wzr, [c0]
+ ret
+ .cfi_endproc
+.LFE0:
+ .size _start, .-_start
+.data
+ .type val, %object
+val:
+ .byte 0x42
+ .byte 0x42
+ .byte 0x42
+ .size val, .-val
+ .chericap val
+ .global globval
+globval:
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .size globval, .-globval
+ .weak weakval
+weakval:
+ .byte 0x1
+ .byte 0x1
+ .byte 0x1
+ .size weakval, .-weakval
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn2.d b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn2.d
new file mode 100644
index 0000000000000000000000000000000000000000..9de0c5f4f362ba8fb2d6c83624f22b4feae839f2
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-link-rela-dyn2.d
@@ -0,0 +1,14 @@
+# This testcase ensures that we have the expected number and type of
+# relocations in our resultant binary.
+#source: morello-dynamic-link-rela-dyn.s
+#as: -march=morello+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#readelf: --relocs
+
+Relocation section '\.rela\.dyn' at offset .* contains 5 entries:
+ Offset Info Type Sym\. Value Sym\. Name \+ Addend
+.* 00000000e803 R_MORELLO_RELATIV 0
+.* 00000000e803 R_MORELLO_RELATIV 0
+.* 00000000e803 R_MORELLO_RELATIV 0
+.* 00000000e803 R_MORELLO_RELATIV 0
+.* 00010000e801 R_MORELLO_GLOB_DA 0000000000000000 var \+ 0
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-local-got.d b/ld/testsuite/ld-aarch64/morello-dynamic-local-got.d
new file mode 100644
index 0000000000000000000000000000000000000000..3b607c9c3255ee5a4b191db274d7a1c29d7720cb
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-local-got.d
@@ -0,0 +1,16 @@
+# This testcase is written mostly to ensure a particular code path is
+# exercised. That is the purpose of the local `x` symbol that we have a GOT
+# relocation to.
+#
+# There is no particular observable for this code path -- a relocation is put
+# in one input section rather than another (though both input sections have the
+# same output section). May as well check that the __rela_dyn_* symbols are
+# not emitted, since this is a dynamic symbol.
+#as: -march=morello+crc+c64
+#ld: tmpdir/morello-dynamic-relocs.so
+#readelf: --symbols
+
+#failif
+#...
+.* __rela_dyn_start
+#...
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-local-got.s b/ld/testsuite/ld-aarch64/morello-dynamic-local-got.s
new file mode 100644
index 0000000000000000000000000000000000000000..e846bb7422cf626d54868db07836cd19c5b112e5
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-local-got.s
@@ -0,0 +1,23 @@
+ .text
+ .global x
+ .bss
+ .align 2
+ .type x, %object
+ .size x, 4
+x:
+ .zero 4
+ .text
+ .align 2
+ .global _start
+ .type _start, %function
+_start:
+.LFB0:
+ .cfi_startproc purecap
+ adrp c0, :got:x
+ ldr c0, [c0, #:got_lo12:x]
+ ldr w0, [c0]
+ ret
+ .cfi_endproc
+.LFE0:
+ .size _start, .-_start
+
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-relocs-lib.s b/ld/testsuite/ld-aarch64/morello-dynamic-relocs-lib.s
index e4cd890c18bd2f39510273c04d36eaca7ee8ac04..80e84e5bc847a99b21c1da515749a3362842a641 100644
--- a/ld/testsuite/ld-aarch64/morello-dynamic-relocs-lib.s
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-relocs-lib.s
@@ -7,4 +7,3 @@
.size var, 4
var:
.zero 4
-
diff --git a/ld/testsuite/ld-aarch64/morello-dynamic-relocs.d b/ld/testsuite/ld-aarch64/morello-dynamic-relocs.d
index ce8d7b39e5db1caacc1dede4265725ef37e813c6..c7cfbd91626c97a1429f6b4a16606031dac8e256 100644
--- a/ld/testsuite/ld-aarch64/morello-dynamic-relocs.d
+++ b/ld/testsuite/ld-aarch64/morello-dynamic-relocs.d
@@ -7,6 +7,7 @@
# N.b. aarch64-elf.exp compiles a shared libary for this test under
# tmpdir/morello-dynamic-relocs.so. We use that shared library for the test in
# the `ld` command below.
+#as: -march=morello+c64
#ld: tmpdir/morello-dynamic-relocs.so
#readelf: --relocs
diff --git a/ld/testsuite/ld-aarch64/morello-static-got.d b/ld/testsuite/ld-aarch64/morello-static-got.d
new file mode 100644
index 0000000000000000000000000000000000000000..0e24d97f2d1afa92e0c339b25174cf566de1bd09
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-static-got.d
@@ -0,0 +1,13 @@
+# This testcase is just to exercise some code rather than to test for an
+# observable. We may as well check that the __rela_dyn_start symbol exists.
+#as: -march=morello+c64
+#ld: -static
+#readelf: --symbols --relocs
+
+Relocation section '\.rela\.dyn' at offset .* contains 1 entry:
+ Offset Info Type Sym\. Value Sym\. Name \+ Addend
+.* 00000000e803 R_MORELLO_RELATIV 0
+
+#...
+.* __rela_dyn_start
+#...
diff --git a/ld/testsuite/ld-aarch64/morello-static-got.s b/ld/testsuite/ld-aarch64/morello-static-got.s
new file mode 100644
index 0000000000000000000000000000000000000000..2a4e410bb469503bb765d83a3406274c3488ef05
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-static-got.s
@@ -0,0 +1,12 @@
+.data
+val:
+ .byte 0x42
+ .byte 0x42
+ .byte 0x42
+ .size val, .-val
+
+.text
+.global _start
+_start:
+ ldr c0, [c0, :got_lo12:val]
+
diff --git a/ld/testsuite/ld-aarch64/no-morello-syms-static.d b/ld/testsuite/ld-aarch64/no-morello-syms-static.d
new file mode 100644
index 0000000000000000000000000000000000000000..e1b495b34a4ee9c21ceb4c232b6e75f35ff6fc39
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/no-morello-syms-static.d
@@ -0,0 +1,13 @@
+# The emit-relocs-28 test was creating space for unnecessary relocations and
+# correspondingly adding the __rela_dyn_{start,end} symbols to span them.
+# This was happening because of Morello changes which applied on non-Morello
+# links by mistake. This testcase is to ensure that that does not happen.
+#source: emit-relocs-28.s
+#as: -mabi=ilp32
+#ld: -m [aarch64_choose_ilp32_emul] --defsym globala=0x11000 --defsym globalb=0x45000 --defsym globalc=0x1234 -e0 --emit-relocs
+#readelf: --symbols
+
+#failif
+#...
+.* __rela_dyn_start
+#...
In standard AArch64 linking by the BFD linker, dynamic symbols in PIC
code have their dynamic relocations created by
elfNN_aarch64_finish_dynamic_symbol. Any required information in the
relevant fragment is added by elfNN_aarch64_final_link_relocate.
Non-dynamic symbols that are supposed to go in the GOT have their
RELATIVE relocations created in elfNN_aarch64_final_link_relocate next
to the place where the fragment is populated.
The code in elfNN_aarch64_finish_dynamic_symbol was not updated when we
ensured that RELATIVE relocations against function symbols were
generated with the PCC base stored in their fragment and an addend
defined to make up the difference so that the relocation pointed at the
relevant function.
On top of this, elfNN_aarch64_final_link_relocate was never written to
include the size and permission information in the GOT fragment for
RELATIVE relocations that will be generated by
elfNN_aarch64_finish_dynamic_symbol.
This patch resolves both issues by adding code to
elfNN_aarch64_final_link_relocate to handle setting up the fragment of a
RELATIVE relocation that elfNN_aarch64_finish_dynamic_symbol will
create, and adding code in elfNN_aarch64_finish_dynamic_symbol to use
the correct addend for the RELATIVE relocation that it generates.
Implementation choices:
The check in elfNN_aarch64_final_link_relocate for "cases where we would
generate a RELATIVE relocation through
elfNN_aarch64_finish_dynamic_symbol" is believed to handle undefined
weak symbols by checking SYMBOL_REFERENCES_LOCAL on the belief that the
latter would not return true if on undefined weak symbols. This is not
as clearly correct as the rest of the condition, so seems reasonable to
bring to the attention of anyone interested.
We add an assertion that this is the case so we get alerted if it is
not, we could choose to include !UNDEFWEAK_NO_DYNAMIC_RELOC in the
condition instead, but believe that would lead to confusion in the code
(i.e. why check something that will always be false).
Similarly, when we check against SYMBOL_REFERENCES_LOCAL to decide
whether to populate the fragment for this relocation this does not
directly correspond to `h->dynindx == -1` (which would indicate that
this symbol is not in the dynamic symbol table).
This means that our clause catches symbols which would appear in the
dynamic symbol table as long as SYMBOL_REFERENCES_LOCAL returns true.
The only case in which we know this can happen is for PROTECTED
visibility data when GNU_PROPERTY_NO_COPY_ON_PROTECTED is set.
When this happens a RELATIVE relocation is generated (since this is
an object we know will resove to the current binary) and the static
linker provides the permissions and size of the associated object in the
relevant fragment.
This behaviour matches all other RELATIVE relocations and allows the
dynamic loader to assume that all RELATIVE relocations should have their
associated permissions and size provided.
We mention this behaviour since the symbol for this object will appear
in the dynamic symbol table and hence the dynamic loader *could*
determine the size and permissions itself.
In our condition to decide whether to update this relocation we include
a check that we `WILL_CALL_FINISH_DYNAMIC_SYMBOL`. This is not
necessary, since the combination of conditions implies it, however it
makes things much clearer as to what we're checking for.
Testsuite notes:
When testing our change here we check:
1) The addend and base of the RELATIVE relocation gives the required
address of the hidden function.
2) The bounds of the RELATIVE relocation is non-zero.
3) The permissions of the RELATIVE relocation are executable.
Lacking in this particular test is a check that the PCC bounds are
calculated correctly, and that the base we define is the base of the
PCC. We rely on existing tests to check our calculation of the PCC
bounds.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index c31e707a4fb8870522d2eb5a624e13fcaabf84bf..766d38c52c31e7f368747c89f2922de189b7c0c8 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -6633,6 +6633,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
struct elf_aarch64_link_hash_table *globals;
bfd_boolean weak_undef_p;
bfd_boolean relative_reloc;
+ bfd_boolean c64_needs_frag_fixup;
asection *base_got;
bfd_vma orig_value = value;
bfd_boolean resolved_to_zero;
@@ -7229,10 +7230,13 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
BFD_ASSERT (h != NULL);
relative_reloc = FALSE;
+ c64_needs_frag_fixup = FALSE;
if (h != NULL)
{
bfd_vma addend = 0;
bfd_vma frag_value;
+ bfd_boolean is_dynamic
+ = elf_hash_table (info)->dynamic_sections_created;
/* If a symbol is not dynamic and is not undefined weak, bind it
locally and generate a RELATIVE relocation under PIC mode.
@@ -7251,7 +7255,37 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
|| (!bfd_link_pic (info) && bfd_link_executable (info)
&& c64_reloc))
&& !symbol_got_offset_mark_p (input_bfd, h, r_symndx))
- relative_reloc = TRUE;
+ {
+ relative_reloc = TRUE;
+ c64_needs_frag_fixup = c64_reloc ? TRUE : FALSE;
+ }
+ /* If this is a dynamic symbol that binds locally then the generic
+ code and elfNN_aarch64_finish_dynamic_symbol will already handle
+ creating the RELATIVE reloc pointing into the GOT for this symbol.
+ That means that this function does not need to handle *creating*
+ such a relocation. This function does already handle setting the
+ base value as the fragment for that relocation, hence we should
+ ensure that we set the fragment correctly for C64 code (i.e.
+ including the required permissions and bounds). */
+ else if (c64_reloc
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dynamic,
+ bfd_link_pic (info), h)
+ && bfd_link_pic (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h))
+ {
+ /* We believe that if `h` were undefined weak it would not have
+ SYMBOL_REFERENCES_LOCAL return true. However this is not 100%
+ clear based purely on the members that we check in the code.
+ The reason it matters is if we could have a
+ SYMBOL_REFERENCES_LOCAL symbol which is also
+ !UNDEFWEAK_NO_DYNAMIC_RELOC then the check above would
+ determine that we need to fix up the fragment for the RELATIVE
+ relocation that elfNN_aarch64_finish_dynamic_symbol will
+ create, but in actual fact elfNN_aarch64_finish_dynamic_symbol
+ would not create that relocation. */
+ BFD_ASSERT (!UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+ c64_needs_frag_fixup = TRUE;
+ }
if (c64_reloc
&& c64_symbol_adjust (h, value, sym_sec, info, &frag_value))
@@ -7311,11 +7345,20 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
linking stage. While for shared library, we need to update the
content of GOT entry according to the shared object's runtime
base address. So, we need to generate a R_AARCH64_RELATIVE reloc
- for dynamic linker. */
+ for dynamic linker.
+
+ For any C64 binary we need to ensure there are RELATIVE
+ relocations to initialise the capabilities. The only case when
+ we would not want to emit such relocations is when the producing
+ a relocatable object file (since such files should not have
+ dynamic relocations). */
if (bfd_link_pic (info)
|| (!bfd_link_pic (info) && bfd_link_executable (info)
&& c64_reloc))
- relative_reloc = TRUE;
+ {
+ relative_reloc = TRUE;
+ c64_needs_frag_fixup = c64_reloc ? TRUE : FALSE;
+ }
symbol_got_offset_mark (input_bfd, h, r_symndx);
}
@@ -7332,6 +7375,22 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
addend, weak_undef_p);
}
+ if (c64_needs_frag_fixup)
+ {
+ BFD_ASSERT (c64_reloc);
+ /* For a C64 relative relocation, also add size and permissions into
+ the frag. */
+ bfd_reloc_status_type ret;
+
+ ret = c64_fixup_frag (input_bfd, info, bfd_r_type, sym, h,
+ sym_sec, globals->root.srelgot,
+ base_got->contents + off + 8,
+ orig_value, 0, off);
+
+ if (ret != bfd_reloc_continue)
+ return ret;
+ }
+
if (relative_reloc)
{
asection *s;
@@ -7341,19 +7400,8 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto,
s = globals->root.srelgot;
- /* For a C64 relative relocation, also add size and permissions into
- the frag. */
if (c64_reloc)
{
- bfd_reloc_status_type ret;
-
- 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;
-
rtype = MORELLO_R (RELATIVE);
if (bfd_link_executable (info) && !bfd_link_pic (info))
@@ -11025,17 +11073,23 @@ elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd,
return FALSE;
BFD_ASSERT ((h->got.offset & 1) != 0);
+ bfd_vma value = h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset;
if (is_c64)
{
rela.r_info = ELFNN_R_INFO (0, MORELLO_R (RELATIVE));
- rela.r_addend = 0;
+ bfd_vma base_value = 0;
+ if (c64_symbol_adjust (h, value, h->root.u.def.section, info,
+ &base_value))
+ rela.r_addend = (value | h->target_internal) - base_value;
+ else
+ rela.r_addend = 0;
}
else
{
rela.r_info = ELFNN_R_INFO (0, AARCH64_R (RELATIVE));
- rela.r_addend = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
+ rela.r_addend = value;
}
}
else
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index adb0081720a48c984e246b838d6ccd0922fa1306..17ba4cfee2aa2214bb3e0c3150862d2aa722a395 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -78,6 +78,19 @@ proc run_dump_test_lp64 { testname } {
[list ld [concat "-m " [aarch64_choose_lp64_emul]]]]
}
+# Return the hexadecimal representation of the value we need to add to $base in
+# order to return $result plus 1. Both $base and $result are assumed to be
+# hexadecimal numbers without the leading 0x prefix.
+#
+# This procedure is especially useful for checking the addend of a RELATIVE
+# relocation against a function in a testcase using the `#check:` directive.
+# Dumping `objdump -DR -j .got -j .text` will give us the address we're trying
+# to reach and base stored in the relocation fragment before reaching the
+# addend we're using for this relocation.
+proc aarch64_required_func_addend { base result } {
+ return [format %x [expr "0x$result + 1 - 0x$base"]];
+}
+
set eh-frame-merge-lp64 [list [list "EH Frame merge" \
[concat "-m " [aarch64_choose_lp64_emul] \
" -Ttext 0x8000"] \
@@ -251,6 +264,7 @@ 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-relocs-morello-9"
+run_dump_test_lp64 "emit-relocs-morello-hidden"
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-hidden.d b/ld/testsuite/ld-aarch64/emit-relocs-morello-hidden.d
new file mode 100644
index 0000000000000000000000000000000000000000..9bac38de22516bc2f1679745df483a16a93c0728
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-hidden.d
@@ -0,0 +1,33 @@
+#source: emit-relocs-morello-hidden.s
+#as: -march=morello+c64
+#ld: -shared
+#objdump: -DR -j .got -j .text
+
+.*: file format .*
+
+
+Disassembly of section \.text:
+
+#record: HIDDEN_ADDR
+#...
+([0-9a-f]*) <hidden_func>:
+ .*: 028043ff sub csp, csp, #0x10
+ .*: b9000fe0 str w0, \[csp, #12\]
+ .*: b9400fe0 ldr w0, \[csp, #12\]
+ .*: 020043ff add csp, csp, #0x10
+ .*: c2c253c0 ret c30
+
+Disassembly of section \.got:
+
+#...
+ \.\.\.
+#record: RELOC_BASE
+ .*: ([0-9a-f]{8}) .*
+#check: RELOC_ADDEND aarch64_required_func_addend $RELOC_BASE $HIDDEN_ADDR
+ .*: R_MORELLO_RELATIVE \*ABS\*\+0xRELOC_ADDEND
+ .*: 00000000 .*
+# Check that the bounds are anything except zero (rely on other tests to ensure
+# that the PCC bounds calculation is correct).
+! .*: 00000000 .*
+ .*: 04000000 .*
+
diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-hidden.s b/ld/testsuite/ld-aarch64/emit-relocs-morello-hidden.s
new file mode 100644
index 0000000000000000000000000000000000000000..24bb687456ea9de2fd16a2dfa311d770ee6580ac
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-hidden.s
@@ -0,0 +1,20 @@
+ .text
+ .align 2
+ .global foo
+ .type foo, %function
+foo:
+ adrp c0, :got:hidden_func
+ ldr c0, [c0, #:got_lo12:hidden_func]
+ ret
+ .size foo, .-foo
+ .align 2
+ .global hidden_func
+ .hidden hidden_func
+ .type hidden_func, %function
+hidden_func:
+ sub csp, csp, #16
+ str w0, [csp, 12]
+ ldr w0, [csp, 12]
+ add csp, csp, 16
+ ret
+ .size hidden_func, .-hidden_func
When DT_INIT and/or DT_FINI point to C64 functions they should have
their LSB set. I.e. these entries should contain the address of the
relevant functions and not a slight variation on them.
This is already done by Morello clang, and we want GNU ld updated to
match.
Here we account for these LSB's for Morello in the same way as the Arm
backend accounts for the Thumb LSB. This is done in the
finish_dynamic_sections hook by checking the two dynamic section
entries, looking up the relevant functions, and adding that LSB onto the
entry value.
In our testcase we simply check that the INIT and FINI section entries
have the same address as the _init and _fini symbols.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index ed8d8719dc28fb11ac9ee2d2e78b0f88a425f2ca..9f8cb7d3a78336aa0922c2635d577e9c2157301b 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -11252,6 +11252,7 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
if (htab->root.dynamic_sections_created)
{
+ const char *name;
ElfNN_External_Dyn *dyncon, *dynconend;
if (sdyn == NULL || htab->root.sgot == NULL)
@@ -11298,6 +11299,27 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd,
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
+ htab->root.tlsdesc_got;
break;
+
+ /* Set the bottom bit of DT_INIT/FINI if the
+ corresponding function is C64. */
+ case DT_INIT:
+ name = info->init_function;
+ goto get_sym;
+ case DT_FINI:
+ name = info->fini_function;
+get_sym:
+ /* If it wasn't set by elf_bfd_final_link
+ then there is nothing to adjust. */
+ if (dyn.d_un.d_val != 0)
+ {
+ struct elf_link_hash_entry * eh;
+
+ eh = elf_link_hash_lookup (elf_hash_table (info), name,
+ FALSE, FALSE, TRUE);
+ if (eh != NULL)
+ dyn.d_un.d_val |= eh->target_internal;
+ }
+ break;
}
bfd_elfNN_swap_dyn_out (output_bfd, &dyn, dyncon);
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index 9b745e3976f856432f29f12a1c974f0fa7411dfa..3e9cf4147f3012a12a0535bee3f6f7bc4c109a12 100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -281,6 +281,7 @@ if { [ld_assemble $as $srcdir/$subdir/morello-dynamic-relocs-lib.s tmpdir/morell
run_dump_test_lp64 "morello-dynamic-relocs"
}
+run_dump_test_lp64 "morello-dt-init-fini"
run_dump_test_lp64 "morello-capinit"
run_dump_test_lp64 "morello-stubs"
diff --git a/ld/testsuite/ld-aarch64/morello-dt-init-fini.d b/ld/testsuite/ld-aarch64/morello-dt-init-fini.d
new file mode 100644
index 0000000000000000000000000000000000000000..d530a288b661a056d9d50077c7aa5d45658ebea6
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dt-init-fini.d
@@ -0,0 +1,23 @@
+# Checking that the DT_INIT and DT_FINI entries in the dynamic section include
+# the LSB when referring to functions which include the LSB.
+#as: -march=morello+c64
+#ld: -shared
+#readelf: --symbols --dynamic --wide
+
+Dynamic section at offset .*
+ Tag Type Name/Value
+#record: INIT_LOC
+#...
+ 0x000000000000000c \(INIT\) 0x([0-9a-f]+)
+#record: FINI_LOC
+#...
+ 0x000000000000000d \(FINI\) 0x([0-9a-f]+)
+#...
+Symbol table '.symtab' contains 18 entries:
+ Num: Value Size Type Bind Vis Ndx Name
+#check: INIT_ADDR string tolower $INIT_LOC
+#check: FINI_ADDR string tolower $FINI_LOC
+#...
+.*: 0+INIT_ADDR 0 FUNC LOCAL DEFAULT .* _init
+.*: 0+FINI_ADDR 0 FUNC LOCAL DEFAULT .* _fini
+#pass
diff --git a/ld/testsuite/ld-aarch64/morello-dt-init-fini.s b/ld/testsuite/ld-aarch64/morello-dt-init-fini.s
new file mode 100644
index 0000000000000000000000000000000000000000..71a5b645b91f958cd3798b134e5970bee6bd7243
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/morello-dt-init-fini.s
@@ -0,0 +1,13 @@
+ .section .init,"ax",%progbits
+ .global _init
+ .hidden _init
+ .type _init, %function
+_init:
+ ret
+
+ .section .fini,"ax",%progbits
+ .global _fini
+ .hidden _fini
+ .type _fini, %function
+_fini:
+ ret
This symbol is defined in a binary when there is a segment which
contains both the file header and the program header. The symbol points
at the file header. The point of this symbol is to allow the program to
robustly examine its own output.
Glibc uses this symbol. This symbol is currently not marked as a
linker or linker script defined symbol, and hence does not get its
bounds adjusted. The symbol is given zero size, and consequently any
capability initialised as a relocation to this symbol is given zero
bounds.
In order to allow access to read the headers this symbol points at this
patch adds a size to the symbol.
We do not believe that the size of this symbol is used for anything
other than CHERI bounds, so we believe that this is a safe change to
make. Setting the size of the symbol means that c64_fixup_frag uses
that size as the bounds to apply to a capability relocation pointing at
that symbol. This allows access to the file and program headers loaded
into memory.
An alternative approach would be to *not* set the size of the symbol,
but only change the bounds of the relocation generated. This would be
done by checking for the `__ehdr_start' name in c64_fixup_frag and
setting the size according to the `sizeof_ehdr' and
`elf_program_header_size' values stored on the output BFD object.
We chose the approach to set the size on the symbol for code-aesthetic
reasons under the belief that having this size on the symbol in the
final binary is a slight benefit in readability for a user and causes no
downside.
I do not believe that Morello lld sets the bounds of a capability to this
symbol correctly. That issue has been raised separately.
############### Attachment also inlined for ease of reply
###############
diff --git a/bfd/elf.c b/bfd/elf.c
index
9a5b472cda2c953cae40d2dfcbce493048ed8168..279f15a3aefaa6e9048ee93a54575a2a06004ae1
100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -6028,6 +6028,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
hash->root.u.def.section = bfd_abs_section_ptr;
}
+ hash->size = bed->s->sizeof_ehdr + elf_program_header_size (abfd);
hash->root.type = bfd_link_hash_defined;
hash->def_regular = 1;
hash->non_elf = 0;
diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp
b/ld/testsuite/ld-aarch64/aarch64-elf.exp
index
f0d2048efc37c2df3f4dfea304c7f93f8fe3a169..adb0081720a48c984e246b838d6ccd0922fa1306
100644
--- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
+++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
@@ -258,6 +258,7 @@ 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 "c64-ehdr-sized-reloc"
run_dump_test_lp64 "morello-capinit"
run_dump_test_lp64 "morello-stubs"
diff --git a/ld/testsuite/ld-aarch64/c64-ehdr-sized-reloc.d
b/ld/testsuite/ld-aarch64/c64-ehdr-sized-reloc.d
new file mode 100644
index
0000000000000000000000000000000000000000..41c3cffa32f6bc494e1ef282319331e794b07abe
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/c64-ehdr-sized-reloc.d
@@ -0,0 +1,18 @@
+#as: -march=morello+c64
+#ld: -shared
+#objdump: -dR -j .data
+
+.*: file format .*
+
+
+Disassembly of section \.data:
+
+00000000000[[:xdigit:]]* <val>:
+ ...
+ [[:xdigit:]]*: R_MORELLO_RELATIVE \*ABS\*
+# Want to check that the size is non-zero.
+# Check that using a negative line match to a zero size.
+# In fact, when this size is zero objdump doesn't even print a line
here, but
+# that just adds extra robustness to our check.
+! .*: 00000000 \.word 0x00000000
+ .*: 01000000 .*
diff --git a/ld/testsuite/ld-aarch64/c64-ehdr-sized-reloc.s
b/ld/testsuite/ld-aarch64/c64-ehdr-sized-reloc.s
new file mode 100644
index
0000000000000000000000000000000000000000..3b750cfbd499d9babd25d1a8fb0b1d573726a855
--- /dev/null
+++ b/ld/testsuite/ld-aarch64/c64-ehdr-sized-reloc.s
@@ -0,0 +1,11 @@
+ .data
+ .global val
+val:
+ .chericap __ehdr_start
+ .size val, .-val
+
+ .align 4
+ .text
+ .global _start
+_start:
+ ldr c0, [c0, :got_lo12:val]