summaryrefslogtreecommitdiff
path: root/bfd/elf32-arm.c
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@nildram.co.uk>2011-03-14 15:53:32 +0000
committerRichard Sandiford <rsandifo@nildram.co.uk>2011-03-14 15:53:32 +0000
commit868c08dea4c2f3c7ba2f36eff7bc072c5a733bd0 (patch)
tree95dcdddd771b590218503513b5475b3446745bc8 /bfd/elf32-arm.c
parentc82752d7ebdb347961edea2bdcdada0d0e7f4f7b (diff)
downloadbinutils-redhat-868c08dea4c2f3c7ba2f36eff7bc072c5a733bd0.tar.gz
bfd/
* 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.
Diffstat (limited to 'bfd/elf32-arm.c')
-rw-r--r--bfd/elf32-arm.c352
1 files changed, 188 insertions, 164 deletions
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 1383090187..76c01276b4 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -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;