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.
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
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;
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;
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"
--- /dev/null
+#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
--- /dev/null
+# 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