bfd/
authorRichard Sandiford <rdsandiford@googlemail.com>
Mon, 14 Mar 2011 15:53:33 +0000 (15:53 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Mon, 14 Mar 2011 15:53:33 +0000 (15:53 +0000)
* elf32-arm.c (elf32_arm_check_relocs): Use call_reloc_p,
may_need_local_target_p and may_become_dynamic_p to classify
the relocation type.  Don't check info->symbolic or h->def_regular
when deciding whether to record a potential dynamic reloc.
Don't treat potential dynamic relocs as PLT references.
(elf32_arm_gc_sweep_hook): Update to match.  Assert that we don't
try to make the PLT reference count go negative.

ld/testsuite/
* ld-arm/arm-lib-plt-2a.s, ld-arm/arm-lib-plt-2b.s,
ld-arm/arm-lib-plt-2.dd, ld-arm/arm-lib-plt-2.rd: New tests.
* ld-arm/arm-elf.exp: Run them.

bfd/ChangeLog
bfd/elf32-arm.c
ld/testsuite/ChangeLog
ld/testsuite/ld-arm/arm-elf.exp
ld/testsuite/ld-arm/arm-lib-plt-2.dd [new file with mode: 0644]
ld/testsuite/ld-arm/arm-lib-plt-2.rd [new file with mode: 0644]
ld/testsuite/ld-arm/arm-lib-plt-2a.s [new file with mode: 0644]
ld/testsuite/ld-arm/arm-lib-plt-2b.s [new file with mode: 0644]

index bb59da145252b5f4fa85ae27db97ec42bab3a2fa..198ed38bfda9648afe2813f14894b622176f4851 100644 (file)
@@ -1,3 +1,13 @@
+2011-03-14  Richard Sandiford  <richard.sandiford@linaro.org>
+
+       * elf32-arm.c (elf32_arm_check_relocs): Use call_reloc_p,
+       may_need_local_target_p and may_become_dynamic_p to classify
+       the relocation type.  Don't check info->symbolic or h->def_regular
+       when deciding whether to record a potential dynamic reloc.
+       Don't treat potential dynamic relocs as PLT references.
+       (elf32_arm_gc_sweep_hook): Update to match.  Assert that we don't
+       try to make the PLT reference count go negative.
+
 2011-03-14  Richard Sandiford  <richard.sandiford@linaro.org>
 
        * elf32-arm.c (elf32_arm_final_link_relocate): Always fill in the
index 138309018750d07c5d58ed60daa6d2775f22d59d..76c01276b4f9fc419c7dcd34475d3b60c3fa8ec7 100644 (file)
@@ -11243,7 +11243,10 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
     {
       unsigned long r_symndx;
       struct elf_link_hash_entry *h = NULL;
+      struct elf32_arm_link_hash_entry *eh;
       int r_type;
+      bfd_boolean may_become_dynamic_p;
+      bfd_boolean may_need_local_target_p;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
@@ -11253,6 +11256,10 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
+      eh = (struct elf32_arm_link_hash_entry *) h;
+
+      may_become_dynamic_p = FALSE;
+      may_need_local_target_p = FALSE;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       r_type = arm_real_reloc_type (globals, r_type);
@@ -11278,10 +11285,6 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
          globals->tls_ldm_got.refcount -= 1;
          break;
 
-       case R_ARM_ABS32:
-       case R_ARM_ABS32_NOI:
-       case R_ARM_REL32:
-       case R_ARM_REL32_NOI:
        case R_ARM_PC24:
        case R_ARM_PLT32:
        case R_ARM_CALL:
@@ -11290,6 +11293,20 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
        case R_ARM_THM_CALL:
        case R_ARM_THM_JUMP24:
        case R_ARM_THM_JUMP19:
+         may_need_local_target_p = TRUE;
+         break;
+
+       case R_ARM_ABS12:
+         if (!globals->vxworks_p)
+           {
+             may_need_local_target_p = TRUE;
+             break;
+           }
+         /* Fall through.  */
+       case R_ARM_ABS32:
+       case R_ARM_ABS32_NOI:
+       case R_ARM_REL32:
+       case R_ARM_REL32_NOI:
        case R_ARM_MOVW_ABS_NC:
        case R_ARM_MOVT_ABS:
        case R_ARM_MOVW_PREL_NC:
@@ -11299,38 +11316,44 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
        case R_ARM_THM_MOVW_PREL_NC:
        case R_ARM_THM_MOVT_PREL:
          /* Should the interworking branches be here also?  */
+         if ((info->shared || globals->root.is_relocatable_executable)
+             && (sec->flags & SEC_ALLOC) != 0
+             && (h != NULL
+                 || (r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI)))
+           may_become_dynamic_p = TRUE;
+         else
+           may_need_local_target_p = TRUE;
+         break;
 
-         if (h != NULL)
-           {
-             struct elf32_arm_link_hash_entry *eh;
-             struct elf_dyn_relocs **pp;
-             struct elf_dyn_relocs *p;
+       default:
+         break;
+       }
 
-             eh = (struct elf32_arm_link_hash_entry *) h;
+      if (may_need_local_target_p && h != NULL)
+       {
+         BFD_ASSERT (h->plt.refcount > 0);
+         h->plt.refcount -= 1;
 
-             if (h->plt.refcount > 0)
-               {
-                 h->plt.refcount -= 1;
-                 if (r_type == R_ARM_THM_CALL)
-                   eh->plt_maybe_thumb_refcount--;
+         if (r_type == R_ARM_THM_CALL)
+           eh->plt_maybe_thumb_refcount--;
 
-                 if (r_type == R_ARM_THM_JUMP24
-                     || r_type == R_ARM_THM_JUMP19)
-                   eh->plt_thumb_refcount--;
-               }
+         if (r_type == R_ARM_THM_JUMP24
+             || r_type == R_ARM_THM_JUMP19)
+           eh->plt_thumb_refcount--;
+       }
 
-             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-               if (p->sec == sec)
-                 {
-                   /* Everything must go for SEC.  */
-                   *pp = p->next;
-                   break;
-                 }
-           }
-         break;
+      if (may_become_dynamic_p && h != NULL)
+       {
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
-       default:
-         break;
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+           if (p->sec == sec)
+             {
+               /* Everything must go for SEC.  */
+               *pp = p->next;
+               break;
+             }
        }
     }
 
