From 6353d82b8fa825c2143f41e84b0d5d4446c6e99a Mon Sep 17 00:00:00 2001 From: Jiong Wang Date: Thu, 15 Jun 2017 16:51:01 +0100 Subject: [PATCH] [AArch64] Allow COPY relocation elimination As discussed at the PR, this patch tries to avoid COPY relocation generation and propagate the original relocation into runtime if it was relocating on writable section. The ELIMINATE_COPY_RELOCS has been set to true and it's underlying infrastructure has been improved so that the COPY reloc elimination at least working on absoluate relocations (ABS64) on AArch64. BFD linker copy relocation elimination framwork requires the backend to always allocate dynrelocs for all those relocation types that are possible to introduce copy relocations. This is for adjust_dynamic_symbol hook to be able to get all symbol reference information. Should one symbol is referenced by more than one relocations, if there is any of them needs copy relocation then linker should generate it. bfd/ PR ld/21532 * elfnn-aarch64.c (ELIMINATE_COPY_RELOCS): Set to 1. (elfNN_aarch64_final_link_relocate): Also propagate relocations to runtime for if there needs copy relocation elimination. (need_copy_relocation_p): New function. Return true for symbol with pc-relative references and if it's against read-only sections. (elfNN_aarch64_adjust_dynamic_symbol): Use need_copy_relocation_p. (elfNN_aarch64_check_relocs): Allocate dynrelocs for relocation types that are related with accessing external objects. (elfNN_aarch64_gc_sweep_hook): Sync the relocation types with the change in elfNN_aarch64_check_relocs. ld/ * testsuite/ld-aarch64/copy-reloc-exe-2.s: New test source file. * testsuite/ld-aarch64/copy-reloc-2.d: New test. * testsuite/ld-aarch64/copy-reloc-exe-eliminate.s: New test source file. * testsuite/ld-aarch64/copy-reloc-eliminate.d: New test. * testsuite/ld-aarch64/copy-reloc-so.s: Define new global objects. * testsuite/ld-aarch64/aarch64-elf.exp: Run new tests. --- bfd/ChangeLog | 14 ++ bfd/elfnn-aarch64.c | 171 +++++++++++++----- ld/ChangeLog | 9 + ld/testsuite/ld-aarch64/aarch64-elf.exp | 4 + ld/testsuite/ld-aarch64/copy-reloc-2.d | 7 + .../ld-aarch64/copy-reloc-eliminate.d | 4 + ld/testsuite/ld-aarch64/copy-reloc-exe-2.s | 32 ++++ .../ld-aarch64/copy-reloc-exe-eliminate.s | 7 + ld/testsuite/ld-aarch64/copy-reloc-so.s | 19 ++ 9 files changed, 220 insertions(+), 47 deletions(-) create mode 100644 ld/testsuite/ld-aarch64/copy-reloc-2.d create mode 100644 ld/testsuite/ld-aarch64/copy-reloc-eliminate.d create mode 100644 ld/testsuite/ld-aarch64/copy-reloc-exe-2.s create mode 100644 ld/testsuite/ld-aarch64/copy-reloc-exe-eliminate.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 550738531bc..879ced757a4 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2017-06-15 Jiong Wang + + PR ld/21532 + * elfnn-aarch64.c (ELIMINATE_COPY_RELOCS): Set to 1. + (elfNN_aarch64_final_link_relocate): Also propagate relocations to + runtime for if there needs copy relocation elimination. + (need_copy_relocation_p): New function. Return true for symbol with + pc-relative references and if it's against read-only sections. + (elfNN_aarch64_adjust_dynamic_symbol): Use need_copy_relocation_p. + (elfNN_aarch64_check_relocs): Allocate dynrelocs for relocation types + that are related with accessing external objects. + (elfNN_aarch64_gc_sweep_hook): Sync the relocation types with the change + in elfNN_aarch64_check_relocs. + 2017-06-15 Nick Clifton PR binutils/21582 diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 1edf2a0bdea..e27f067ce50 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -249,7 +249,7 @@ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC \ || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G1) -#define ELIMINATE_COPY_RELOCS 0 +#define ELIMINATE_COPY_RELOCS 1 /* Return size of a relocation entry. HTAB is the bfd's elf_aarch64_link_hash_entry. */ @@ -5169,12 +5169,25 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, /* When generating a shared object or relocatable executable, these relocations are copied into the output file to be resolved at run time. */ - if ((bfd_link_pic (info) - || globals->root.is_relocatable_executable) - && (input_section->flags & SEC_ALLOC) - && (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) + if (((bfd_link_pic (info) + || globals->root.is_relocatable_executable) + && (input_section->flags & SEC_ALLOC) + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + /* Or we are creating an executable, we may need to keep relocations + for symbols satisfied by a dynamic library if we manage to avoid + copy relocs for the symbol. */ + || (ELIMINATE_COPY_RELOCS + && !bfd_link_pic (info) + && h != NULL + && (input_section->flags & SEC_ALLOC) + && h->dynindx != -1 + && !h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined))) { Elf_Internal_Rela outrel; bfd_byte *loc; @@ -6846,15 +6859,22 @@ elfNN_aarch64_gc_sweep_hook (bfd *abfd, h->plt.refcount -= 1; break; + case BFD_RELOC_AARCH64_ADD_LO12: case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: case BFD_RELOC_AARCH64_ADR_HI21_PCREL: case BFD_RELOC_AARCH64_ADR_LO21_PCREL: + case BFD_RELOC_AARCH64_LDST128_LO12: + case BFD_RELOC_AARCH64_LDST16_LO12: + case BFD_RELOC_AARCH64_LDST32_LO12: + case BFD_RELOC_AARCH64_LDST64_LO12: + case BFD_RELOC_AARCH64_LDST8_LO12: + case BFD_RELOC_AARCH64_LD_LO19_PCREL: case BFD_RELOC_AARCH64_MOVW_G0_NC: case BFD_RELOC_AARCH64_MOVW_G1_NC: case BFD_RELOC_AARCH64_MOVW_G2_NC: case BFD_RELOC_AARCH64_MOVW_G3: case BFD_RELOC_AARCH64_NN: - if (h != NULL && bfd_link_executable (info)) + if (h != NULL && !bfd_link_pic (info)) { if (h->plt.refcount > 0) h->plt.refcount -= 1; @@ -6869,6 +6889,31 @@ elfNN_aarch64_gc_sweep_hook (bfd *abfd, return TRUE; } +/* Return true if we need copy relocation against EH. */ + +static bfd_boolean +need_copy_relocation_p (struct elf_aarch64_link_hash_entry *eh) +{ + struct elf_dyn_relocs *p; + asection *s; + + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + /* If there is any pc-relative reference, we need to keep copy relocation + to avoid propagating the relocation into runtime that current glibc + does not support. */ + if (p->pc_count) + return TRUE; + + s = p->sec->output_section; + /* Need copy relocation if it's against read-only section. */ + if (s != NULL && (s->flags & SEC_READONLY) != 0) + return TRUE; + } + + return FALSE; +} + /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -6942,6 +6987,19 @@ elfNN_aarch64_adjust_dynamic_symbol (struct bfd_link_info *info, return TRUE; } + if (ELIMINATE_COPY_RELOCS) + { + struct elf_aarch64_link_hash_entry *eh; + /* If we didn't find any dynamic relocs in read-only sections, then + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ + eh = (struct elf_aarch64_link_hash_entry *) h; + if (!need_copy_relocation_p (eh)) + { + h->non_got_ref = 0; + return TRUE; + } + } + /* We must allocate the symbol in our .dynbss section, which will become part of the .bss section of the executable. There will be an entry for this symbol in the .dynsym section. The dynamic @@ -7196,6 +7254,41 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, switch (bfd_r_type) { + case BFD_RELOC_AARCH64_MOVW_G0_NC: + case BFD_RELOC_AARCH64_MOVW_G1_NC: + case BFD_RELOC_AARCH64_MOVW_G2_NC: + case BFD_RELOC_AARCH64_MOVW_G3: + if (bfd_link_pic (info)) + { + int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; + _bfd_error_handler + /* xgettext:c-format */ + (_("%B: relocation %s against `%s' can not be used when making " + "a shared object; recompile with -fPIC"), + abfd, elfNN_aarch64_howto_table[howto_index].name, + (h) ? h->root.root.string : "a local symbol"); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + /* Fall through. */ + + case BFD_RELOC_AARCH64_16_PCREL: + case BFD_RELOC_AARCH64_32_PCREL: + case BFD_RELOC_AARCH64_64_PCREL: + case BFD_RELOC_AARCH64_ADD_LO12: + case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: + case BFD_RELOC_AARCH64_ADR_HI21_PCREL: + case BFD_RELOC_AARCH64_ADR_LO21_PCREL: + case BFD_RELOC_AARCH64_LDST128_LO12: + case BFD_RELOC_AARCH64_LDST16_LO12: + case BFD_RELOC_AARCH64_LDST32_LO12: + case BFD_RELOC_AARCH64_LDST64_LO12: + case BFD_RELOC_AARCH64_LDST8_LO12: + case BFD_RELOC_AARCH64_LD_LO19_PCREL: + if (h == NULL || bfd_link_pic (info)) + break; + /* Fall through. */ + case BFD_RELOC_AARCH64_NN: /* We don't need to handle relocs into sections not going into @@ -7214,12 +7307,32 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, /* No need to do anything if we're not creating a shared object. */ - if (! bfd_link_pic (info)) + if (!(bfd_link_pic (info) + /* If on the other hand, we are creating an executable, we + may need to keep relocations for symbols satisfied by a + dynamic library if we manage to avoid copy relocs for the + symbol. + + NOTE: Currently, there is no support of copy relocs + elimination on pc-relative relocation types, because there is + no dynamic relocation support for them in glibc. We still + record the dynamic symbol reference for them. This is + because one symbol may be referenced by both absolute + relocation (for example, BFD_RELOC_AARCH64_NN) and + pc-relative relocation. We need full symbol reference + information to make correct decision later in + elfNN_aarch64_adjust_dynamic_symbol. */ + || (ELIMINATE_COPY_RELOCS + && !bfd_link_pic (info) + && h != NULL + && (h->root.type == bfd_link_hash_defweak + || !h->def_regular)))) break; { struct elf_dyn_relocs *p; struct elf_dyn_relocs **head; + int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; /* We must copy these reloc types into the output file. Create a reloc section in dynobj and make room for @@ -7283,6 +7396,8 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, p->count += 1; + if (elfNN_aarch64_howto_table[howto_index].pc_relative) + p->pc_count += 1; } break; @@ -7386,44 +7501,6 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, break; } - case BFD_RELOC_AARCH64_MOVW_G0_NC: - case BFD_RELOC_AARCH64_MOVW_G1_NC: - case BFD_RELOC_AARCH64_MOVW_G2_NC: - case BFD_RELOC_AARCH64_MOVW_G3: - if (bfd_link_pic (info)) - { - int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation %s against `%s' can not be used when making " - "a shared object; recompile with -fPIC"), - abfd, elfNN_aarch64_howto_table[howto_index].name, - (h) ? h->root.root.string : "a local symbol"); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - /* Fall through. */ - - case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: - case BFD_RELOC_AARCH64_ADR_HI21_PCREL: - case BFD_RELOC_AARCH64_ADR_LO21_PCREL: - if (h != NULL && bfd_link_executable (info)) - { - /* If this reloc is in a read-only section, we might - need a copy reloc. We can't check reliably at this - stage whether the section is read-only, as input - sections have not yet been mapped to output sections. - Tentatively set the flag for now, and correct in - adjust_dynamic_symbol. */ - h->non_got_ref = 1; - h->plt.refcount += 1; - h->pointer_equality_needed = 1; - } - /* FIXME:: RR need to handle these in shared libraries - and essentially bomb out as these being non-PIC - relocations in shared libraries. */ - break; - case BFD_RELOC_AARCH64_CALL26: case BFD_RELOC_AARCH64_JUMP26: /* If this is a local symbol then we resolve it diff --git a/ld/ChangeLog b/ld/ChangeLog index 72777eeea96..e3afabf83fa 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2017-06-15 Jiong Wang + + * testsuite/ld-aarch64/copy-reloc-exe-2.s: New test source file. + * testsuite/ld-aarch64/copy-reloc-2.d: New test. + * testsuite/ld-aarch64/copy-reloc-exe-eliminate.s: New test source file. + * testsuite/ld-aarch64/copy-reloc-eliminate.d: New test. + * testsuite/ld-aarch64/copy-reloc-so.s: Define new global objects. + * testsuite/ld-aarch64/aarch64-elf.exp: Run new tests. + 2017-06-14 Nick Clifton PR binutils/21580 diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp index ca21e171a11..f171f6fe348 100644 --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp @@ -335,6 +335,10 @@ set aarch64elflinktests { {} "copy-reloc-so.so"} {"ld-aarch64/exe with copy relocation" "-e0 tmpdir/copy-reloc-so.so" "" "" {copy-reloc-exe.s} {{objdump -R copy-reloc.d}} "copy-reloc"} + {"ld-aarch64/exe with copy relocation 2" "-e0 tmpdir/copy-reloc-so.so" "" "" + {copy-reloc-exe-2.s} {{objdump -R copy-reloc-2.d}} "copy-reloc-2"} + {"ld-aarch64/exe with copy relocation elimination" "-e0 tmpdir/copy-reloc-so.so" "" "" + {copy-reloc-exe-eliminate.s} {{objdump -R copy-reloc-eliminate.d}} "copy-reloc-elimination"} {"ld-aarch64/so with global func" "-shared" "" "" {func-in-so.s} {} "func-in-so.so"} {"ld-aarch64/func sym hash opt for exe" diff --git a/ld/testsuite/ld-aarch64/copy-reloc-2.d b/ld/testsuite/ld-aarch64/copy-reloc-2.d new file mode 100644 index 00000000000..87ddccd7486 --- /dev/null +++ b/ld/testsuite/ld-aarch64/copy-reloc-2.d @@ -0,0 +1,7 @@ +.* +DYNAMIC RELOCATION RECORDS +OFFSET.*TYPE.*VALUE.* +.*R_AARCH64_COPY.*global_[abcd] +.*R_AARCH64_COPY.*global_[abcd] +.*R_AARCH64_COPY.*global_[abcd] +.*R_AARCH64_COPY.*global_[abcd] diff --git a/ld/testsuite/ld-aarch64/copy-reloc-eliminate.d b/ld/testsuite/ld-aarch64/copy-reloc-eliminate.d new file mode 100644 index 00000000000..9657d651132 --- /dev/null +++ b/ld/testsuite/ld-aarch64/copy-reloc-eliminate.d @@ -0,0 +1,4 @@ +.* +DYNAMIC RELOCATION RECORDS +OFFSET.*TYPE.*VALUE.* +.*R_AARCH64_ABS64.*global_a diff --git a/ld/testsuite/ld-aarch64/copy-reloc-exe-2.s b/ld/testsuite/ld-aarch64/copy-reloc-exe-2.s new file mode 100644 index 00000000000..d83658c4fa8 --- /dev/null +++ b/ld/testsuite/ld-aarch64/copy-reloc-exe-2.s @@ -0,0 +1,32 @@ + # expect copy relocation for all these scenarios. + .global p + .global q + .global r + .section .data.rel.ro,"aw",%progbits + .align 3 + .type p, %object + .size p, 8 +p: + .xword global_a + + .type q, %object + .size q, 8 +q: + .xword global_b + + .type r, %object + .size r, 8 +r: + # Any pc-rel relocation as no dynamic linker support on AArch64. + .xword global_c - . + + .text + .global main +main: + # Symbols are referenced by any other relocation against read-only + # section. + movz x0, :abs_g0_nc:global_a + adrp x1, global_b + # pc-rel. + adrp x2, global_d + add x2, x2, #:lo12:global_c diff --git a/ld/testsuite/ld-aarch64/copy-reloc-exe-eliminate.s b/ld/testsuite/ld-aarch64/copy-reloc-exe-eliminate.s new file mode 100644 index 00000000000..33227aad3ee --- /dev/null +++ b/ld/testsuite/ld-aarch64/copy-reloc-exe-eliminate.s @@ -0,0 +1,7 @@ + .global p + .section .data.rel.ro,"aw",%progbits + .align 3 + .type p, %object + .size p, 8 +p: + .xword global_a diff --git a/ld/testsuite/ld-aarch64/copy-reloc-so.s b/ld/testsuite/ld-aarch64/copy-reloc-so.s index 07ec44a2c7d..af40f69a0a0 100644 --- a/ld/testsuite/ld-aarch64/copy-reloc-so.s +++ b/ld/testsuite/ld-aarch64/copy-reloc-so.s @@ -1,6 +1,25 @@ .global global_a .type global_a, %object .size global_a, 4 + + .global global_b + .type global_b, %object + .size global_b, 4 + + .global global_c + .type global_c, %object + .size global_c, 4 + + .global global_d + .type global_d, %object + .size global_d, 4 + .data global_a: .word 0xcafedead +global_b: + .word 0xcafecafe +global_c: + .word 0xdeadcafe +global_d: + .word 0xdeaddead -- 2.30.2