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