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 +
gnu-morello@op-lists.linaro.org