@@ -11350,7 +11373,9 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
   bfd *dynobj;
   asection *sreloc;
   struct elf32_arm_link_hash_table *htab;
-  bfd_boolean needs_plt;
+  bfd_boolean call_reloc_p;
+  bfd_boolean may_become_dynamic_p;
+  bfd_boolean may_need_local_target_p;
   unsigned long nsyms;
 
   if (info->relocatable)
@@ -11413,6 +11438,10 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       eh = (struct elf32_arm_link_hash_entry *) h;
 
+      call_reloc_p = FALSE;
+      may_become_dynamic_p = FALSE;
+      may_need_local_target_p = FALSE;
+
       /* Could be done earlier, if h were already available.  */
       r_type = elf32_arm_tls_transition (info, r_type, h);
       switch (r_type)
@@ -11524,13 +11553,6 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
              }
            break;
 
-         case R_ARM_ABS12:
-           /* VxWorks uses dynamic R_ARM_ABS12 relocations for
-              ldr __GOTT_INDEX__ offsets.  */
-           if (!htab->vxworks_p)
-             break;
-           /* Fall through.  */
-
          case R_ARM_PC24:
          case R_ARM_PLT32:
          case R_ARM_CALL:
@@ -11539,8 +11561,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          case R_ARM_THM_CALL:
          case R_ARM_THM_JUMP24:
          case R_ARM_THM_JUMP19:
