--- 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),