[AArch64] Allow COPY relocation elimination
authorJiong Wang <jiong.wang@arm.com>
Thu, 15 Jun 2017 15:51:01 +0000 (16:51 +0100)
committerJiong Wang <jiong.wang@arm.com>
Thu, 15 Jun 2017 16:04:04 +0000 (17:04 +0100)
  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
bfd/elfnn-aarch64.c
ld/ChangeLog
ld/testsuite/ld-aarch64/aarch64-elf.exp
ld/testsuite/ld-aarch64/copy-reloc-2.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/copy-reloc-eliminate.d [new file with mode: 0644]
ld/testsuite/ld-aarch64/copy-reloc-exe-2.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/copy-reloc-exe-eliminate.s [new file with mode: 0644]
ld/testsuite/ld-aarch64/copy-reloc-so.s

index 550738531bcdd8cff68236f9b949cae577312699..879ced757a4be83f154a5b1e7cae18234f2c2921 100644 (file)
@@ -1,3 +1,17 @@
+2017-06-15  Jiong Wang  <jiong.wang@arm.com>
+
+       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  <nickc@redhat.com>
 
        PR binutils/21582
index 1edf2a0bdead06a2f808a950c234fcd601714177..e27f067ce504bcd9fc1871ce39cdbdcc3174c419 100644 (file)
    || (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
index 72777eeea96b5d399313740e07370da81173e9ba..e3afabf83fa6d6d3ef909b2fb0eea756c1d91cb6 100644 (file)
@@ -1,3 +1,12 @@
+2017-06-15  Jiong Wang  <jiong.wang@arm.com>
+
+       * 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  <nickc@redhat.com>
 
        PR binutils/21580
index ca21e171a1106ccd99d93f7d6b7256253b623c0e..f171f6fe3483e2b24e73cdb0fbf26bb5576d1ab2 100644 (file)
@@ -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 (file)
index 0000000..87ddccd
--- /dev/null
@@ -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 (file)
index 0000000..9657d65
--- /dev/null
@@ -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 (file)
index 0000000..d83658c
--- /dev/null
@@ -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 (file)
index 0000000..33227aa
--- /dev/null
@@ -0,0 +1,7 @@
+       .global p
+       .section        .data.rel.ro,"aw",%progbits
+       .align  3
+       .type   p, %object
+       .size   p, 8
+p:
+       .xword  global_a
index 07ec44a2c7dcecfd6b16fa7000716d5638a66954..af40f69a0a0127f51637c7d6ac356dd646861344 100644 (file)
@@ -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