Advertisement
Guest User

elf32-arm.c

a guest
Apr 4th, 2013
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.29 KB | None | 0 0
  1. /* Determine the type of stub needed, if any, for a call.  */
  2.  
  3. static enum elf32_arm_stub_type
  4. arm_type_of_stub (struct bfd_link_info *info,
  5.           asection *input_sec,
  6.           const Elf_Internal_Rela *rel,
  7.           unsigned char st_type,
  8.           struct elf32_arm_link_hash_entry *hash,
  9.           bfd_vma destination,
  10.           asection *sym_sec,
  11.           bfd *input_bfd,
  12.           const char *name)
  13. {
  14.   bfd_vma location;
  15.   bfd_signed_vma branch_offset;
  16.   unsigned int r_type;
  17.   struct elf32_arm_link_hash_table * globals;
  18.   int thumb2;
  19.   int thumb_only;
  20.   enum elf32_arm_stub_type stub_type = arm_stub_none;
  21.   int use_plt = 0;
  22.  
  23.   /* We don't know the actual type of destination in case it is of
  24.      type STT_SECTION: give up.  */
  25.   if (st_type == STT_SECTION)
  26.     return stub_type;
  27.  
  28.   globals = elf32_arm_hash_table (info);
  29.  
  30.   thumb_only = using_thumb_only (globals);
  31.  
  32.   thumb2 = using_thumb2 (globals);
  33.  
  34.   /* Determine where the call point is.  */
  35.   location = (input_sec->output_offset
  36.           + input_sec->output_section->vma
  37.           + rel->r_offset);
  38.  
  39.   branch_offset = (bfd_signed_vma)(destination - location);
  40.  
  41.   r_type = ELF32_R_TYPE (rel->r_info);
  42.  
  43.   /* Keep a simpler condition, for the sake of clarity.  */
  44.   if (globals->splt != NULL && hash != NULL && hash->root.plt.offset != (bfd_vma) -1)
  45.     {
  46.       use_plt = 1;
  47.       /* Note when dealing with PLT entries: the main PLT stub is in
  48.      ARM mode, so if the branch is in Thumb mode, another
  49.      Thumb->ARM stub will be inserted later just before the ARM
  50.      PLT stub. We don't take this extra distance into account
  51.      here, because if a long branch stub is needed, we'll add a
  52.      Thumb->Arm one and branch directly to the ARM PLT entry
  53.      because it avoids spreading offset corrections in several
  54.      places.  */
  55.     }
  56.  
  57.   if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24)
  58.     {
  59.       /* Handle cases where:
  60.      - this call goes too far (different Thumb/Thumb2 max
  61.            distance)
  62.      - it's a Thumb->Arm call and blx is not available, or it's a
  63.            Thumb->Arm branch (not bl). A stub is needed in this case,
  64.            but only if this call is not through a PLT entry. Indeed,
  65.            PLT stubs handle mode switching already.
  66.       */
  67.       if ((!thumb2
  68.         && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET
  69.         || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET)))
  70.       || (thumb2
  71.           && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
  72.           || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
  73.       || ((st_type != STT_ARM_TFUNC)
  74.           && (((r_type == R_ARM_THM_CALL) && !globals->use_blx)
  75.           || (r_type == R_ARM_THM_JUMP24))
  76.           && !use_plt))
  77.     {
  78.       if (st_type == STT_ARM_TFUNC)
  79.         {
  80.           /* Thumb to thumb.  */
  81.           if (!thumb_only)
  82.         {
  83.           stub_type = (info->shared | globals->pic_veneer)
  84.             /* PIC stubs.  */
  85.             ? ((globals->use_blx
  86.             && (r_type ==R_ARM_THM_CALL))
  87.                /* V5T and above. Stub starts with ARM code, so
  88.               we must be able to switch mode before
  89.               reaching it, which is only possible for 'bl'
  90.               (ie R_ARM_THM_CALL relocation).  */
  91.                ? arm_stub_long_branch_any_thumb_pic
  92.                /* On V4T, use Thumb code only.  */
  93.                : arm_stub_long_branch_v4t_thumb_thumb_pic)
  94.  
  95.             /* non-PIC stubs.  */
  96.             : ((globals->use_blx
  97.             && (r_type ==R_ARM_THM_CALL))
  98.                /* V5T and above.  */
  99.                ? arm_stub_long_branch_any_any
  100.                /* V4T.  */
  101.                : arm_stub_long_branch_v4t_thumb_thumb);
  102.         }
  103.           else
  104.         {
  105.           stub_type = (info->shared | globals->pic_veneer)
  106.             /* PIC stub.  */
  107.             ? arm_stub_long_branch_thumb_only_pic
  108.             /* non-PIC stub.  */
  109.             : arm_stub_long_branch_thumb_only;
  110.         }
  111.         }
  112.       else
  113.         {
  114.           /* Thumb to arm.  */
  115.           if (sym_sec != NULL
  116.           && sym_sec->owner != NULL
  117.           && !INTERWORK_FLAG (sym_sec->owner))
  118.         {
  119.           (*_bfd_error_handler)
  120.             (_("%B(%s): warning: interworking not enabled.\n"
  121.                "  first occurrence: %B: Thumb call to ARM"),
  122.              sym_sec->owner, input_bfd, name);
  123.         }
  124.  
  125.           stub_type = (info->shared | globals->pic_veneer)
  126.         /* PIC stubs.  */
  127.         ? ((globals->use_blx
  128.             && (r_type ==R_ARM_THM_CALL))
  129.            /* V5T and above.  */
  130.            ? arm_stub_long_branch_any_arm_pic
  131.            /* V4T PIC stub.  */
  132.            : arm_stub_long_branch_v4t_thumb_arm_pic)
  133.  
  134.         /* non-PIC stubs.  */
  135.         : ((globals->use_blx
  136.             && (r_type ==R_ARM_THM_CALL))
  137.            /* V5T and above.  */
  138.            ? arm_stub_long_branch_any_any
  139.            /* V4T.  */
  140.            : arm_stub_long_branch_v4t_thumb_arm);
  141.  
  142.           /* Handle v4t short branches.  */
  143.           if ((stub_type == arm_stub_long_branch_v4t_thumb_arm)
  144.           && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET)
  145.           && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET))
  146.         stub_type = arm_stub_short_branch_v4t_thumb_arm;
  147.         }
  148.     }
  149.     }
  150.   else if (r_type == R_ARM_CALL || r_type == R_ARM_JUMP24 || r_type == R_ARM_PLT32)
  151.     {
  152.       if (st_type == STT_ARM_TFUNC)
  153.     {
  154.       /* Arm to thumb.  */
  155.  
  156.       if (sym_sec != NULL
  157.           && sym_sec->owner != NULL
  158.           && !INTERWORK_FLAG (sym_sec->owner))
  159.         {
  160.           (*_bfd_error_handler)
  161.         (_("%B(%s): warning: interworking not enabled.\n"
  162.            "  first occurrence: %B: ARM call to Thumb"),
  163.          sym_sec->owner, input_bfd, name);
  164.         }
  165.  
  166.       /* We have an extra 2-bytes reach because of
  167.          the mode change (bit 24 (H) of BLX encoding).  */
  168.       if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2)
  169.           || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)
  170.           || ((r_type == R_ARM_CALL) && !globals->use_blx)
  171.           || (r_type == R_ARM_JUMP24)
  172.           || (r_type == R_ARM_PLT32))
  173.         {
  174.           stub_type = (info->shared | globals->pic_veneer)
  175.         /* PIC stubs.  */
  176.         ? ((globals->use_blx)
  177.            /* V5T and above.  */
  178.            ? arm_stub_long_branch_any_thumb_pic
  179.            /* V4T stub.  */
  180.            : arm_stub_long_branch_v4t_arm_thumb_pic)
  181.  
  182.         /* non-PIC stubs.  */
  183.         : ((globals->use_blx)
  184.            /* V5T and above.  */
  185.            ? arm_stub_long_branch_any_any
  186.            /* V4T.  */
  187.            : arm_stub_long_branch_v4t_arm_thumb);
  188.         }
  189.     }
  190.       else
  191.     {
  192.       /* Arm to arm.  */
  193.       if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
  194.           || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET))
  195.         {
  196.           stub_type = (info->shared | globals->pic_veneer)
  197.         /* PIC stubs.  */
  198.         ? arm_stub_long_branch_any_arm_pic
  199.         /* non-PIC stubs.  */
  200.         : arm_stub_long_branch_any_any;
  201.         }
  202.     }
  203.     }
  204.  
  205.   return stub_type;
  206. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement