PR ld/15787
[binutils-gdb.git] / bfd / elf32-arm.c
index eef1b1361afcb40499f56ec9d682d6b08e13cf66..6d2d5534b14311f97e29d360a376a46320e1915d 100644 (file)
@@ -2415,6 +2415,33 @@ static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_tls_pic[] =
   DATA_WORD (0, R_ARM_REL32, -4),    /* dcd  R_ARM_REL32(X) */
 };
 
+/* NaCl ARM -> ARM long branch stub.  */
+static const insn_sequence elf32_arm_stub_long_branch_arm_nacl[] =
+{
+  ARM_INSN (0xe59fc00c),               /* ldr  ip, [pc, #12] */
+  ARM_INSN (0xe3ccc13f),               /* bic  ip, ip, #0xc000000f */
+  ARM_INSN (0xe12fff1c),                /* bx  ip */
+  ARM_INSN (0xe320f000),                /* nop */
+  ARM_INSN (0xe125be70),                /* bkpt        0x5be0 */
+  DATA_WORD (0, R_ARM_ABS32, 0),        /* dcd R_ARM_ABS32(X) */
+  DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
+  DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
+};
+
+/* NaCl ARM -> ARM long branch stub, PIC.  */
+static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] =
+{
+  ARM_INSN (0xe59fc00c),               /* ldr  ip, [pc, #12] */
+  ARM_INSN (0xe08cc00f),                /* add ip, ip, pc */
+  ARM_INSN (0xe3ccc13f),               /* bic  ip, ip, #0xc000000f */
+  ARM_INSN (0xe12fff1c),                /* bx  ip */
+  ARM_INSN (0xe125be70),                /* bkpt        0x5be0 */
+  DATA_WORD (0, R_ARM_REL32, 8),        /* dcd R_ARM_REL32(X+8) */
+  DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
+  DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
+};
+
+
 /* Cortex-A8 erratum-workaround stubs.  */
 
 /* Stub used for conditional branches (which may be beyond +/-1MB away, so we
@@ -2491,6 +2518,8 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_thumb_only_pic) \
   DEF_STUB(long_branch_any_tls_pic) \
   DEF_STUB(long_branch_v4t_thumb_tls_pic) \
+  DEF_STUB(long_branch_arm_nacl) \
+  DEF_STUB(long_branch_arm_nacl_pic) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -2983,7 +3012,7 @@ struct elf32_arm_link_hash_table
   bfd *stub_bfd;
 
   /* Linker call-backs.  */
-  asection * (*add_stub_section) (const char *, asection *);
+  asection * (*add_stub_section) (const char *, asection *, unsigned int);
   void (*layout_sections_again) (void);
 
   /* Array to keep track of which stub sections have been created, and
@@ -3580,6 +3609,12 @@ arm_type_of_stub (struct bfd_link_info *info,
 
   r_type = ELF32_R_TYPE (rel->r_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)
+      && branch_type == ST_BRANCH_TO_ARM)
+    branch_type = ST_BRANCH_TO_THUMB;
+
   /* For TLS call relocs, it is the caller's responsibility to provide
      the address of the appropriate trampoline.  */
   if (r_type != R_ARM_TLS_CALL
@@ -3772,9 +3807,13 @@ arm_type_of_stub (struct bfd_link_info *info,
                ? (r_type == R_ARM_TLS_CALL
                   /* TLS PIC Stub */
                   ? arm_stub_long_branch_any_tls_pic
-                  : arm_stub_long_branch_any_arm_pic)
+                  : (globals->nacl_p
+                     ? arm_stub_long_branch_arm_nacl_pic
+                     : arm_stub_long_branch_any_arm_pic))
                /* non-PIC stubs.  */
-               : arm_stub_long_branch_any_any;
+               : (globals->nacl_p
+                  ? arm_stub_long_branch_arm_nacl
+                  : arm_stub_long_branch_any_any);
            }
        }
     }
@@ -3910,7 +3949,8 @@ elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section,
 
          memcpy (s_name, link_sec->name, namelen);
          memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
-         stub_sec = (*htab->add_stub_section) (s_name, link_sec);
+         stub_sec = (*htab->add_stub_section) (s_name, link_sec,
+                                               htab->nacl_p ? 4 : 3);
          if (stub_sec == NULL)
            return NULL;
          htab->stub_group[link_sec->id].stub_sec = stub_sec;
@@ -4043,6 +4083,10 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
     case arm_stub_a8_veneer_blx:
       return 4;
 
+    case arm_stub_long_branch_arm_nacl:
+    case arm_stub_long_branch_arm_nacl_pic:
+      return 16;
+
     default:
       abort ();  /* Should be unreachable.  */
     }
@@ -4052,7 +4096,7 @@ static bfd_boolean
 arm_build_one_stub (struct bfd_hash_entry *gen_entry,
                    void * in_arg)
 {
-#define MAXRELOCS 2
+#define MAXRELOCS 3
   struct elf32_arm_stub_hash_entry *stub_entry;
   struct elf32_arm_link_hash_table *globals;
   struct bfd_link_info *info;
@@ -4864,7 +4908,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
                      bfd *stub_bfd,
                      struct bfd_link_info *info,
                      bfd_signed_vma group_size,
-                     asection * (*add_stub_section) (const char *, asection *),
+                     asection * (*add_stub_section) (const char *, asection *,
+                                                     unsigned int),
                      void (*layout_sections_again) (void))
 {
   bfd_size_type stub_group_size;
@@ -8084,6 +8129,14 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   else
     addend = signed_addend = rel->r_addend;
 
+  /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we
+     are resolving a function call relocation.  */
+  if (using_thumb_only (globals)
+      && (r_type == R_ARM_THM_CALL
+         || r_type == R_ARM_THM_JUMP24)
+      && branch_type == ST_BRANCH_TO_ARM)
+    branch_type = ST_BRANCH_TO_THUMB;
+
   /* Record the symbol information that should be used in dynamic
      relocations.  */
   dynreloc_st_type = st_type;
@@ -9799,10 +9852,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
        bfd_vma pc = input_section->output_section->vma
                     + input_section->output_offset + rel->r_offset;
-       /* sb should be the origin of the *segment* containing the symbol.
-          It is not clear how to obtain this OS-dependent value, so we
-          make an arbitrary choice of zero.  */
-       bfd_vma sb = 0;
+       /* sb is the origin of the *segment* containing the symbol.  */
+       bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0;
        bfd_vma residual;
        bfd_vma g_n;
        bfd_signed_vma signed_value;
@@ -9935,7 +9986,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
        bfd_vma pc = input_section->output_section->vma
                     + input_section->output_offset + rel->r_offset;
-       bfd_vma sb = 0; /* See note above.  */
+       /* sb is the origin of the *segment* containing the symbol.  */
+       bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0;
        bfd_vma residual;
        bfd_signed_vma signed_value;
        int group = 0;
@@ -10018,7 +10070,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
        bfd_vma pc = input_section->output_section->vma
                     + input_section->output_offset + rel->r_offset;
-       bfd_vma sb = 0; /* See note above.  */
+       /* sb is the origin of the *segment* containing the symbol.  */
+       bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0;
        bfd_vma residual;
        bfd_signed_vma signed_value;
        int group = 0;
@@ -10101,7 +10154,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
        bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
        bfd_vma pc = input_section->output_section->vma
                     + input_section->output_offset + rel->r_offset;
-       bfd_vma sb = 0; /* See note above.  */
+       /* sb is the origin of the *segment* containing the symbol.  */
+       bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0;
        bfd_vma residual;
        bfd_signed_vma signed_value;
        int group = 0;