diff options
author | Christophe Lyon <christophe.lyon@st.com> | 2009-03-05 17:28:21 +0000 |
---|---|---|
committer | Christophe Lyon <christophe.lyon@st.com> | 2009-03-05 17:28:21 +0000 |
commit | 5fa9e92f74b051a84c435688595c141456a5d9f3 (patch) | |
tree | 4af9f514e206a1cc3979010296dd729d01f19e23 /bfd | |
parent | 84d7b001a67873d45e47e52e9978f09f78e96035 (diff) | |
download | gdb-5fa9e92f74b051a84c435688595c141456a5d9f3.zip gdb-5fa9e92f74b051a84c435688595c141456a5d9f3.tar.gz gdb-5fa9e92f74b051a84c435688595c141456a5d9f3.tar.bz2 |
2009-03-05 Christophe Lyon <christophe.lyon@st.com>
bfd/
* elf32-arm.c (arm_type_of_stub): Handle long branches targetting
PLT entries.
(elf32_arm_final_link_relocate): Likewise.
testsuite/
* ld-arm/arm-elf.exp: Add 2 more tests to check long branch stubs
in PLT context.
* ld-arm/farcall-mixed-app-v5.d: New file.
* ld-arm/farcall-mixed-app.d: Likewise.
* ld-arm/farcall-mixed-app.r: Likewise.
* ld-arm/farcall-mixed-app.s: Likewise.
* ld-arm/farcall-mixed-app.sym: Likewise.
* ld-arm/farcall-mixed-lib.d: Likewise.
* ld-arm/farcall-mixed-lib.r: Likewise.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 6 | ||||
-rw-r--r-- | bfd/elf32-arm.c | 53 |
2 files changed, 48 insertions, 11 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 78a23a8..bc12f9f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2009-03-05 Christophe Lyon <christophe.lyon@st.com> + + * elf32-arm.c (arm_type_of_stub): Handle long branches targetting + PLT entries. + (elf32_arm_final_link_relocate): Likewise. + 2009-03-05 Moritz Kroll <Moritz.Kroll@gmx.de> PR 9923 diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 2527e5e..607ba04 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -2857,6 +2857,7 @@ arm_type_of_stub (struct bfd_link_info *info, int thumb2; int thumb_only; enum elf32_arm_stub_type stub_type = arm_stub_none; + int use_plt = 0; /* We don't know the actual type of destination in case it is of type STT_SECTION: give up. */ @@ -2878,20 +2879,38 @@ arm_type_of_stub (struct bfd_link_info *info, r_type = ELF32_R_TYPE (rel->r_info); - /* If the call will go through a PLT entry then we do not need - glue. */ + /* Keep a simpler condition, for the sake of clarity. */ if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1) - return stub_type; + { + use_plt = 1; + /* Note when dealing with PLT entries: the main PLT stub is in + ARM mode, so if the branch is in Thumb mode, another + Thumb->ARM stub will be inserted later just before the ARM + PLT stub. We don't take this extra distance into account + here, because if a long branch stub is needed, we'll add a + Thumb->Arm one and branch directly to the ARM PLT entry + because it avoids spreading offset corrections in several + places. */ + } if (r_type == R_ARM_THM_CALL) { + /* Handle cases where: + - this call goes too far (different Thumb/Thumb2 max + distance) + - it's a Thumb->Arm call and blx is not available. A stub is + needed in this case, but only if this call is not through a + PLT entry. Indeed, PLT stubs handle mode switching already. + */ if ((!thumb2 && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET))) || (thumb2 && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) - || ((st_type != STT_ARM_TFUNC) && !globals->use_blx)) + || ((st_type != STT_ARM_TFUNC) + && ((r_type == R_ARM_THM_CALL) && !globals->use_blx) + && !use_plt)) { if (st_type == STT_ARM_TFUNC) { @@ -6049,9 +6068,11 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, /* Handle relocations which should use the PLT entry. ABS32/REL32 will use the symbol's value, which may point to a PLT entry, but we don't need to handle that here. If we created a PLT entry, all - branches in this object should go to it. */ + branches in this object should go to it, except if the PLT is too + far away, in which case a long branch stub should be inserted. */ if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32 - && r_type != R_ARM_ABS32_NOI && r_type != R_ARM_REL32_NOI) + && r_type != R_ARM_ABS32_NOI && r_type != R_ARM_REL32_NOI + && r_type != R_ARM_CALL) && h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) @@ -6208,11 +6229,6 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, bfd_signed_vma branch_offset; struct elf32_arm_stub_hash_entry *stub_entry = NULL; - from = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - branch_offset = (bfd_signed_vma)(value - from); - if (r_type == R_ARM_XPC25) { /* Check for Arm calling Arm function. */ @@ -6244,6 +6260,21 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, destination is too far or we are changing mode. */ if (r_type == R_ARM_CALL) { + /* If the call goes through a PLT entry, make sure to + check distance to the right destination address. */ + if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) + { + value = (splt->output_section->vma + + splt->output_offset + + h->plt.offset); + *unresolved_reloc_p = FALSE; + } + + from = (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + branch_offset = (bfd_signed_vma)(value - from); + if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET || branch_offset < ARM_MAX_BWD_BRANCH_OFFSET || sym_flags == STT_ARM_TFUNC) |