diff options
Diffstat (limited to 'bfd/elf32-arm.c')
-rw-r--r-- | bfd/elf32-arm.c | 165 |
1 files changed, 89 insertions, 76 deletions
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index de063e6..b1129d8 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -2010,20 +2010,27 @@ static const bfd_vma elf32_arm_symbian_plt_entry [] = #define THM2_MAX_FWD_BRANCH_OFFSET (((1 << 24) - 2) + 4) #define THM2_MAX_BWD_BRANCH_OFFSET (-(1 << 24) + 4) -static const bfd_vma arm_long_branch_stub[] = +/* Arm/Thumb -> Arm/Thumb long branch stub. On V5T and above, use blx + to reach the stub if necessary. */ +static const bfd_vma elf32_arm_stub_long_branch_any_any[] = { 0xe51ff004, /* ldr pc, [pc, #-4] */ 0x00000000, /* dcd R_ARM_ABS32(X) */ }; -static const bfd_vma arm_thumb_v4t_long_branch_stub[] = +/* V4T Arm -> Thumb long branch stub. Used on V4T where blx is not + available. */ +static const bfd_vma elf32_arm_stub_long_branch_v4t_arm_thumb[] = { 0xe59fc000, /* ldr ip, [pc, #0] */ 0xe12fff1c, /* bx ip */ 0x00000000, /* dcd R_ARM_ABS32(X) */ }; -static const bfd_vma arm_thumb_thumb_long_branch_stub[] = +/* Thumb -> Thumb long branch stub. Used on architectures which + support only this mode, or on V4T where it is expensive to switch + to ARM. */ +static const bfd_vma elf32_arm_stub_long_branch_thumb_only[] = { 0x4e02b540, /* push {r6, lr} */ /* ldr r6, [pc, #8] */ @@ -2034,7 +2041,9 @@ static const bfd_vma arm_thumb_thumb_long_branch_stub[] = 0x00000000, /* dcd R_ARM_ABS32(X) */ }; -static const bfd_vma arm_thumb_arm_v4t_long_branch_stub[] = +/* V4T Thumb -> ARM long branch stub. Used on V4T where blx is not + available. */ +static const bfd_vma elf32_arm_stub_long_branch_v4t_thumb_arm[] = { 0x4e03b540, /* push {r6, lr} */ /* ldr r6, [pc, #12] */ @@ -2045,14 +2054,18 @@ static const bfd_vma arm_thumb_arm_v4t_long_branch_stub[] = 0x00000000, /* dcd R_ARM_ABS32(X) */ }; -static const bfd_vma arm_thumb_arm_v4t_short_branch_stub[] = +/* V4T Thumb -> ARM short branch stub. Shorter variant of the above + one, when the destination is close enough. */ +static const bfd_vma elf32_arm_stub_short_branch_v4t_thumb_arm[] = { 0x46c04778, /* bx pc */ /* nop */ 0xea000000, /* b (X) */ }; -static const bfd_vma arm_pic_long_branch_stub[] = +/* ARM/Thumb -> ARM/Thumb long branch stub, PIC. On V5T and above, use + blx to reach the stub if necessary. */ +static const bfd_vma elf32_arm_stub_long_branch_any_any_pic[] = { 0xe59fc000, /* ldr r12, [pc] */ 0xe08ff00c, /* add pc, pc, ip */ @@ -2066,12 +2079,12 @@ static const bfd_vma arm_pic_long_branch_stub[] = enum elf32_arm_stub_type { arm_stub_none, - arm_stub_long_branch, - arm_thumb_v4t_stub_long_branch, - arm_thumb_thumb_stub_long_branch, - arm_thumb_arm_v4t_stub_long_branch, - arm_thumb_arm_v4t_stub_short_branch, - arm_stub_pic_long_branch, + arm_stub_long_branch_any_any, + arm_stub_long_branch_v4t_arm_thumb, + arm_stub_long_branch_thumb_only, + arm_stub_long_branch_v4t_thumb_arm, + arm_stub_short_branch_v4t_thumb_arm, + arm_stub_long_branch_any_any_pic, }; struct elf32_arm_stub_hash_entry @@ -2731,9 +2744,9 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type) { switch (stub_type) { - case arm_thumb_thumb_stub_long_branch: - case arm_thumb_arm_v4t_stub_long_branch: - case arm_thumb_arm_v4t_stub_short_branch: + case arm_stub_long_branch_thumb_only: + case arm_stub_long_branch_v4t_thumb_arm: + case arm_stub_short_branch_v4t_thumb_arm: return TRUE; case arm_stub_none: BFD_FAIL (); @@ -2807,10 +2820,10 @@ arm_type_of_stub (struct bfd_link_info *info, { stub_type = (info->shared | globals->pic_veneer) ? ((globals->use_blx) - ? arm_stub_pic_long_branch + ? arm_stub_long_branch_any_any_pic : arm_stub_none) : (globals->use_blx) - ? arm_stub_long_branch + ? arm_stub_long_branch_any_any : arm_stub_none; } else @@ -2818,7 +2831,7 @@ arm_type_of_stub (struct bfd_link_info *info, stub_type = (info->shared | globals->pic_veneer) ? arm_stub_none : (globals->use_blx) - ? arm_thumb_thumb_stub_long_branch + ? arm_stub_long_branch_thumb_only : arm_stub_none; } } @@ -2837,17 +2850,17 @@ arm_type_of_stub (struct bfd_link_info *info, stub_type = (info->shared | globals->pic_veneer) ? ((globals->use_blx) - ? arm_stub_pic_long_branch + ? arm_stub_long_branch_any_any_pic : arm_stub_none) : (globals->use_blx) - ? arm_stub_long_branch - : arm_thumb_arm_v4t_stub_long_branch; + ? arm_stub_long_branch_any_any + : arm_stub_long_branch_v4t_thumb_arm; /* Handle v4t short branches. */ - if ((stub_type == arm_thumb_arm_v4t_stub_long_branch) + if ((stub_type == arm_stub_long_branch_v4t_thumb_arm) && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET) && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET)) - stub_type = arm_thumb_arm_v4t_stub_short_branch; + stub_type = arm_stub_short_branch_v4t_thumb_arm; } } } @@ -2874,10 +2887,10 @@ arm_type_of_stub (struct bfd_link_info *info, || !globals->use_blx) { stub_type = (info->shared | globals->pic_veneer) - ? arm_stub_pic_long_branch + ? arm_stub_long_branch_any_any_pic : (globals->use_blx) - ? arm_stub_long_branch - : arm_thumb_v4t_stub_long_branch; + ? arm_stub_long_branch_any_any + : arm_stub_long_branch_v4t_arm_thumb; } } else @@ -2887,8 +2900,8 @@ arm_type_of_stub (struct bfd_link_info *info, || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)) { stub_type = (info->shared | globals->pic_veneer) - ? arm_stub_pic_long_branch - : arm_stub_long_branch; + ? arm_stub_long_branch_any_any_pic + : arm_stub_long_branch_any_any; } } } @@ -3108,29 +3121,29 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, switch (stub_entry->stub_type) { - case arm_stub_long_branch: - template = arm_long_branch_stub; - template_size = (sizeof (arm_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_any_any: + template = elf32_arm_stub_long_branch_any_any; + template_size = (sizeof (elf32_arm_stub_long_branch_any_any) / sizeof (bfd_vma)) * 4; break; - case arm_thumb_v4t_stub_long_branch: - template = arm_thumb_v4t_long_branch_stub; - template_size = (sizeof (arm_thumb_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_v4t_arm_thumb: + template = elf32_arm_stub_long_branch_v4t_arm_thumb; + template_size = (sizeof (elf32_arm_stub_long_branch_v4t_arm_thumb) / sizeof (bfd_vma)) * 4; break; - case arm_thumb_thumb_stub_long_branch: - template = arm_thumb_thumb_long_branch_stub; - template_size = (sizeof (arm_thumb_thumb_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_thumb_only: + template = elf32_arm_stub_long_branch_thumb_only; + template_size = (sizeof (elf32_arm_stub_long_branch_thumb_only) / sizeof (bfd_vma)) * 4; break; - case arm_thumb_arm_v4t_stub_long_branch: - template = arm_thumb_arm_v4t_long_branch_stub; - template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_v4t_thumb_arm: + template = elf32_arm_stub_long_branch_v4t_thumb_arm; + template_size = (sizeof (elf32_arm_stub_long_branch_v4t_thumb_arm) / sizeof (bfd_vma)) * 4; break; - case arm_thumb_arm_v4t_stub_short_branch: - template = arm_thumb_arm_v4t_short_branch_stub; - template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_short_branch_v4t_thumb_arm: + template = elf32_arm_stub_short_branch_v4t_thumb_arm; + template_size = (sizeof(elf32_arm_stub_short_branch_v4t_thumb_arm) / sizeof (bfd_vma)) * 4; break; - case arm_stub_pic_long_branch: - template = arm_pic_long_branch_stub; - template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_any_any_pic: + template = elf32_arm_stub_long_branch_any_any_pic; + template_size = (sizeof (elf32_arm_stub_long_branch_any_any_pic) / sizeof (bfd_vma)) * 4; break; default: BFD_FAIL (); @@ -3157,27 +3170,27 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, switch (stub_entry->stub_type) { - case arm_stub_long_branch: + case arm_stub_long_branch_any_any: _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32), stub_bfd, stub_sec, stub_sec->contents, stub_entry->stub_offset + 4, sym_value, 0); break; - case arm_thumb_v4t_stub_long_branch: + case arm_stub_long_branch_v4t_arm_thumb: _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32), stub_bfd, stub_sec, stub_sec->contents, stub_entry->stub_offset + 8, sym_value, 0); break; - case arm_thumb_thumb_stub_long_branch: + case arm_stub_long_branch_thumb_only: _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32), stub_bfd, stub_sec, stub_sec->contents, stub_entry->stub_offset + 12, sym_value, 0); break; - case arm_thumb_arm_v4t_stub_long_branch: + case arm_stub_long_branch_v4t_thumb_arm: _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_ABS32), stub_bfd, stub_sec, stub_sec->contents, stub_entry->stub_offset + 16, sym_value, 0); break; - case arm_thumb_arm_v4t_stub_short_branch: + case arm_stub_short_branch_v4t_thumb_arm: { long int rel_offset; static const insn32 t2a3_b_insn = 0xea000000; @@ -3190,7 +3203,7 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, } break; - case arm_stub_pic_long_branch: + case arm_stub_long_branch_any_any_pic: /* We want the value relative to the address 8 bytes from the start of the stub. */ _bfd_final_link_relocate (elf32_arm_howto_from_type (R_ARM_REL32), @@ -3224,29 +3237,29 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry, switch (stub_entry->stub_type) { - case arm_stub_long_branch: - template = arm_long_branch_stub; - template_size = (sizeof (arm_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_any_any: + template = elf32_arm_stub_long_branch_any_any; + template_size = (sizeof (elf32_arm_stub_long_branch_any_any) / sizeof (bfd_vma)) * 4; break; - case arm_thumb_v4t_stub_long_branch: - template = arm_thumb_v4t_long_branch_stub; - template_size = (sizeof (arm_thumb_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_v4t_arm_thumb: + template = elf32_arm_stub_long_branch_v4t_arm_thumb; + template_size = (sizeof (elf32_arm_stub_long_branch_v4t_arm_thumb) / sizeof (bfd_vma)) * 4; break; - case arm_thumb_thumb_stub_long_branch: - template = arm_thumb_thumb_long_branch_stub; - template_size = (sizeof (arm_thumb_thumb_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_thumb_only: + template = elf32_arm_stub_long_branch_thumb_only; + template_size = (sizeof (elf32_arm_stub_long_branch_thumb_only) / sizeof (bfd_vma)) * 4; break; - case arm_thumb_arm_v4t_stub_long_branch: - template = arm_thumb_arm_v4t_long_branch_stub; - template_size = (sizeof (arm_thumb_arm_v4t_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_v4t_thumb_arm: + template = elf32_arm_stub_long_branch_v4t_thumb_arm; + template_size = (sizeof (elf32_arm_stub_long_branch_v4t_thumb_arm) / sizeof (bfd_vma)) * 4; break; - case arm_thumb_arm_v4t_stub_short_branch: - template = arm_thumb_arm_v4t_short_branch_stub; - template_size = (sizeof(arm_thumb_arm_v4t_short_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_short_branch_v4t_thumb_arm: + template = elf32_arm_stub_short_branch_v4t_thumb_arm; + template_size = (sizeof(elf32_arm_stub_short_branch_v4t_thumb_arm) / sizeof (bfd_vma)) * 4; break; - case arm_stub_pic_long_branch: - template = arm_pic_long_branch_stub; - template_size = (sizeof (arm_pic_long_branch_stub) / sizeof (bfd_vma)) * 4; + case arm_stub_long_branch_any_any_pic: + template = elf32_arm_stub_long_branch_any_any_pic; + template_size = (sizeof (elf32_arm_stub_long_branch_any_any_pic) / sizeof (bfd_vma)) * 4; break; default: BFD_FAIL (); @@ -11654,7 +11667,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, switch (stub_entry->stub_type) { - case arm_stub_long_branch: + case arm_stub_long_branch_any_any: if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 8)) return FALSE; if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) @@ -11662,7 +11675,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 4)) return FALSE; break; - case arm_thumb_v4t_stub_long_branch: + case arm_stub_long_branch_v4t_arm_thumb: if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 12)) return FALSE; if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) @@ -11670,7 +11683,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 8)) return FALSE; break; - case arm_thumb_thumb_stub_long_branch: + case arm_stub_long_branch_thumb_only: if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, 16)) return FALSE; if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr)) @@ -11678,7 +11691,7 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 12)) return FALSE; break; - case arm_thumb_arm_v4t_stub_long_branch: + case arm_stub_long_branch_v4t_thumb_arm: if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, 20)) return FALSE; if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr)) @@ -11688,13 +11701,13 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry, if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 16)) return FALSE; break; - case arm_thumb_arm_v4t_stub_short_branch: + case arm_stub_short_branch_v4t_thumb_arm: if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, 8)) return FALSE; if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 4)) return FALSE; break; - case arm_stub_pic_long_branch: + case arm_stub_long_branch_any_any_pic: if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 12)) return FALSE; if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) |