diff options
author | Terry Guo <terry.guo@arm.com> | 2014-08-21 18:00:35 +0800 |
---|---|---|
committer | Terry Guo <terry.guo@arm.com> | 2014-08-21 18:00:35 +0800 |
commit | c542398150124a0b5adbbeeb274e55ee56d3120a (patch) | |
tree | 6aad77db344e75217caa41097faf6fc474c49fa9 /bfd/elf32-arm.c | |
parent | de589d04f30e658fcf4ba37a678c9487c128f97f (diff) | |
download | gdb-c542398150124a0b5adbbeeb274e55ee56d3120a.zip gdb-c542398150124a0b5adbbeeb274e55ee56d3120a.tar.gz gdb-c542398150124a0b5adbbeeb274e55ee56d3120a.tar.bz2 |
bfd/ChangeLog
2014-08-21 Tony Wang <tony.wang@arm.com>
* elf32-arm.c (elf32_arm_final_link_relocate): Implement
the veneer routine for R_ARM_THM_JUMP19.
(arm_type_of_stub): Add conditional clause for R_ARM_THM_JUMP19
(elf32_arm_size_stub): Ditto.
ld/testsuite/ChangeLog
2014-08-21 Tony Wang <tony.wang@arm.com>
* ld-arm/jump-reloc-veneers-cond.s: New test.
* ld-arm/farcall-cond-thumb-arm.s: Ditto.
* ld-arm/jump-reloc-veneers-cond-short.d: Expected output
for target without a veneer generation.
* ld-arm/jump-reloc-veneers-cond-long.d: Expected output
for target with a veneer generation.
* ld-arm/farcall-cond-thumb-arm.d: Expected output for
inter working veneer generation.
* ld-arm/arm-elf.exp: Add tests for conditional branch veneer.
Diffstat (limited to 'bfd/elf32-arm.c')
-rw-r--r-- | bfd/elf32-arm.c | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 73b5fb0..89d51c1 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -2283,6 +2283,8 @@ static const bfd_vma elf32_arm_nacl_plt_entry [] = #define THM_MAX_BWD_BRANCH_OFFSET (-(1 << 22) + 4) #define THM2_MAX_FWD_BRANCH_OFFSET (((1 << 24) - 2) + 4) #define THM2_MAX_BWD_BRANCH_OFFSET (-(1 << 24) + 4) +#define THM2_MAX_FWD_COND_BRANCH_OFFSET (((1 << 20) -2) + 4) +#define THM2_MAX_BWD_COND_BRANCH_OFFSET (-(1 << 20) + 4) enum stub_insn_type { @@ -3667,7 +3669,8 @@ arm_type_of_stub (struct bfd_link_info *info, /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we are considering a function call relocation. */ - if (thumb_only && (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) + if (thumb_only && (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24 + || r_type == R_ARM_THM_JUMP19) && branch_type == ST_BRANCH_TO_ARM) branch_type = ST_BRANCH_TO_THUMB; @@ -3711,7 +3714,7 @@ arm_type_of_stub (struct bfd_link_info *info, branch_offset = (bfd_signed_vma)(destination - location); if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24 - || r_type == R_ARM_THM_TLS_CALL) + || r_type == R_ARM_THM_TLS_CALL || r_type == R_ARM_THM_JUMP19) { /* Handle cases where: - this call goes too far (different Thumb/Thumb2 max @@ -3727,10 +3730,15 @@ arm_type_of_stub (struct bfd_link_info *info, || (thumb2 && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) + || (thumb2 + && (branch_offset > THM2_MAX_FWD_COND_BRANCH_OFFSET + || (branch_offset < THM2_MAX_BWD_COND_BRANCH_OFFSET)) + && (r_type == R_ARM_THM_JUMP19)) || (branch_type == ST_BRANCH_TO_ARM && (((r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_TLS_CALL) && !globals->use_blx) - || (r_type == R_ARM_THM_JUMP24)) + || (r_type == R_ARM_THM_JUMP24) + || (r_type == R_ARM_THM_JUMP19)) && !use_plt)) { if (branch_type == ST_BRANCH_TO_THUMB) @@ -5347,7 +5355,8 @@ elf32_arm_size_stubs (bfd *output_bfd, /* For historical reasons, use the existing names for ARM-to-Thumb and Thumb-to-ARM stubs. */ if ((r_type == (unsigned int) R_ARM_THM_CALL - || r_type == (unsigned int) R_ARM_THM_JUMP24) + || r_type == (unsigned int) R_ARM_THM_JUMP24 + || r_type == (unsigned int) R_ARM_THM_JUMP19) && branch_type == ST_BRANCH_TO_ARM) sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME, sym_name); @@ -9125,6 +9134,9 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, bfd_signed_vma reloc_signed_max = 0xffffe; bfd_signed_vma reloc_signed_min = -0x100000; bfd_signed_vma signed_check; + enum elf32_arm_stub_type stub_type = arm_stub_none; + struct elf32_arm_stub_hash_entry *stub_entry; + struct elf32_arm_link_hash_entry *hash; /* Need to refetch the addend, reconstruct the top three bits, and squish the two 11 bit pieces together. */ @@ -9156,8 +9168,25 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, *unresolved_reloc_p = FALSE; } - /* ??? Should handle interworking? GCC might someday try to - use this for tail calls. */ + hash = (struct elf32_arm_link_hash_entry *)h; + + stub_type = arm_type_of_stub (info, input_section, rel, + st_type, &branch_type, + hash, value, sym_sec, + input_bfd, sym_name); + if (stub_type != arm_stub_none) + { + stub_entry = elf32_arm_get_stub_entry (input_section, + sym_sec, h, + rel, globals, + stub_type); + if (stub_entry != NULL) + { + value = (stub_entry->stub_offset + + stub_entry->stub_sec->output_offset + + stub_entry->stub_sec->output_section->vma); + } + } relocation = value + signed_addend; relocation -= (input_section->output_section->vma |