From 3b98fa7d6706063736b5a910fc1228c747dabeb5 Mon Sep 17 00:00:00 2001 From: John Bowler Date: Thu, 22 Sep 2005 19:36:38 +0000 Subject: binutils_2.16: patch thumb trampoline and glue code generation This patch fixes problems with the ARM thumb specific code generation. It also adds debugging to bfd/elf32-arm.c to detect ref counting problems - one error message can fire in theory in the absence of thumb support if a union refcount field is used to refcount when it is set to something else. The error should be ignorable, in that the code should not have changed in effect. --- .../binutils-2.16/binutils-2.16-thumb-glue.patch | 76 ++++++ .../binutils-2.16-thumb-trampoline.patch | 292 +++++++++++++++++++++ packages/binutils/binutils_2.16.bb | 6 +- 3 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 packages/binutils/binutils-2.16/binutils-2.16-thumb-glue.patch create mode 100644 packages/binutils/binutils-2.16/binutils-2.16-thumb-trampoline.patch (limited to 'packages/binutils') diff --git a/packages/binutils/binutils-2.16/binutils-2.16-thumb-glue.patch b/packages/binutils/binutils-2.16/binutils-2.16-thumb-glue.patch new file mode 100644 index 0000000000..59d8035f7d --- /dev/null +++ b/packages/binutils/binutils-2.16/binutils-2.16-thumb-glue.patch @@ -0,0 +1,76 @@ +# The ARM->Thumb glue uses an ldr of the target function address, this +# simply doesn't work for PIC code, changed to use 4 word PIC glue +# +--- binutils-2.16/.pc/binutils-2.16-thumb-glue.patch/bfd/elf32-arm.c 2005-09-18 03:52:15.465165051 -0700 ++++ binutils-2.16/bfd/elf32-arm.c 2005-09-18 03:52:33.546302825 -0700 +@@ -1493,19 +1493,20 @@ + return myh; + } + +-/* ARM->Thumb glue: ++/* ARM->Thumb glue (PIC version): + + .arm + __func_from_arm: + ldr r12, __func_addr ++ add r12, r12, pc @ pc is __func_addr, so r12 is func + bx r12 + __func_addr: +- .word func @ behave as if you saw a ARM_32 reloc. */ ++ .word func-.+1 @ offset to actual function, low bit set */ + +-#define ARM2THUMB_GLUE_SIZE 12 +-static const insn32 a2t1_ldr_insn = 0xe59fc000; +-static const insn32 a2t2_bx_r12_insn = 0xe12fff1c; +-static const insn32 a2t3_func_addr_insn = 0x00000001; ++#define ARM2THUMB_GLUE_SIZE 16 ++static const insn32 a2t1_ldr_insn = 0xe59fc004; ++static const insn32 a2t2_add_r12_insn = 0xe08fc00c; ++static const insn32 a2t3_bx_r12_insn = 0xe12fff1c; + + /* Thumb->ARM: Thumb->(non-interworking aware) ARM + +@@ -2187,6 +2188,8 @@ + + if ((my_offset & 0x01) == 0x01) + { ++ long int ret_offset; ++ + if (sym_sec != NULL + && sym_sec->owner != NULL + && !INTERWORK_FLAG (sym_sec->owner)) +@@ -2203,12 +2206,31 @@ + bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn, + s->contents + my_offset); + +- bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn, ++ bfd_put_32 (output_bfd, (bfd_vma) a2t2_add_r12_insn, + s->contents + my_offset + 4); + +- /* It's a thumb address. Add the low order bit. */ +- bfd_put_32 (output_bfd, val | a2t3_func_addr_insn, ++ bfd_put_32 (output_bfd, (bfd_vma) a2t3_bx_r12_insn, + s->contents + my_offset + 8); ++ ++ /* Calculate the offset to the actual function. */ ++ ret_offset = ++ /* Address of destination of the stub. */ ++ ((bfd_signed_vma) val) ++ - ((bfd_signed_vma) ++ /* Offset from the start of the current section ++ to the start of the stubs. */ ++ (s->output_offset ++ /* Offset of the start of this stub from the start of the stubs. */ ++ + my_offset ++ /* Address of the start of the current section. */ ++ + s->output_section->vma) ++ /* The word is 12 bytes into the stub. */ ++ + 12 ++ /* The destination is a thumb function so the bottom bit must be set. */ ++ - 1); ++ ++ bfd_put_32 (output_bfd, (bfd_vma) ret_offset, ++ s->contents + my_offset + 12); + } + + BFD_ASSERT (my_offset <= globals->arm_glue_size); diff --git a/packages/binutils/binutils-2.16/binutils-2.16-thumb-trampoline.patch b/packages/binutils/binutils-2.16/binutils-2.16-thumb-trampoline.patch new file mode 100644 index 0000000000..a4f90a7254 --- /dev/null +++ b/packages/binutils/binutils-2.16/binutils-2.16-thumb-trampoline.patch @@ -0,0 +1,292 @@ +--- 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), diff --git a/packages/binutils/binutils_2.16.bb b/packages/binutils/binutils_2.16.bb index 046f2c15c7..bb66ca6741 100644 --- a/packages/binutils/binutils_2.16.bb +++ b/packages/binutils/binutils_2.16.bb @@ -3,7 +3,7 @@ HOMEPAGE = "http://www.gnu.org/software/binutils/" SECTION = "devel" LICENSE = "GPL" MAINTAINER = "Gerald Britton " -PR = "r2" +PR = "r3" SRC_URI = \ "http://ftp.gnu.org/gnu/binutils/binutils-${PV}.tar.bz2 \ @@ -15,6 +15,10 @@ SRC_URI = \ # uclibc patches SRC_URI += "file://binutils-2.16-linux-uclibc.patch;patch=1" +# thumb support patches +SRC_URI += "file://binutils-2.16-thumb-trampoline.patch;patch=1" +SRC_URI += "file://binutils-2.16-thumb-glue.patch;patch=1" + #to be removed: # this patch does not seem to do anything any longer #SRC_URI += "file://binutils-2.15.90.0.3-uclibc-200-build_modules.patch;patch=1" -- cgit v1.2.3