Index: bfd/elf32-arm.c =================================================================== RCS file: /cvs/src/src/bfd/elf32-arm.c,v retrieving revision 1.180 diff -u -p -r1.180 elf32-arm.c --- bfd/elf32-arm.c 6 Mar 2009 08:57:57 -0000 1.180 +++ bfd/elf32-arm.c 6 Mar 2009 15:24:30 -0000 @@ -2893,14 +2893,15 @@ arm_type_of_stub (struct bfd_link_info * places. */ } - if (r_type == R_ARM_THM_CALL) + if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) { /* 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. + - it's a Thumb->Arm call and blx is not available, or it's a + Thumb->Arm branch (not bl). 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 @@ -2909,7 +2910,8 @@ arm_type_of_stub (struct bfd_link_info * && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) || ((st_type != STT_ARM_TFUNC) - && ((r_type == R_ARM_THM_CALL) && !globals->use_blx) + && (((r_type == R_ARM_THM_CALL) && !globals->use_blx) + || (r_type == R_ARM_THM_JUMP24)) && !use_plt)) { if (st_type == STT_ARM_TFUNC) @@ -2919,14 +2921,19 @@ arm_type_of_stub (struct bfd_link_info * { stub_type = (info->shared | globals->pic_veneer) /* PIC stubs. */ - ? ((globals->use_blx) - /* V5T and above. */ + ? ((globals->use_blx + && (r_type ==R_ARM_THM_CALL)) + /* V5T and above. Stub starts with ARM code, so + we must be able to switch mode before + reaching it, which is only possible for 'bl' + (ie R_ARM_THM_CALL relocation). */ ? arm_stub_long_branch_any_thumb_pic /* On V4T, use Thumb code only. */ : arm_stub_long_branch_thumb_only_pic) /* non-PIC stubs. */ - : ((globals->use_blx) + : ((globals->use_blx + && (r_type ==R_ARM_THM_CALL)) /* V5T and above. */ ? arm_stub_long_branch_any_any /* V4T. */ @@ -2956,14 +2963,16 @@ arm_type_of_stub (struct bfd_link_info * stub_type = (info->shared | globals->pic_veneer) /* PIC stubs. */ - ? ((globals->use_blx) + ? ((globals->use_blx + && (r_type ==R_ARM_THM_CALL)) /* V5T and above. */ ? arm_stub_long_branch_any_arm_pic /* V4T PIC stub. */ : arm_stub_long_branch_v4t_thumb_arm_pic) /* non-PIC stubs. */ - : ((globals->use_blx) + : ((globals->use_blx + && (r_type ==R_ARM_THM_CALL)) /* V5T and above. */ ? arm_stub_long_branch_any_any /* V4T. */ @@ -2977,7 +2986,7 @@ arm_type_of_stub (struct bfd_link_info * } } } - else if (r_type == R_ARM_CALL) + else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32) { if (st_type == STT_ARM_TFUNC) { @@ -2997,7 +3006,9 @@ arm_type_of_stub (struct bfd_link_info * the mode change (bit 24 (H) of BLX encoding). */ if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2) || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET) - || !globals->use_blx) + || ((r_type == R_ARM_CALL) && !globals->use_blx) + || (r_type == R_ARM_JUMP24) + || (r_type == R_ARM_PLT32)) { stub_type = (info->shared | globals->pic_veneer) /* PIC stubs. */ @@ -3740,9 +3751,12 @@ elf32_arm_size_stubs (bfd *output_bfd, goto error_ret_free_local; } - /* Only look for stubs on call instructions. */ + /* Only look for stubs on branch instructions. */ if ((r_type != (unsigned int) R_ARM_CALL) - && (r_type != (unsigned int) R_ARM_THM_CALL)) + && (r_type != (unsigned int) R_ARM_THM_CALL) + && (r_type != (unsigned int) R_ARM_JUMP24) + && (r_type != (unsigned int) R_ARM_THM_JUMP24) + && (r_type != (unsigned int) R_ARM_PLT32)) continue; /* Now determine the call target, its name, value, @@ -3876,11 +3890,13 @@ 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 - && st_type != STT_ARM_TFUNC) + if ( ((r_type == (unsigned int) R_ARM_THM_CALL) + || (r_type == (unsigned int) R_ARM_THM_JUMP24)) + && st_type != STT_ARM_TFUNC) sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME, sym_name); - else if (r_type == (unsigned int) R_ARM_CALL + else if ( ((r_type == (unsigned int) R_ARM_CALL) + || (r_type == (unsigned int) R_ARM_JUMP24)) && st_type == STT_ARM_TFUNC) sprintf (stub_entry->output_name, ARM2THUMB_GLUE_ENTRY_NAME, sym_name); @@ -4215,86 +4231,6 @@ record_arm_to_thumb_glue (struct bfd_lin return myh; } -static void -record_thumb_to_arm_glue (struct bfd_link_info *link_info, - struct elf_link_hash_entry *h) -{ - const char *name = h->root.root.string; - asection *s; - char *tmp_name; - struct elf_link_hash_entry *myh; - struct bfd_link_hash_entry *bh; - struct elf32_arm_link_hash_table *hash_table; - bfd_vma val; - - hash_table = elf32_arm_hash_table (link_info); - - BFD_ASSERT (hash_table != NULL); - BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL); - - s = bfd_get_section_by_name - (hash_table->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - - tmp_name = bfd_malloc ((bfd_size_type) strlen (name) - + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); - - myh = elf_link_hash_lookup - (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); - - if (myh != NULL) - { - /* We've already seen this guy. */ - free (tmp_name); - return; - } - - /* The only trick here is using hash_table->thumb_glue_size as the value. - Even though the section isn't allocated yet, this is where we will be - putting it. The +1 on the value marks that the stub has not been - output yet - not that it is a Thumb function. */ - bh = NULL; - val = hash_table->thumb_glue_size + 1; - _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, - tmp_name, BSF_GLOBAL, s, val, - NULL, TRUE, FALSE, &bh); - - /* If we mark it 'Thumb', the disassembler will do a better job. */ - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC); - myh->forced_local = 1; - - free (tmp_name); - -#define CHANGE_TO_ARM "__%s_change_to_arm" -#define BACK_FROM_ARM "__%s_back_from_arm" - - /* Allocate another symbol to mark where we switch to Arm mode. */ - tmp_name = bfd_malloc ((bfd_size_type) strlen (name) - + strlen (CHANGE_TO_ARM) + 1); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, CHANGE_TO_ARM, name); - - bh = NULL; - val = hash_table->thumb_glue_size + 4, - _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, - tmp_name, BSF_LOCAL, s, val, - NULL, TRUE, FALSE, &bh); - - free (tmp_name); - - s->size += THUMB2ARM_GLUE_SIZE; - hash_table->thumb_glue_size += THUMB2ARM_GLUE_SIZE; -} - - /* Allocate space for ARMv4 BX veneers. */ static void @@ -4670,9 +4606,6 @@ bfd_elf32_arm_process_before_allocation /* These are the only relocation types we care about. */ if ( r_type != R_ARM_PC24 - && r_type != R_ARM_PLT32 - && r_type != R_ARM_JUMP24 - && r_type != R_ARM_THM_JUMP24 && (r_type != R_ARM_V4BX || globals->fix_v4bx < 2)) continue; @@ -4724,8 +4657,6 @@ bfd_elf32_arm_process_before_allocation switch (r_type) { case R_ARM_PC24: - case R_ARM_PLT32: - case R_ARM_JUMP24: /* This one is a call from arm code. We need to look up the target of the call. If it is a thumb target, we insert glue. */ @@ -4733,16 +4664,6 @@ bfd_elf32_arm_process_before_allocation record_arm_to_thumb_glue (link_info, h); break; - case R_ARM_THM_JUMP24: - /* This one is a call from thumb code. We look - up the target of the call. If it is not a thumb - target, we insert glue. */ - if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC - && !(globals->use_blx && r_type == R_ARM_THM_CALL) - && h->root.type != bfd_link_hash_undefweak) - record_thumb_to_arm_glue (link_info, h); - break; - default: abort (); } @@ -6088,7 +6009,9 @@ elf32_arm_final_link_relocate (reloc_how 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_CALL) + && r_type != R_ARM_CALL + && r_type != R_ARM_JUMP24 + && r_type != R_ARM_PLT32) && h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) @@ -6256,7 +6179,7 @@ elf32_arm_final_link_relocate (reloc_how input_bfd, h ? h->root.root.string : "(local)"); } - else if (r_type != R_ARM_CALL) + else if (r_type == R_ARM_PC24) { /* Check for Arm calling Thumb function. */ if (sym_flags == STT_ARM_TFUNC) @@ -6274,7 +6197,9 @@ elf32_arm_final_link_relocate (reloc_how /* Check if a stub has to be inserted because the destination is too far or we are changing mode. */ - if (r_type == R_ARM_CALL) + if ( r_type == R_ARM_CALL + || r_type == R_ARM_JUMP24 + || r_type == R_ARM_PLT32) { /* If the call goes through a PLT entry, make sure to check distance to the right destination address. */ @@ -6293,7 +6218,11 @@ elf32_arm_final_link_relocate (reloc_how if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET || branch_offset < ARM_MAX_BWD_BRANCH_OFFSET - || sym_flags == STT_ARM_TFUNC) + || ((sym_flags == STT_ARM_TFUNC) + && (((r_type == R_ARM_CALL) && !globals->use_blx) + || (r_type == R_ARM_JUMP24) + || (r_type == R_ARM_PLT32) )) + ) { /* The target is out of reach, so redirect the branch to the local stub for this function. */ @@ -6358,16 +6287,17 @@ elf32_arm_final_link_relocate (reloc_how value = (signed_addend & howto->dst_mask) | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); - /* Set the H bit in the BLX instruction. */ - if (sym_flags == STT_ARM_TFUNC) - { - if (addend) - value |= (1 << 24); - else - value &= ~(bfd_vma)(1 << 24); - } if (r_type == R_ARM_CALL) { + /* Set the H bit in the BLX instruction. */ + if (sym_flags == STT_ARM_TFUNC) + { + if (addend) + value |= (1 << 24); + else + value &= ~(bfd_vma)(1 << 24); + } + /* Select the correct instruction (BL or BLX). */ /* Only if we are not handling a BL to a stub. In this case, mode switching is performed by the stub. */ @@ -6611,7 +6541,8 @@ elf32_arm_final_link_relocate (reloc_how /* Convert BL to BLX. */ lower_insn = (lower_insn & ~0x1000) | 0x0800; } - else if (r_type != R_ARM_THM_CALL) + else if (( r_type != R_ARM_THM_CALL) + && (r_type != R_ARM_THM_JUMP24)) { if (elf32_thumb_to_arm_stub (info, sym_name, input_bfd, output_bfd, input_section, @@ -6648,7 +6579,7 @@ elf32_arm_final_link_relocate (reloc_how *unresolved_reloc_p = FALSE; } - if (r_type == R_ARM_THM_CALL) + if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) { /* Check if a stub has to be inserted because the destination is too far. */ @@ -6668,7 +6599,9 @@ elf32_arm_final_link_relocate (reloc_how (thumb2 && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) - || ((sym_flags != STT_ARM_TFUNC) && !globals->use_blx)) + || ((sym_flags != STT_ARM_TFUNC) + && (((r_type == R_ARM_THM_CALL) && !globals->use_blx) + || r_type == R_ARM_THM_JUMP24))) { /* The target is out of reach or we are changing modes, so redirect the branch to the local stub for this @@ -6682,7 +6615,7 @@ elf32_arm_final_link_relocate (reloc_how + stub_entry->stub_sec->output_section->vma); /* If this call becomes a call to Arm, force BLX. */ - if (globals->use_blx) + if (globals->use_blx && (r_type == R_ARM_THM_CALL)) { if ((stub_entry && !arm_stub_is_thumb (stub_entry->stub_type)) Index: ld/testsuite/ld-arm/arm-call.d =================================================================== RCS file: /cvs/src/src/ld/testsuite/ld-arm/arm-call.d,v retrieving revision 1.3 diff -u -p -r1.3 arm-call.d --- ld/testsuite/ld-arm/arm-call.d 22 May 2007 17:17:53 -0000 1.3 +++ ld/testsuite/ld-arm/arm-call.d 6 Mar 2009 15:24:36 -0000 @@ -10,10 +10,10 @@ Disassembly of section .text: 800c: fb00000d blx 804a 8010: fa00000a blx 8040 8014: fb000009 blx 8042 - 8018: ea00000f b 805c <__t1_from_arm> - 801c: ea000010 b 8064 <__t2_from_arm> - 8020: 1b00000d blne 805c <__t1_from_arm> - 8024: 1b00000e blne 8064 <__t2_from_arm> + 8018: ea000010 b 8060 <__t1_from_arm> + 801c: ea000011 b 8068 <__t2_from_arm> + 8020: 1b00000e blne 8060 <__t1_from_arm> + 8024: 1b00000f blne 8068 <__t2_from_arm> 8028: 1b000003 blne 803c 802c: eb000002 bl 803c 8030: faffffff blx 8034 @@ -46,11 +46,13 @@ Disassembly of section .text: 8050: f7ff fff1 bl 8036 8054: f7ff efd4 blx 8000 <_start> 8058: f7ff efd2 blx 8000 <_start> + 805c: 0000 lsls r0, r0, #0 + ... -0000805c <__t1_from_arm>: - 805c: e51ff004 ldr pc, \[pc, #-4\] ; 8060 <__t1_from_arm\+0x4> - 8060: 00008041 .word 0x00008041 - -00008064 <__t2_from_arm>: - 8064: e51ff004 ldr pc, \[pc, #-4\] ; 8068 <__t2_from_arm\+0x4> - 8068: 00008043 .word 0x00008043 +00008060 <__t1_from_arm>: + 8060: e51ff004 ldr pc, \[pc, #-4\] ; 8064 <__t1_from_arm\+0x4> + 8064: 00008041 .word 0x00008041 + +00008068 <__t2_from_arm>: + 8068: e51ff004 ldr pc, \[pc, #-4\] ; 806c <__t2_from_arm\+0x4> + 806c: 00008043 .word 0x00008043 Index: ld/testsuite/ld-arm/arm-pic-veneer.d =================================================================== RCS file: /cvs/src/src/ld/testsuite/ld-arm/arm-pic-veneer.d,v retrieving revision 1.2 diff -u -p -r1.2 arm-pic-veneer.d --- ld/testsuite/ld-arm/arm-pic-veneer.d 22 May 2007 17:17:53 -0000 1.2 +++ ld/testsuite/ld-arm/arm-pic-veneer.d 6 Mar 2009 15:24:36 -0000 @@ -12,6 +12,6 @@ Disassembly of section .text: 00008008 <__foo_from_arm>: 8008: e59fc004 ldr ip, \[pc, #4\] ; 8014 <__foo_from_arm\+0xc> - 800c: e08cc00f add ip, ip, pc + 800c: e08fc00c add ip, pc, ip 8010: e12fff1c bx ip 8014: fffffff1 .word 0xfffffff1 Index: ld/testsuite/ld-arm/thumb2-b-interwork.d =================================================================== RCS file: /cvs/src/src/ld/testsuite/ld-arm/thumb2-b-interwork.d,v retrieving revision 1.1 diff -u -p -r1.1 thumb2-b-interwork.d --- ld/testsuite/ld-arm/thumb2-b-interwork.d 8 Mar 2008 14:58:14 -0000 1.1 +++ ld/testsuite/ld-arm/thumb2-b-interwork.d 6 Mar 2009 15:24:36 -0000 @@ -8,12 +8,9 @@ Disassembly of section .text: 00008004 : 8004: e12fff1e bx lr -Disassembly of section .glue_7t: 00008008 <__bar_from_thumb>: 8008: 4778 bx pc 800a: 46c0 nop \(mov r8, r8\) - -0000800c <__bar_change_to_arm>: 800c: eafffffc b 8004