293 lines
9.6 KiB
Diff
293 lines
9.6 KiB
Diff
--- binutils-2.16/.pc/binutils-2.16-thumb-trampoline.patch/bfd/elf32-arm.c 2005-05-02 12:43:06.000000000 -0700
|
|
+++ binutils-2.16/bfd/elf32-arm.c 2005-09-19 22:58:49.834931044 -0700
|
|
@@ -24,6 +24,8 @@
|
|
#include "libbfd.h"
|
|
#include "elf-bfd.h"
|
|
|
|
+#define NOTE_DEBUG 0
|
|
+
|
|
#ifndef NUM_ELEM
|
|
#define NUM_ELEM(a) (sizeof (a) / (sizeof (a)[0]))
|
|
#endif
|
|
@@ -1127,6 +1129,10 @@
|
|
used, we need to record the index into .got.plt instead of
|
|
recomputing it from the PLT offset. */
|
|
bfd_signed_vma plt_got_offset;
|
|
+
|
|
+ /* This is used to sanity check that the Thumb trampoline space
|
|
+ really was allocated. */
|
|
+ int accomodate_trampoline;
|
|
};
|
|
|
|
/* Traverse an arm ELF linker hash table. */
|
|
@@ -1219,9 +1225,15 @@
|
|
table, string));
|
|
if (ret != NULL)
|
|
{
|
|
+#if NOTE_DEBUG
|
|
+ _bfd_error_handler(
|
|
+ _("NOTE: %x(%s): New hash entry (plt refcount %d)"),
|
|
+ ret, string, ret->root.plt.refcount);
|
|
+#endif
|
|
ret->relocs_copied = NULL;
|
|
ret->plt_thumb_refcount = 0;
|
|
ret->plt_got_offset = -1;
|
|
+ ret->accomodate_trampoline = 0;
|
|
}
|
|
|
|
return (struct bfd_hash_entry *) ret;
|
|
@@ -1335,16 +1347,38 @@
|
|
eind->relocs_copied = NULL;
|
|
}
|
|
|
|
- /* If the direct symbol already has an associated PLT entry, the
|
|
- indirect symbol should not. If it doesn't, swap refcount information
|
|
- from the indirect symbol. */
|
|
- if (edir->plt_thumb_refcount == 0)
|
|
+ if (ind->root.type == bfd_link_hash_indirect)
|
|
{
|
|
- edir->plt_thumb_refcount = eind->plt_thumb_refcount;
|
|
- eind->plt_thumb_refcount = 0;
|
|
+ bfd_signed_vma tmp;
|
|
+ bfd_signed_vma lowest_valid = bed->can_refcount;
|
|
+
|
|
+ /* If the direct symbol already has an associated PLT entry, the
|
|
+ indirect symbol should not. If it doesn't, swap refcount information
|
|
+ from the indirect symbol. */
|
|
+#if NOTE_DEBUG
|
|
+ _bfd_error_handler(_("NOTE: %x(%s,%d,%d) <== %x(%s,%d,%d)"),
|
|
+ dir, dir->root.root.string, dir->plt.refcount, edir->plt_thumb_refcount,
|
|
+ ind, ind->root.root.string, ind->plt.refcount, eind->plt_thumb_refcount);
|
|
+#endif
|
|
+
|
|
+ /* Copy over the global and procedure linkage table refcount entries.
|
|
+ These may have been already set up by a check_relocs routine. This
|
|
+ code duplicates that for the plt refcount in elf.c
|
|
+ _bfd_elf_link_hash_copy_indirect */
|
|
+ tmp = dir->plt.refcount;
|
|
+ /* this obfuscated test evaluates to bed->can_refcount && plt.refcount == 0
|
|
+ * || plt.refcount < 0.
|
|
+ */
|
|
+ if (tmp < lowest_valid)
|
|
+ {
|
|
+ tmp = edir->plt_thumb_refcount;
|
|
+ edir->plt_thumb_refcount = eind->plt_thumb_refcount;
|
|
+ eind->plt_thumb_refcount = tmp;
|
|
+ BFD_ASSERT(eind->accomodate_trampoline == 0);
|
|
+ }
|
|
+ else
|
|
+ BFD_ASSERT (eind->plt_thumb_refcount == 0);
|
|
}
|
|
- else
|
|
- BFD_ASSERT (eind->plt_thumb_refcount == 0);
|
|
|
|
_bfd_elf_link_hash_copy_indirect (bed, dir, ind);
|
|
}
|
|
@@ -2060,7 +2094,7 @@
|
|
(*_bfd_error_handler)
|
|
(_("%B(%s): warning: interworking not enabled.\n"
|
|
" first occurrence: %B: thumb call to arm"),
|
|
- sym_sec->owner, input_bfd, name);
|
|
+ sym_sec->owner, name, input_bfd);
|
|
|
|
return FALSE;
|
|
}
|
|
@@ -2165,7 +2199,7 @@
|
|
(*_bfd_error_handler)
|
|
(_("%B(%s): warning: interworking not enabled.\n"
|
|
" first occurrence: %B: arm call to thumb"),
|
|
- sym_sec->owner, input_bfd, name);
|
|
+ sym_sec->owner, name, input_bfd);
|
|
}
|
|
|
|
--my_offset;
|
|
@@ -2481,7 +2515,7 @@
|
|
instruction instead ? */
|
|
if (sym_flags != STT_ARM_TFUNC)
|
|
(*_bfd_error_handler)
|
|
- (_("\%B: Warning: Arm BLX instruction targets Arm function '%s'."),
|
|
+ (_("%B: Warning: Arm BLX instruction targets Arm function '%s'."),
|
|
input_bfd,
|
|
h ? h->root.root.string : "(local)");
|
|
}
|
|
@@ -2697,6 +2731,20 @@
|
|
/* Handle calls via the PLT. */
|
|
if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
|
|
{
|
|
+ struct elf32_arm_link_hash_entry *eh;
|
|
+ eh = (struct elf32_arm_link_hash_entry *) h;
|
|
+ if (!eh->accomodate_trampoline)
|
|
+ {
|
|
+ /* %B of output_bfd crashes here, so %x is used instead */
|
|
+ _bfd_error_handler(
|
|
+ _("ERROR: %B: %x(%s): missing thumb trampoline, refcount(thumb %d, plt %d) in %x at %x+%x+%x"),
|
|
+ input_bfd, h, h->root.root.string, eh->plt_thumb_refcount,
|
|
+ h->plt.refcount, output_bfd, splt->output_section->vma,
|
|
+ splt->output_offset, h->plt.offset);
|
|
+ /* The relocation would point to garbage, it gets skipped... */
|
|
+ return bfd_reloc_dangerous;
|
|
+ }
|
|
+
|
|
value = (splt->output_section->vma
|
|
+ splt->output_offset
|
|
+ h->plt.offset);
|
|
@@ -3525,8 +3573,9 @@
|
|
{
|
|
_bfd_error_handler
|
|
(_("ERROR: Source object %B has EABI version %d, but target %B has EABI version %d"),
|
|
- ibfd, obfd,
|
|
+ ibfd,
|
|
(in_flags & EF_ARM_EABIMASK) >> 24,
|
|
+ obfd,
|
|
(out_flags & EF_ARM_EABIMASK) >> 24);
|
|
return FALSE;
|
|
}
|
|
@@ -3538,8 +3587,9 @@
|
|
{
|
|
_bfd_error_handler
|
|
(_("ERROR: %B is compiled for APCS-%d, whereas target %B uses APCS-%d"),
|
|
- ibfd, obfd,
|
|
+ ibfd,
|
|
in_flags & EF_ARM_APCS_26 ? 26 : 32,
|
|
+ obfd,
|
|
out_flags & EF_ARM_APCS_26 ? 26 : 32);
|
|
flags_compatible = FALSE;
|
|
}
|
|
@@ -3903,10 +3953,18 @@
|
|
eh = (struct elf32_arm_link_hash_entry *) h;
|
|
|
|
if (h->plt.refcount > 0)
|
|
+ h->plt.refcount -= 1;
|
|
+
|
|
+ if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_PC22)
|
|
{
|
|
- h->plt.refcount -= 1;
|
|
- if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_PC22)
|
|
- eh->plt_thumb_refcount--;
|
|
+ BFD_ASSERT (eh->plt_thumb_refcount > 0);
|
|
+ eh->plt_thumb_refcount--;
|
|
+ BFD_ASSERT (eh->accomodate_trampoline == 0);
|
|
+#if NOTE_DEBUG
|
|
+ _bfd_error_handler(
|
|
+ _("NOTE: %B: %x(%s): Thumb refcount decremented to %d (plt refcount %d)"),
|
|
+ abfd, h, h->root.root.string, eh->plt_thumb_refcount, h->plt.refcount);
|
|
+#endif
|
|
}
|
|
|
|
if (r_type == R_ARM_ABS32
|
|
@@ -3994,6 +4052,10 @@
|
|
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
|
|
|
|
eh = (struct elf32_arm_link_hash_entry *) h;
|
|
+#if NOTE_DEBUG
|
|
+ if (h != NULL)
|
|
+ _bfd_error_handler(_("NOTE: %B: %x(%s): verify relocation"), abfd, h, h->root.root.string);
|
|
+#endif
|
|
|
|
switch (r_type)
|
|
{
|
|
@@ -4078,10 +4140,30 @@
|
|
|
|
/* If we create a PLT entry, this relocation will reference
|
|
it, even if it's an ABS32 relocation. */
|
|
- h->plt.refcount += 1;
|
|
+ if (h->plt.refcount >= 0)
|
|
+ h->plt.refcount += 1;
|
|
+ else
|
|
+ {
|
|
+ /* This happens, I suspect it happens with glue code because,
|
|
+ * somehow, the backend data had can_refcount==0. Expert required...
|
|
+ */
|
|
+ _bfd_error_handler(
|
|
+ _("WARNING: %B: %x(%s): PLT refcount was %d (set to 1)"),
|
|
+ abfd, h, h->root.root.string, h->plt.refcount);
|
|
+ h->plt.refcount = 1;
|
|
+ }
|
|
|
|
if (r_type == R_ARM_THM_PC22)
|
|
- eh->plt_thumb_refcount += 1;
|
|
+ {
|
|
+ eh->plt_thumb_refcount += 1;
|
|
+ BFD_ASSERT (eh->plt_thumb_refcount <= h->plt.refcount);
|
|
+ BFD_ASSERT (eh->accomodate_trampoline == 0);
|
|
+#if NOTE_DEBUG
|
|
+ _bfd_error_handler(
|
|
+ _("NOTE: %B: %x(%s): Thumb refcount incremented to %d (plt refcount %d)"),
|
|
+ abfd, h, h->root.root.string, eh->plt_thumb_refcount, h->plt.refcount);
|
|
+#endif
|
|
+ }
|
|
}
|
|
|
|
/* If we are creating a shared library or relocatable executable,
|
|
@@ -4376,8 +4458,15 @@
|
|
object, or if all references were garbage collected. In
|
|
such a case, we don't actually need to build a procedure
|
|
linkage table, and we can just do a PC24 reloc instead. */
|
|
+#if NOTE_DEBUG
|
|
+ _bfd_error_handler(
|
|
+ _("NOTE: %x(%s): Thumb refcount zeroed (plt refcount %d, thumb %d) (%s)"),
|
|
+ h, h->root.root.string, h->plt.refcount, eh->plt_thumb_refcount,
|
|
+ SYMBOL_CALLS_LOCAL (info, h) ? "local call" : "invisible");
|
|
+#endif
|
|
h->plt.offset = (bfd_vma) -1;
|
|
eh->plt_thumb_refcount = 0;
|
|
+ BFD_ASSERT (eh->accomodate_trampoline == 0);
|
|
h->needs_plt = 0;
|
|
}
|
|
|
|
@@ -4390,8 +4479,14 @@
|
|
in check_relocs. We can't decide accurately between function
|
|
and non-function syms in check-relocs; Objects loaded later in
|
|
the link may change h->type. So fix it now. */
|
|
+#if NOTE_DEBUG
|
|
+ _bfd_error_handler(
|
|
+ _("NOTE: %x(%s): Thumb refcount zeroed (%d, plt refcount %d)"),
|
|
+ h, h->root.root.string, eh->plt_thumb_refcount, h->plt.refcount);
|
|
+#endif
|
|
h->plt.offset = (bfd_vma) -1;
|
|
eh->plt_thumb_refcount = 0;
|
|
+ BFD_ASSERT (eh->accomodate_trampoline == 0);
|
|
}
|
|
|
|
/* If this is a weak symbol, and there is a real definition, the
|
|
@@ -4521,8 +4616,14 @@
|
|
for it. */
|
|
if (!htab->symbian_p && eh->plt_thumb_refcount > 0)
|
|
{
|
|
+#if NOTE_DEBUG
|
|
+ _bfd_error_handler(_("NOTE: %x(%s): Thumb trampoline created at %x"),
|
|
+ h, h->root.root.string, h->plt.offset);
|
|
+#endif
|
|
h->plt.offset += PLT_THUMB_STUB_SIZE;
|
|
s->size += PLT_THUMB_STUB_SIZE;
|
|
+ BFD_ASSERT (eh->accomodate_trampoline == 0);
|
|
+ eh->accomodate_trampoline = 1;
|
|
}
|
|
|
|
/* If this symbol is not defined in a regular file, and we are
|
|
@@ -5014,10 +5115,20 @@
|
|
|
|
if (eh->plt_thumb_refcount > 0)
|
|
{
|
|
- bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[0],
|
|
- splt->contents + h->plt.offset - 4);
|
|
- bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[1],
|
|
- splt->contents + h->plt.offset - 2);
|
|
+ if (eh->accomodate_trampoline == 1)
|
|
+ {
|
|
+ bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[0],
|
|
+ splt->contents + h->plt.offset - 4);
|
|
+ bfd_put_16 (output_bfd, elf32_arm_plt_thumb_stub[1],
|
|
+ splt->contents + h->plt.offset - 2);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ (*_bfd_error_handler) (
|
|
+ _("%B: no space for THUMB trampoline at %x[%x]"),
|
|
+ output_bfd, h->plt.offset, got_offset);
|
|
+ return FALSE;
|
|
+ }
|
|
}
|
|
|
|
bfd_put_32 (output_bfd, elf32_arm_plt_entry[0] | ((got_displacement & 0x0ff00000) >> 20),
|