-           needs_plt = 1;
-           goto normal_reloc;
+           call_reloc_p = TRUE;
+           may_need_local_target_p = TRUE;
+           break;
+
+         case R_ARM_ABS12:
+           /* VxWorks uses dynamic R_ARM_ABS12 relocations for
+              ldr __GOTT_INDEX__ offsets.  */
+           if (!htab->vxworks_p)
+             {
+               may_need_local_target_p = TRUE;
+               break;
+             }
+           /* Fall through.  */
 
          case R_ARM_MOVW_ABS_NC:
          case R_ARM_MOVT_ABS:
@@ -11565,134 +11598,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          case R_ARM_MOVT_PREL:
          case R_ARM_THM_MOVW_PREL_NC:
          case R_ARM_THM_MOVT_PREL:
-           needs_plt = 0;
-         normal_reloc:
 
            /* Should the interworking branches be listed here?  */
-           if (h != NULL)
-             {
-               /* 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.  */
-               if (!info->shared)
-                 h->non_got_ref = 1;
-
-               /* We may need a .plt entry if the function this reloc
-                  refers to is in a different object.  We can't tell for
-                  sure yet, because something later might force the
-                  symbol local.  */
-               if (needs_plt)
-                 h->needs_plt = 1;
-
-               /* If we create a PLT entry, this relocation will reference
-                  it, even if it's an ABS32 relocation.  */
-               h->plt.refcount += 1;
-
-               /* It's too early to use htab->use_blx here, so we have to
-                  record possible blx references separately from
-                  relocs that definitely need a thumb stub.  */
-
-               if (r_type == R_ARM_THM_CALL)
-                 eh->plt_maybe_thumb_refcount += 1;
-
-               if (r_type == R_ARM_THM_JUMP24
-                   || r_type == R_ARM_THM_JUMP19)
-                 eh->plt_thumb_refcount += 1;
-             }
-
-           /* If we are creating a shared library or relocatable executable,
-              and this is a reloc against a global symbol, or a non PC
-              relative reloc against a local symbol, then we need to copy
-              the reloc into the shared library.  However, if we are linking
-              with -Bsymbolic, we do not need to copy a reloc against a
-               global symbol which is defined in an object we are
-               including in the link (i.e., DEF_REGULAR is set).  At
-               this point we have not seen all the input files, so it is
-               possible that DEF_REGULAR is not set now but will be set
-               later (it is never cleared).  We account for that
-               possibility below by storing information in the
-               dyn_relocs field of the hash table entry.  */
+           /* If we are creating a shared library or relocatable
+              executable, and this is a reloc against a global symbol,
+              or a non-PC-relative reloc against a local symbol,
+              then we may need to copy the reloc into the output.  */
            if ((info->shared || htab->root.is_relocatable_executable)
                && (sec->flags & SEC_ALLOC) != 0
-               && ((r_type == R_ARM_ABS32 || r_type == R_ARM_ABS32_NOI)
-                   || (h != NULL && ! needs_plt
-                       && (! info->symbolic || ! h->def_regular))))
-             {
-               struct elf_dyn_relocs *p, **head;
-
-               /* When creating a shared object, we must copy these
-                   reloc types into the output file.  We create a reloc
-                   section in dynobj and make room for this reloc.  */
-               if (sreloc == NULL)
-                 {
-                   sreloc = _bfd_elf_make_dynamic_reloc_section
-                     (sec, dynobj, 2, abfd, ! htab->use_rel);
-
-                   if (sreloc == NULL)
-                     return FALSE;
-
-                   /* BPABI objects never have dynamic relocations mapped.  */
-                   if (htab->symbian_p)
-                     {
-                       flagword flags;
-
-                       flags = bfd_get_section_flags (dynobj, sreloc);
-                       flags &= ~(SEC_LOAD | SEC_ALLOC);
-                       bfd_set_section_flags (dynobj, sreloc, flags);
-                     }
-                 }
-
-               /* If this is a global symbol, we count the number of
-                  relocations we need for this symbol.  */
-               if (h != NULL)
-                 {
-                   head = &((struct elf32_arm_link_hash_entry *) h)->dyn_relocs;
-                 }
-               else
-                 {
-                   /* Track dynamic relocs needed for local syms too.
-                      We really need local syms available to do this
-                      easily.  Oh well.  */
-                   asection *s;
-                   void *vpp;
-                   Elf_Internal_Sym *isym;
-
-                   isym = bfd_sym_from_r_symndx (&htab->sym_cache,
-                                                 abfd, r_symndx);
-                   if (isym == NULL)
-                     return FALSE;
-
-                   s = bfd_section_from_elf_index (abfd, isym->st_shndx);
-                   if (s == NULL)
-                     s = sec;
-
-                   vpp = &elf_section_data (s)->local_dynrel;
-                   head = (struct elf_dyn_relocs **) vpp;
-                 }
-
-               p = *head;
-               if (p == NULL || p->sec != sec)
-                 {
-                   bfd_size_type amt = sizeof *p;
-
-                   p = (struct elf_dyn_relocs *)
-                        bfd_alloc (htab->root.dynobj, amt);
-                   if (p == NULL)
-                     return FALSE;
-                   p->next = *head;
-                   *head = p;
-                   p->sec = sec;
-                   p->count = 0;
-                   p->pc_count = 0;
-                 }
-
-               if (r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI)
-                 p->pc_count += 1;
-               p->count += 1;
-             }
+               && (h != NULL
+                   || (r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI)))
+             may_become_dynamic_p = TRUE;
+           else
+             may_need_local_target_p = TRUE;
            break;
 
         /* This relocation describes the C++ object vtable hierarchy.
@@ -11711,6 +11629,112 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
             return FALSE;
           break;
         }
+
+      if (h != NULL)
+       {
+         if (call_reloc_p)
+           /* We may need a .plt entry if the function this reloc
+              refers to is in a different object, regardless of the
+              symbol's type.  We can't tell for sure yet, because
+              something later might force the symbol local.  */
+           h->needs_plt = 1;
+         else if (may_need_local_target_p)
+           /* 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;
+       }
+
+      if (may_need_local_target_p && h != NULL)
+       {
+         /* If the symbol is a function that doesn't bind locally,
+            this relocation will need a PLT entry.  */
+         h->plt.refcount += 1;
+
+         /* It's too early to use htab->use_blx here, so we have to
+            record possible blx references separately from
+            relocs that definitely need a thumb stub.  */
+
+         if (r_type == R_ARM_THM_CALL)
+           eh->plt_maybe_thumb_refcount += 1;
+
+         if (r_type == R_ARM_THM_JUMP24
+             || r_type == R_ARM_THM_JUMP19)
+           eh->plt_thumb_refcount += 1;
+       }
+
+      if (may_become_dynamic_p)
+       {
+         struct elf_dyn_relocs *p, **head;
+
+         /* Create a reloc section in dynobj.  */
+         if (sreloc == NULL)
+           {
+             sreloc = _bfd_elf_make_dynamic_reloc_section
+               (sec, dynobj, 2, abfd, ! htab->use_rel);
+
+             if (sreloc == NULL)
+               return FALSE;
+
+             /* BPABI objects never have dynamic relocations mapped.  */
+             if (htab->symbian_p)
+               {
+                 flagword flags;
+
+                 flags = bfd_get_section_flags (dynobj, sreloc);
+                 flags &= ~(SEC_LOAD | SEC_ALLOC);
+                 bfd_set_section_flags (dynobj, sreloc, flags);
+               }
+           }
+
+         /* If this is a global symbol, count the number of
+            relocations we need for this symbol.  */
+         if (h != NULL)
+           head = &((struct elf32_arm_link_hash_entry *) h)->dyn_relocs;
+         else
+           {
+             /* Track dynamic relocs needed for local syms too.
+                We really need local syms available to do this
+                easily.  Oh well.  */
+             asection *s;
+             void *vpp;
+             Elf_Internal_Sym *isym;
+
+             isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                           abfd, r_symndx);
+             if (isym == NULL)
+               return FALSE;
+
+             s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+             if (s == NULL)
+               s = sec;
+
+             vpp = &elf_section_data (s)->local_dynrel;
+             head = (struct elf_dyn_relocs **) vpp;
+           }
+
+         p = *head;
+         if (p == NULL || p->sec != sec)
+           {
+             bfd_size_type amt = sizeof *p;
+
+             p = (struct elf_dyn_relocs *) bfd_alloc (htab->root.dynobj, amt);
+             if (p == NULL)
+               return FALSE;
+             p->next = *head;
+             *head = p;
+             p->sec = sec;
+             p->count = 0;
+             p->pc_count = 0;
+           }
+
+         if (r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI)
+           p->pc_count += 1;
+         p->count += 1;
+       }
     }
 
   return TRUE;
