Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Determine the type of stub needed, if any, for a call. */
- static enum elf32_arm_stub_type
- arm_type_of_stub (struct bfd_link_info *info,
- asection *input_sec,
- const Elf_Internal_Rela *rel,
- unsigned char st_type,
- struct elf32_arm_link_hash_entry *hash,
- bfd_vma destination,
- asection *sym_sec,
- bfd *input_bfd,
- const char *name)
- {
- bfd_vma location;
- bfd_signed_vma branch_offset;
- unsigned int r_type;
- struct elf32_arm_link_hash_table * globals;
- 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. */
- if (st_type == STT_SECTION)
- return stub_type;
- globals = elf32_arm_hash_table (info);
- thumb_only = using_thumb_only (globals);
- thumb2 = using_thumb2 (globals);
- /* Determine where the call point is. */
- location = (input_sec->output_offset
- + input_sec->output_section->vma
- + rel->r_offset);
- branch_offset = (bfd_signed_vma)(destination - location);
- r_type = ELF32_R_TYPE (rel->r_info);
- /* Keep a simpler condition, for the sake of clarity. */
- if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1)
- {
- 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 || 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, 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
- || (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)
- && (((r_type == R_ARM_THM_CALL) && !globals->use_blx)
- || (r_type == R_ARM_THM_JUMP24))
- && !use_plt))
- {
- if (st_type == STT_ARM_TFUNC)
- {
- /* Thumb to thumb. */
- if (!thumb_only)
- {
- stub_type = (info->shared | globals->pic_veneer)
- /* PIC stubs. */
- ? ((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_v4t_thumb_thumb_pic)
- /* non-PIC stubs. */
- : ((globals->use_blx
- && (r_type ==R_ARM_THM_CALL))
- /* V5T and above. */
- ? arm_stub_long_branch_any_any
- /* V4T. */
- : arm_stub_long_branch_v4t_thumb_thumb);
- }
- else
- {
- stub_type = (info->shared | globals->pic_veneer)
- /* PIC stub. */
- ? arm_stub_long_branch_thumb_only_pic
- /* non-PIC stub. */
- : arm_stub_long_branch_thumb_only;
- }
- }
- else
- {
- /* Thumb to arm. */
- if (sym_sec != NULL
- && sym_sec->owner != NULL
- && !INTERWORK_FLAG (sym_sec->owner))
- {
- (*_bfd_error_handler)
- (_("%B(%s): warning: interworking not enabled.\n"
- " first occurrence: %B: Thumb call to ARM"),
- sym_sec->owner, input_bfd, name);
- }
- stub_type = (info->shared | globals->pic_veneer)
- /* PIC stubs. */
- ? ((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
- && (r_type ==R_ARM_THM_CALL))
- /* V5T and above. */
- ? arm_stub_long_branch_any_any
- /* V4T. */
- : arm_stub_long_branch_v4t_thumb_arm);
- /* Handle v4t short branches. */
- 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_stub_short_branch_v4t_thumb_arm;
- }
- }
- }
- else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32)
- {
- if (st_type == STT_ARM_TFUNC)
- {
- /* Arm to thumb. */
- if (sym_sec != NULL
- && sym_sec->owner != NULL
- && !INTERWORK_FLAG (sym_sec->owner))
- {
- (*_bfd_error_handler)
- (_("%B(%s): warning: interworking not enabled.\n"
- " first occurrence: %B: ARM call to Thumb"),
- sym_sec->owner, input_bfd, name);
- }
- /* We have an extra 2-bytes reach because of
- 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)
- || ((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. */
- ? ((globals->use_blx)
- /* V5T and above. */
- ? arm_stub_long_branch_any_thumb_pic
- /* V4T stub. */
- : arm_stub_long_branch_v4t_arm_thumb_pic)
- /* non-PIC stubs. */
- : ((globals->use_blx)
- /* V5T and above. */
- ? arm_stub_long_branch_any_any
- /* V4T. */
- : arm_stub_long_branch_v4t_arm_thumb);
- }
- }
- else
- {
- /* Arm to arm. */
- if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
- || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET))
- {
- stub_type = (info->shared | globals->pic_veneer)
- /* PIC stubs. */
- ? arm_stub_long_branch_any_arm_pic
- /* non-PIC stubs. */
- : arm_stub_long_branch_any_any;
- }
- }
- }
- return stub_type;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement