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