The LSB on STT_FUNC symbols was missed in a few different places.
1) Absolute relocations coming from .xword, .word, and .hword directives and the lowest bit MOVW relocations did not account for the LSB at all. 2) Relocations for the ADR instruction only added the LSB on local symbols.
Here we account for these by adding the LSB in each clause in elfNN_aarch64_final_link_relocate. The change under the BFD_RELOC_AARCH64_NN clause handles absolute 64 bit relocations, the change for BFD_RELOC_AARCH64_ADR_LO21_PCREL handles the relocation on ADR instructions, and the extra relocations checked against in the clause including BFD_RELOC_AARCH64_ADD_LO12 ore the remaining items.
N.b. we noticed the MOVW relocation problem because glibc's start.S was using these direct MOV relocations to access the value of `main`. Since `main` is a function we need to include the LSB in the resulting relocation value. These relocations did not include the LSB from STT_FUNC symbols.
Others were found from inspection of each relocation in turn.
############### Attachment also inlined for ease of reply ###############
diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index cb9e5f132cca2d360b8bd2cf2e2eb1fbbf1695f0..a33aea0eab02ac97cb605cac677d8ac27a475967 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -6900,6 +6900,11 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, return bfd_reloc_ok; case BFD_RELOC_AARCH64_NN: + /* If we are relocating against a C64 symbol, then the value can't + already have the LSB set (since STT_FUNC symbols are code labels and + they will be aligned). Hence it's safe just to or-equal in order + to ensure the LSB is set in that case. */ + value |= to_c64 ? 1 : 0; /* When generating a shared object or relocatable executable, these relocations are copied into the output file to be resolved at @@ -7115,8 +7120,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, signed_addend, weak_undef_p); - if (bfd_r_type == BFD_RELOC_AARCH64_ADR_LO21_PCREL && isym != NULL - && isym->st_target_internal & ST_BRANCH_TO_C64) + if (bfd_r_type == BFD_RELOC_AARCH64_ADR_LO21_PCREL && to_c64) value |= 1; break; @@ -7172,8 +7176,13 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, place, value, signed_addend, weak_undef_p); - if (bfd_r_type == BFD_RELOC_AARCH64_ADD_LO12 && isym != NULL - && isym->st_target_internal & ST_BRANCH_TO_C64) + if ((bfd_r_type == BFD_RELOC_AARCH64_ADD_LO12 + || bfd_r_type == BFD_RELOC_AARCH64_MOVW_G0 + || bfd_r_type == BFD_RELOC_AARCH64_MOVW_G0_S + || bfd_r_type == BFD_RELOC_AARCH64_MOVW_G0_NC + || bfd_r_type == BFD_RELOC_AARCH64_32 + || bfd_r_type == BFD_RELOC_AARCH64_16) + && to_c64) value |= 1; break; diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp index 9352db42e9913021d17a8e5dd8d7d8cf2125fe29..49b2e70adca947b61294bf1d589ce366b81da569 100644 --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp @@ -250,6 +250,7 @@ run_dump_test_lp64 "emit-relocs-morello-6" run_dump_test_lp64 "emit-relocs-morello-6b" run_dump_test_lp64 "emit-relocs-morello-7" run_dump_test_lp64 "emit-relocs-morello-8" +run_dump_test_lp64 "emit-relocs-morello-9" 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-9.d b/ld/testsuite/ld-aarch64/emit-relocs-morello-9.d new file mode 100644 index 0000000000000000000000000000000000000000..a9e1c3f37485df9d0ea9f2a52edab97cc9edf355 --- /dev/null +++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-9.d @@ -0,0 +1,33 @@ +#source: emit-relocs-morello-9.s +#as: -march=morello+c64 +#ld: -static -Ttext-segment 0x0 +#objdump: -d -j .data -j .text + +.*: file format .* + + +Disassembly of section .text: + +0000000000000000 <_start>: + 0: f2800020 movk x0, #0x1 + 4: f2800020 movk x0, #0x1 + 8: 30ffffc0 adr c0, 1 <_start+0x1> + c: 30ffffa0 adr c0, 1 <_start+0x1> + 10: 02000400 add c0, c0, #0x1 + 14: 02000400 add c0, c0, #0x1 + 18: d2800020 mov x0, #0x1 // #1 + 1c: d2800020 mov x0, #0x1 // #1 + 20: f2800020 movk x0, #0x1 + 24: f2800020 movk x0, #0x1 + +Disassembly of section .data: + +.* <val>: + .*: 00000001 .word 0x00000001 + .*: 00000001 .word 0x00000001 + .*: 00000001 .word 0x00000001 + .*: 00000000 .word 0x00000000 + .*: 00000001 .word 0x00000001 + .*: 00000001 .word 0x00000001 + .*: 00000001 .word 0x00000001 + .*: 00000000 .word 0x00000000 diff --git a/ld/testsuite/ld-aarch64/emit-relocs-morello-9.s b/ld/testsuite/ld-aarch64/emit-relocs-morello-9.s new file mode 100644 index 0000000000000000000000000000000000000000..854482cd027dd853aecd41465c1b2238bbbedb7d --- /dev/null +++ b/ld/testsuite/ld-aarch64/emit-relocs-morello-9.s @@ -0,0 +1,42 @@ +# Attempting to check that the LSB is set on all relocations to a function +# symbol. +# +# This should only happen for those relocations which load an address into a +# register, since relocations that jump to a PC relative address like `bl` +# should not include the LSB. +.text +.global _start +.type _start,@function +.type otherstart,@function +_start: +otherstart: + movk x0, #:abs_g0_nc:_start + movk x0, #:abs_g0_nc:otherstart + adr c0, _start + adr c0, otherstart + add c0, c0, :lo12:_start + add c0, c0, :lo12:otherstart + # The below are not as much of a worry if they go wrong since they + # check overflow, and the likelyhood of there being a function which + # fits in the lowest 16 bits of an address is low. However, we can + # still test it in our testsuite with arguments to the linker, so we + # still get to check this edge case. + movz x0, #:abs_g0_s:_start + movz x0, #:abs_g0_s:otherstart + movk x0, #:abs_g0:_start + movk x0, #:abs_g0:otherstart +.data +.align 4 +.global val +val: + # LSB should be included in the value of function symbols even if they + # are just added via absolute relocations. + .hword _start + .hword 0 + .word _start + .xword _start + .hword otherstart + .hword 0 + .word otherstart + .xword otherstart + .size val, .-val