index fdeaf77c1b99cfc720cd2c5f2ed0dca85a4240e8..d2532674d6aedcf5865deb3d735e8c95573843da 100644 (file)
@@ -1,3 +1,9 @@
+2011-03-14  Richard Sandiford  <richard.sandiford@linaro.org>
+
+       * ld-arm/arm-lib-plt-2a.s, ld-arm/arm-lib-plt-2b.s,
+       ld-arm/arm-lib-plt-2.dd, ld-arm/arm-lib-plt-2.rd: New tests.
+       * ld-arm/arm-elf.exp: Run them.
+
 2011-03-14  Richard Sandiford  <richard.sandiford@linaro.org>
 
        * ld-arm/exec-got-1a.s, ld-arm/exec-got-1b.s, ld-arm/exec-got-1.d,
index dcdc2310d44f993d3267b9087ee2f59a9f6cbac1..11ee5759afbecb9672347718c50360cde8b0c191 100644 (file)
@@ -80,6 +80,14 @@ set armelftests {
     {"Simple PIC shared library" "-shared" "" {arm-lib-plt32.s}
      {{objdump -fdw arm-lib-plt32.d} {objdump -Rw arm-lib-plt32.r}}
      "arm-lib-plt32.so"}
+    {"Indirect cross-library function reference (set-up)"
+     "-shared" "" {arm-lib-plt-2a.s}
+     {}
+     "arm-lib-plt-2a.so"}
+    {"Indirect cross-library function reference"
+     "-shared tmpdir/arm-lib-plt-2a.so" "" {arm-lib-plt-2b.s}
+     {{objdump -dr arm-lib-plt-2.dd} {readelf --relocs arm-lib-plt-2.rd}}
+     "arm-lib-plt-2b.so"}
     {"Simple dynamic application" "tmpdir/arm-lib.so" "" {arm-app.s}
      {{objdump -fdw arm-app.d} {objdump -Rw arm-app.r}}
      "arm-app"}
diff --git a/ld/testsuite/ld-arm/arm-lib-plt-2.dd b/ld/testsuite/ld-arm/arm-lib-plt-2.dd
new file mode 100644 (file)
index 0000000..fd61b73
--- /dev/null
@@ -0,0 +1,4 @@
+
+.*:     file format .*
+
+# There shouldn't be any code at all.
diff --git a/ld/testsuite/ld-arm/arm-lib-plt-2.rd b/ld/testsuite/ld-arm/arm-lib-plt-2.rd
new file mode 100644 (file)
index 0000000..3860bdd
--- /dev/null
@@ -0,0 +1,6 @@
+
+Relocation section '.rel.dyn' .*:
+ Offset .*
+.* R_ARM_ABS32       00000000   foo
+
+# There shouldn't be any .rel.plt relocations.
diff --git a/ld/testsuite/ld-arm/arm-lib-plt-2a.s b/ld/testsuite/ld-arm/arm-lib-plt-2a.s
new file mode 100644 (file)
index 0000000..6c8edac
--- /dev/null
@@ -0,0 +1,5 @@
+       .globl  foo
+       .type   foo,%function
+foo:
+       mov     pc,lr
+       .size   foo,.-foo
diff --git a/ld/testsuite/ld-arm/arm-lib-plt-2b.s b/ld/testsuite/ld-arm/arm-lib-plt-2b.s
new file mode 100644 (file)
index 0000000..fa5b135
--- /dev/null
@@ -0,0 +1,2 @@
+       .data
+       .word   foo