* elf-hppa.h (elf_hppa_final_link): Use elf_hppa_final_link.
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index ece1a56ccfcb300a175e9f9bc3b9282da1c5df1d..2527e5e8425714d8dd1d96aa6242c08f64b020cd 100644 (file)
@@ -2010,53 +2010,130 @@ 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[] =
+enum stub_insn_type
   {
-    0xe51ff004,         /* ldr   pc, [pc, #-4] */
-    0x00000000,         /* dcd   R_ARM_ABS32(X) */
+    THUMB16_TYPE = 1,
+    THUMB32_TYPE,
+    ARM_TYPE,
+    DATA_TYPE
+  };
+
+#define THUMB16_INSN(X)    {(X), THUMB16_TYPE, R_ARM_NONE, 0}
+#define THUMB32_INSN(X)    {(X), THUMB32_TYPE, R_ARM_NONE, 0}
+#define ARM_INSN(X)        {(X), ARM_TYPE, R_ARM_NONE, 0}
+#define ARM_REL_INSN(X, Z) {(X), ARM_TYPE, R_ARM_JUMP24, (Z)}
+#define DATA_WORD(X,Y,Z)   {(X), DATA_TYPE, (Y), (Z)}
+
+typedef struct
+{
+  bfd_vma data;
+  enum stub_insn_type type;
+  unsigned int r_type;
+  int reloc_addend;
+}  insn_sequence;
+
+/* Arm/Thumb -> Arm/Thumb long branch stub. On V5T and above, use blx
+   to reach the stub if necessary.  */
+static const insn_sequence elf32_arm_stub_long_branch_any_any[] =
+  {
+    ARM_INSN(0xe51ff004),            /* ldr   pc, [pc, #-4] */
+    DATA_WORD(0, R_ARM_ABS32, 0),    /* dcd   R_ARM_ABS32(X) */
+  };
+
+/* V4T Arm -> Thumb long branch stub. Used on V4T where blx is not
+   available.  */
+static const insn_sequence elf32_arm_stub_long_branch_v4t_arm_thumb[] =
+  {
+    ARM_INSN(0xe59fc000),            /* ldr   ip, [pc, #0] */
+    ARM_INSN(0xe12fff1c),            /* bx    ip */
+    DATA_WORD(0, R_ARM_ABS32, 0),    /* dcd   R_ARM_ABS32(X) */
+  };
+
+/* 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 insn_sequence elf32_arm_stub_long_branch_thumb_only[] =
+  {
+    THUMB16_INSN(0xb401),             /* push {r0} */
+    THUMB16_INSN(0x4802),             /* ldr  r0, [pc, #8] */
+    THUMB16_INSN(0x4684),             /* mov  ip, r0 */
+    THUMB16_INSN(0xbc01),             /* pop  {r0} */
+    THUMB16_INSN(0x4760),             /* bx   ip */
+    THUMB16_INSN(0xbf00),             /* nop */
+    DATA_WORD(0, R_ARM_ABS32, 0),     /* dcd  R_ARM_ABS32(X) */
   };
 
-static const bfd_vma arm_thumb_v4t_long_branch_stub[] =
+/* V4T Thumb -> ARM long branch stub. Used on V4T where blx is not
+   available.  */
+static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_arm[] =
   {
-    0xe59fc000,         /* ldr   ip, [pc, #0] */
-    0xe12fff1c,         /* bx    ip */
-    0x00000000,         /* dcd   R_ARM_ABS32(X) */
+    THUMB16_INSN(0x4778),             /* bx   pc */
+    THUMB16_INSN(0x46c0),             /* nop   */
+    ARM_INSN(0xe51ff004),             /* ldr   pc, [pc, #-4] */
+    DATA_WORD(0, R_ARM_ABS32, 0),     /* dcd   R_ARM_ABS32(X) */
   };
 
-static const bfd_vma arm_thumb_thumb_long_branch_stub[] =
+/* V4T Thumb -> ARM short branch stub. Shorter variant of the above
+   one, when the destination is close enough.  */
+static const insn_sequence elf32_arm_stub_short_branch_v4t_thumb_arm[] =
   {
-    0x4e02b540,         /* push {r6, lr} */
-                        /* ldr  r6, [pc, #8] */
-    0x473046fe,         /* mov  lr, pc */
-                        /* bx   r6 */
-    0xbf00bd40,         /* pop  {r6, pc} */
-                        /* nop */
-    0x00000000,         /* dcd  R_ARM_ABS32(X) */
+    THUMB16_INSN(0x4778),             /* bx   pc */
+    THUMB16_INSN(0x46c0),             /* nop   */
+    ARM_REL_INSN(0xea000000, -8),     /* b    (X-8) */
   };
 
-static const bfd_vma arm_thumb_arm_v4t_long_branch_stub[] =
+/* ARM/Thumb -> ARM long branch stub, PIC.  On V5T and above, use
+   blx to reach the stub if necessary.  */
+static const insn_sequence elf32_arm_stub_long_branch_any_arm_pic[] =
   {
-    0x4e03b540,         /* push {r6, lr} */
-                        /* ldr  r6, [pc, #12] */
-    0x473046fe,         /* mov  lr, pc */
-                        /* bx   r6 */
-    0xe8bd4040,         /* pop  {r6, pc} */
-    0xe12fff1e,         /* bx   lr */
-    0x00000000,         /* dcd  R_ARM_ABS32(X) */
+    ARM_INSN(0xe59fc000),             /* ldr   r12, [pc] */
+    ARM_INSN(0xe08ff00c),             /* add   pc, pc, ip */
+    DATA_WORD(0, R_ARM_REL32, -4),    /* dcd   R_ARM_REL32(X-4) */
   };
 
-static const bfd_vma arm_thumb_arm_v4t_short_branch_stub[] =
+/* ARM/Thumb -> Thumb long branch stub, PIC.  On V5T and above, use
+   blx to reach the stub if necessary.  We can not add into pc;
+   it is not guaranteed to mode switch (different in ARMv6 and
+   ARMv7).  */
+static const insn_sequence elf32_arm_stub_long_branch_any_thumb_pic[] =
   {
-    0x46c04778,         /* bx   pc */
-                        /* nop   */
-    0xea000000,         /* b    (X) */
+    ARM_INSN(0xe59fc004),             /* ldr   r12, [pc, #4] */
+    ARM_INSN(0xe08fc00c),             /* add   ip, pc, ip */
+    ARM_INSN(0xe12fff1c),             /* bx    ip */
+    DATA_WORD(0, R_ARM_REL32, 0),     /* dcd   R_ARM_REL32(X) */
   };
 
-static const bfd_vma arm_pic_long_branch_stub[] =
+/* V4T ARM -> ARM long branch stub, PIC.  */
+static const insn_sequence elf32_arm_stub_long_branch_v4t_arm_thumb_pic[] =
   {
-    0xe59fc000,         /* ldr   r12, [pc] */
-    0xe08ff00c,         /* add   pc, pc, ip */
-    0x00000000,         /* dcd   R_ARM_REL32(X) */
+    ARM_INSN(0xe59fc004),             /* ldr   ip, [pc, #4] */
+    ARM_INSN(0xe08fc00c),             /* add   ip, pc, ip */
+    ARM_INSN(0xe12fff1c),             /* bx    ip */
+    DATA_WORD(0, R_ARM_REL32, 0),     /* dcd   R_ARM_REL32(X) */
+  };
+
+/* V4T Thumb -> ARM long branch stub, PIC.  */
+static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_arm_pic[] =
+  {
+    THUMB16_INSN(0x4778),             /* bx   pc */
+    THUMB16_INSN(0x46c0),             /* nop  */
+    ARM_INSN(0xe59fc000),             /* ldr  ip, [pc, #0] */
+    ARM_INSN(0xe08cf00f),             /* add  pc, ip, pc */
+    DATA_WORD(0, R_ARM_REL32, -4),     /* dcd  R_ARM_REL32(X) */
+  };
+
+/* Thumb -> Thumb long branch stub, PIC. Used on architectures which
+   support only this mode, or on V4T where it is expensive to switch
+   to ARM.  */
+static const insn_sequence elf32_arm_stub_long_branch_thumb_only_pic[] =
+  {
+    THUMB16_INSN(0xb401),             /* push {r0} */
+    THUMB16_INSN(0x4802),             /* ldr  r0, [pc, #8] */
+    THUMB16_INSN(0x46fc),             /* mov  ip, pc */
+    THUMB16_INSN(0x4484),             /* add  ip, r0 */
+    THUMB16_INSN(0xbc01),             /* pop  {r0} */
+    THUMB16_INSN(0x4760),             /* bx   ip */
+    DATA_WORD(0, R_ARM_REL32, 4),     /* dcd  R_ARM_REL32(X) */
   };
 
 /* Section name for stubs is the associated section name plus this
@@ -2066,12 +2143,16 @@ 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_arm_pic,
+  arm_stub_long_branch_any_thumb_pic,
+  arm_stub_long_branch_v4t_arm_thumb_pic,
+  arm_stub_long_branch_v4t_thumb_arm_pic,
+  arm_stub_long_branch_thumb_only_pic,
 };
 
 struct elf32_arm_stub_hash_entry
@@ -2090,7 +2171,14 @@ struct elf32_arm_stub_hash_entry
   bfd_vma target_value;
   asection *target_section;
 
+  /* The stub type.  */
   enum elf32_arm_stub_type stub_type;
+  /* Its encoding size in bytes.  */
+  int stub_size;
+  /* Its template.  */
+  const insn_sequence *stub_template;
+  /* The size of the template (number of entries).  */
+  int stub_template_size;
 
   /* The symbol table entry, if any, that this was derived from.  */
   struct elf32_arm_link_hash_entry *h;
@@ -2459,6 +2547,9 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
       eh->target_value = 0;
       eh->target_section = NULL;
       eh->stub_type = arm_stub_none;
+      eh->stub_size = 0;
+      eh->stub_template = NULL;
+      eh->stub_template_size = 0;
       eh->h = NULL;
       eh->id_sec = NULL;
     }
@@ -2731,9 +2822,11 @@ 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:
+    case arm_stub_long_branch_v4t_thumb_arm_pic:
+    case arm_stub_long_branch_thumb_only_pic:
       return TRUE;
     case arm_stub_none:
       BFD_FAIL ();
@@ -2806,20 +2899,27 @@ arm_type_of_stub (struct bfd_link_info *info,
              if (!thumb_only)
                {
                  stub_type = (info->shared | globals->pic_veneer)
+                   /* PIC stubs.  */
                    ? ((globals->use_blx)
-                      ? arm_stub_pic_long_branch
-                      : arm_stub_none)
-                   : (globals->use_blx)
-                   ? arm_stub_long_branch
-                   : arm_stub_none;
+                      /* V5T and above.  */
+                      ? 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)
+                      /* V5T and above.  */
+                      ? arm_stub_long_branch_any_any
+                      /* V4T.  */
+                      : arm_stub_long_branch_thumb_only);
                }
              else
                {
                  stub_type = (info->shared | globals->pic_veneer)
-                   ? arm_stub_none
-                   : (globals->use_blx)
-                   ? arm_thumb_thumb_stub_long_branch
-                   : arm_stub_none;
+                   /* PIC stub.  */
+                   ? arm_stub_long_branch_thumb_only_pic
+                   /* non-PIC stub.  */
+                   : arm_stub_long_branch_thumb_only;
                }
            }
          else
@@ -2836,18 +2936,25 @@ arm_type_of_stub (struct bfd_link_info *info,
                }
 
              stub_type = (info->shared | globals->pic_veneer)
+               /* PIC stubs.  */
                ? ((globals->use_blx)
-                  ? arm_stub_pic_long_branch
-                  : arm_stub_none)
-               : (globals->use_blx)
-               ? arm_stub_long_branch
-               : arm_thumb_arm_v4t_stub_long_branch;
+                  /* 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)
+                  /* 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_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;
            }
        }
     }
@@ -2863,7 +2970,7 @@ arm_type_of_stub (struct bfd_link_info *info,
            {
              (*_bfd_error_handler)
                (_("%B(%s): warning: interworking not enabled.\n"
-                  "  first occurrence: %B: Thumb call to ARM"),
+                  "  first occurrence: %B: ARM call to Thumb"),
                 sym_sec->owner, input_bfd, name);
            }
 
@@ -2874,10 +2981,19 @@ arm_type_of_stub (struct bfd_link_info *info,
              || !globals->use_blx)
            {
              stub_type = (info->shared | globals->pic_veneer)
-               ? arm_stub_pic_long_branch
-               : (globals->use_blx)
-               ? arm_stub_long_branch
-               : arm_thumb_v4t_stub_long_branch;
+               /* 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
@@ -2887,8 +3003,10 @@ 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;
+               /* PIC stubs.  */
+               ? arm_stub_long_branch_any_arm_pic
+               /* non-PIC stubs.  */
+               : arm_stub_long_branch_any_any;
            }
        }
     }
@@ -3078,9 +3196,11 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
   bfd_vma sym_value;
   int template_size;
   int size;
-  const bfd_vma *template;
+  const insn_sequence *template;
   int i;
   struct elf32_arm_link_hash_table * globals;
+  int stub_reloc_idx = -1;
+  int stub_reloc_offset = 0;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
@@ -3106,100 +3226,61 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry,
               + stub_entry->target_section->output_offset
               + stub_entry->target_section->output_section->vma);
 
-  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;
-      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;
-      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;
-      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;
-      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;
-      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;
-      break;
-    default:
-      BFD_FAIL ();
-      return FALSE;
-    }
+  template = stub_entry->stub_template;
+  template_size = stub_entry->stub_template_size;
 
   size = 0;
-  for (i = 0; i < (template_size / 4); i++)
+  for (i = 0; i < template_size; i++)
     {
-      /* A 0 pattern is a placeholder, every other pattern is an
-        instruction.  */
-      if (template[i] != 0)
-       put_arm_insn (globals, stub_bfd, template[i], loc + size);
-      else
-       bfd_put_32 (stub_bfd, template[i], loc + size);
+      switch (template[i].type)
+       {
+       case THUMB16_TYPE:
+         put_thumb_insn (globals, stub_bfd, template[i].data, loc + size);
+         size += 2;
+         break;
+
+       case ARM_TYPE:
+         put_arm_insn (globals, stub_bfd, template[i].data, loc + size);
+         /* Handle cases where the target is encoded within the
+            instruction.  */
+         if (template[i].r_type == R_ARM_JUMP24)
+           {
+             stub_reloc_idx = i;
+             stub_reloc_offset = size;
+           }
+         size += 4;
+         break;
 
-      size += 4;
+       case DATA_TYPE:
+         bfd_put_32 (stub_bfd, template[i].data, loc + size);
+         stub_reloc_idx = i;
+         stub_reloc_offset = size;
+         size += 4;
+         break;
+
+       default:
+         BFD_FAIL ();
+         return FALSE;
+       }
     }
+
   stub_sec->size += size;
 
+  /* Stub size has already been computed in arm_size_one_stub. Check
+     consistency.  */
+  BFD_ASSERT (size == stub_entry->stub_size);
+
   /* Destination is Thumb. Force bit 0 to 1 to reflect this.  */
   if (stub_entry->st_type == STT_ARM_TFUNC)
     sym_value |= 1;
 
-  switch (stub_entry->stub_type)
-    {
-    case arm_stub_long_branch:
-      _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:
-      _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:
-      _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:
-      _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:
-      {
-       long int rel_offset;
-       static const insn32 t2a3_b_insn = 0xea000000;
-
-       rel_offset = sym_value - (stub_addr + 8 + 4);
+  /* Assume there is one and only one entry to relocate in each stub.  */
+  BFD_ASSERT (stub_reloc_idx != -1);
 
-       put_arm_insn (globals, stub_bfd,
-                     (bfd_vma) t2a3_b_insn | ((rel_offset >> 2) & 0x00FFFFFF),
-                     loc + 4);
-      }
-      break;
-
-    case arm_stub_pic_long_branch:
-      /* 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),
-                               stub_bfd, stub_sec, stub_sec->contents,
-                               stub_entry->stub_offset + 8, sym_value, 0);
-      break;
-    default:
-      break;
-    }
+  _bfd_final_link_relocate (elf32_arm_howto_from_type (template[stub_reloc_idx].r_type),
+                           stub_bfd, stub_sec, stub_sec->contents,
+                           stub_entry->stub_offset + stub_reloc_offset,
+                           sym_value, template[stub_reloc_idx].reloc_addend);
 
   return TRUE;
 }
@@ -3213,7 +3294,7 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry,
 {
   struct elf32_arm_stub_hash_entry *stub_entry;
   struct elf32_arm_link_hash_table *htab;
-  const bfd_vma *template;
+  const insn_sequence *template;
   int template_size;
   int size;
   int i;
@@ -3224,41 +3305,81 @@ 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 = ARRAY_SIZE (elf32_arm_stub_long_branch_any_any);
+      break;
+    case arm_stub_long_branch_v4t_arm_thumb:
+      template =  elf32_arm_stub_long_branch_v4t_arm_thumb;
+      template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_v4t_arm_thumb);
       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_thumb_only:
+      template =  elf32_arm_stub_long_branch_thumb_only;
+      template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_thumb_only);
       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_v4t_thumb_arm:
+      template =  elf32_arm_stub_long_branch_v4t_thumb_arm;
+      template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_v4t_thumb_arm);
       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_short_branch_v4t_thumb_arm:
+      template =  elf32_arm_stub_short_branch_v4t_thumb_arm;
+      template_size = ARRAY_SIZE (elf32_arm_stub_short_branch_v4t_thumb_arm);
       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_long_branch_any_arm_pic:
+      template = elf32_arm_stub_long_branch_any_arm_pic;
+      template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_any_arm_pic);
       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_thumb_pic:
+      template = elf32_arm_stub_long_branch_any_thumb_pic;
+      template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_any_thumb_pic);
+      break;
+    case arm_stub_long_branch_v4t_arm_thumb_pic:
+      template = elf32_arm_stub_long_branch_v4t_arm_thumb_pic;
+      template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_v4t_arm_thumb_pic);
+      break;
+    case arm_stub_long_branch_v4t_thumb_arm_pic:
+      template = elf32_arm_stub_long_branch_v4t_thumb_arm_pic;
+      template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_v4t_thumb_arm_pic);
+      break;
+    case arm_stub_long_branch_thumb_only_pic:
+      template = elf32_arm_stub_long_branch_thumb_only_pic;
+      template_size = ARRAY_SIZE (elf32_arm_stub_long_branch_thumb_only_pic);
       break;
     default:
       BFD_FAIL ();
       return FALSE;
-      break;
     }
 
   size = 0;
-  for (i = 0; i < (template_size / 4); i++)
-      size += 4;
+  for (i = 0; i < template_size; i++)
+    {
+      switch (template[i].type)
+       {
+       case THUMB16_TYPE:
+         size += 2;
+         break;
+
+       case ARM_TYPE:
+         size += 4;
+         break;
+
+       case DATA_TYPE:
+         size += 4;
+         break;
+
+       default:
+         BFD_FAIL ();
+         return FALSE;
+       }
+    }
+
+  stub_entry->stub_size = size;
+  stub_entry->stub_template = template;
+  stub_entry->stub_template_size = template_size;
+
   size = (size + 7) & ~7;
   stub_entry->stub_sec->size += size;
+
   return TRUE;
 }
 
@@ -3360,7 +3481,7 @@ elf32_arm_next_input_section (struct bfd_link_info *info,
          /* Steal the link_sec pointer for our list.  */
 #define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
          /* This happens to make the list in reverse order,
-            which is what we want.  */
+            which we reverse later.  */
          PREV_SEC (isec) = *list;
          *list = isec;
        }
@@ -3369,7 +3490,7 @@ elf32_arm_next_input_section (struct bfd_link_info *info,
 
 /* See whether we can group stub sections together.  Grouping stub
    sections may result in fewer stubs.  More importantly, we need to
-   put all .init* and .fini* stubs at the beginning of the .init or
+   put all .init* and .fini* stubs at the end of the .init or
    .fini output sections respectively, because glibc splits the
    _init and _fini functions into multiple parts.  Putting a stub in
    the middle of a function is not a good idea.  */
@@ -3377,66 +3498,86 @@ elf32_arm_next_input_section (struct bfd_link_info *info,
 static void
 group_sections (struct elf32_arm_link_hash_table *htab,
                bfd_size_type stub_group_size,
-               bfd_boolean stubs_always_before_branch)
+               bfd_boolean stubs_always_after_branch)
 {
-  asection **list = htab->input_list + htab->top_index;
+  asection **list = htab->input_list;
 
   do
     {
       asection *tail = *list;
+      asection *head;
+      asection *tp;
 
       if (tail == bfd_abs_section_ptr)
        continue;
 
-      while (tail != NULL)
+      /* Reverse the list: we must avoid placing stubs at the
+        beginning of the section because the beginning of the text
+        section may be required for an interrupt vector in bare metal
+        code.  */
+#define NEXT_SEC PREV_SEC
+      head = tail;
+      tp = NULL;
+      for (;;)
+       {
+         asection *h = PREV_SEC (head);
+         NEXT_SEC (head) = tp;
+         if (h == NULL)
+           break;
+         tp = head;
+         head = h;
+       }
+
+      while (head != NULL)
        {
          asection *curr;
-         asection *prev;
+         asection *next;
          bfd_size_type total;
 
-         curr = tail;
-         total = tail->size;
-         while ((prev = PREV_SEC (curr)) != NULL
-                && ((total += curr->output_offset - prev->output_offset)
+         curr = head;
+         total = head->size;
+         while ((next = NEXT_SEC (curr)) != NULL
+                && ((total += next->output_offset - curr->output_offset)
                     < stub_group_size))
-           curr = prev;
+           curr = next;
 
-         /* OK, the size from the start of CURR to the end is less
+         /* OK, the size from the start to the start of CURR is less
             than stub_group_size and thus can be handled by one stub
-            section.  (Or the tail section is itself larger than
+            section.  (Or the head section is itself larger than
             stub_group_size, in which case we may be toast.)
             We should really be keeping track of the total size of
             stubs added here, as stubs contribute to the final output
             section size.  */
          do
            {
-             prev = PREV_SEC (tail);
+             next = NEXT_SEC (head);
              /* Set up this stub group.  */
-             htab->stub_group[tail->id].link_sec = curr;
+             htab->stub_group[head->id].link_sec = curr;
            }
-         while (tail != curr && (tail = prev) != NULL);
+         while (head != curr && (head = next) != NULL);
 
          /* But wait, there's more!  Input sections up to stub_group_size
-            bytes before the stub section can be handled by it too.  */
-         if (!stubs_always_before_branch)
+            bytes after the stub section can be handled by it too.  */
+         if (!stubs_always_after_branch)
            {
              total = 0;
-             while (prev != NULL
-                    && ((total += tail->output_offset - prev->output_offset)
+             while (next != NULL
+                    && ((total += next->output_offset - head->output_offset)
                         < stub_group_size))
                {
-                 tail = prev;
-                 prev = PREV_SEC (tail);
-                 htab->stub_group[tail->id].link_sec = curr;
+                 head = next;
+                 next = NEXT_SEC (head);
+                 htab->stub_group[head->id].link_sec = curr;
                }
            }
-         tail = prev;
+         head = next;
        }
     }
-  while (list-- != htab->input_list);
+  while (list++ != htab->input_list + htab->top_index);
 
   free (htab->input_list);
 #undef PREV_SEC
+#undef NEXT_SEC
 }
 
 /* Determine and set the size of the stub section for a final link.
@@ -3454,7 +3595,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
                      void (*layout_sections_again) (void))
 {
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_before_branch;
+  bfd_boolean stubs_always_after_branch;
   bfd_boolean stub_changed = 0;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
 
@@ -3467,7 +3608,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->stub_bfd = stub_bfd;
   htab->add_stub_section = add_stub_section;
   htab->layout_sections_again = layout_sections_again;
-  stubs_always_before_branch = group_size < 0;
+  stubs_always_after_branch = group_size < 0;
   if (group_size < 0)
     stub_group_size = -group_size;
   else
@@ -3487,7 +3628,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
       stub_group_size = 4170000;
     }
 
-  group_sections (htab, stub_group_size, stubs_always_before_branch);
+  group_sections (htab, stub_group_size, stubs_always_after_branch);
 
   while (1)
     {
@@ -4553,8 +4694,7 @@ bfd_elf32_arm_process_before_allocation (bfd *abfd,
              /* 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.  */
-             if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC
-                 && !(r_type == R_ARM_CALL && globals->use_blx))
+             if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC)
                record_arm_to_thumb_glue (link_info, h);
              break;
 
@@ -4998,6 +5138,10 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
   if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_NONE)
     return TRUE;
 
+  /* Skip this BFD if it corresponds to an executable or dynamic object.  */
+  if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+    return TRUE;
+
   for (sec = abfd->sections; sec != NULL; sec = sec->next)
     {
       unsigned int i, span, first_fmac = 0, veneer_of_insn = 0;
@@ -5008,6 +5152,8 @@ bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
       if (elf_section_type (sec) != SHT_PROGBITS
           || (elf_section_flags (sec) & SHF_EXECINSTR) == 0
           || (sec->flags & SEC_EXCLUDE) != 0
+         || sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS
+         || sec->output_section == bfd_abs_section_ptr
           || strcmp (sec->name, VFP11_ERRATUM_VENEER_SECTION_NAME) == 0)
         continue;
 
@@ -8138,13 +8284,33 @@ static int
 elf32_arm_obj_attrs_arg_type (int tag)
 {
   if (tag == Tag_compatibility)
-    return 3;
-  else if (tag == 4 || tag == 5)
-    return 2;
+    return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL;
+  else if (tag == Tag_nodefaults)
+    return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_NO_DEFAULT;
+  else if (tag == Tag_CPU_raw_name || tag == Tag_CPU_name)
+    return ATTR_TYPE_FLAG_STR_VAL;
   else if (tag < 32)
-    return 1;
+    return ATTR_TYPE_FLAG_INT_VAL;
   else
-    return (tag & 1) != 0 ? 2 : 1;
+    return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL;
+}
+
+/* The ABI defines that Tag_conformance should be emitted first, and that
+   Tag_nodefaults should be second (if either is defined).  This sets those
+   two positions, and bumps up the position of all the remaining tags to
+   compensate.  */
+static int
+elf32_arm_obj_attrs_order (int num)
+{
+  if (num == 4)
+    return Tag_conformance;
+  if (num == 5)
+    return Tag_nodefaults;
+  if ((num - 2) < Tag_nodefaults)
+    return num - 2;
+  if ((num - 1) < Tag_conformance)
+    return num - 1;
+  return num;
 }
 
 /* Read the architecture from the Tag_also_compatible_with attribute, if any.
@@ -8675,11 +8841,10 @@ elf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
          break;
 
        case Tag_nodefaults:
-         /* This tag is set if it exists, but the value is unused.
-            Unfortunately, we don't record whether each attribute is zero
-            initialized, or read from the file, so the information has been
-            lost.  In any case, we don't write attributes with zero values.
-            Do nothing. */
+         /* This tag is set if it exists, but the value is unused (and is
+            typically zero).  We don't actually need to do anything here -
+            the merge happens automatically when the type flags are merged
+            below.  */
          break;
        case Tag_also_compatible_with:
          /* Already done in Tag_CPU_arch.  */
@@ -9624,7 +9789,7 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                        flagword flags;
 
                        flags = bfd_get_section_flags (dynobj, sreloc);
-                       flags &= ~(SEC_LOAD | SEC_ALLOC);
+                       flags |= (SEC_LOAD | SEC_ALLOC);
                        bfd_set_section_flags (dynobj, sreloc, flags);
                      }
                  }
@@ -11609,6 +11774,11 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
   bfd_vma addr;
   char *stub_name;
   output_arch_syminfo *osi;
+  const insn_sequence *template;
+  enum stub_insn_type prev_type;
+  int size;
+  int i;
+  enum map_symbol_type sym_type;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry;
@@ -11627,58 +11797,71 @@ arm_map_one_stub (struct bfd_hash_entry * gen_entry,
   addr = (bfd_vma) stub_entry->stub_offset;
   stub_name = stub_entry->output_name;
 
-  switch (stub_entry->stub_type)
+  template = stub_entry->stub_template;
+  switch (template[0].type)
     {
-    case arm_stub_long_branch:
-      if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 8))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 4))
-       return FALSE;
-      break;
-    case arm_thumb_v4t_stub_long_branch:
-      if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 12))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 8))
-       return FALSE;
-      break;
-    case arm_thumb_thumb_stub_long_branch:
-      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))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 12))
-       return FALSE;
-      break;
-    case arm_thumb_arm_v4t_stub_long_branch:
-      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))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 8))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 16))
-       return FALSE;
-      break;
-    case arm_thumb_arm_v4t_stub_short_branch:
-      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))
+    case ARM_TYPE:
+      if (!elf32_arm_output_stub_sym (osi, stub_name, addr, stub_entry->stub_size))
        return FALSE;
       break;
-    case arm_stub_pic_long_branch:
-      if (!elf32_arm_output_stub_sym (osi, stub_name, addr, 12))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
-       return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 8))
+    case THUMB16_TYPE:
+      if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1,
+                                     stub_entry->stub_size))
        return FALSE;
       break;
     default:
       BFD_FAIL ();
+      return FALSE;
+    }
+
+  prev_type = DATA_TYPE;
+  size = 0;
+  for (i = 0; i < stub_entry->stub_template_size; i++)
+    {
+      switch (template[i].type)
+       {
+       case ARM_TYPE:
+         sym_type = ARM_MAP_ARM;
+         break;
+
+       case THUMB16_TYPE:
+         sym_type = ARM_MAP_THUMB;
+         break;
+
+       case DATA_TYPE:
+         sym_type = ARM_MAP_DATA;
+         break;
+
+       default:
+         BFD_FAIL ();
+         return FALSE;
+       }
+
+      if (template[i].type != prev_type)
+       {
+         prev_type = template[i].type;
+         if (!elf32_arm_output_map_sym (osi, sym_type, addr + size))
+           return FALSE;
+       }
+
+      switch (template[i].type)
+       {
+       case ARM_TYPE:
+         size += 4;
+         break;
+
+       case THUMB16_TYPE:
+         size += 2;
+         break;
+
+       case DATA_TYPE:
+         size += 4;
+         break;
+
+       default:
+         BFD_FAIL ();
+         return FALSE;
+       }
     }
 
   return TRUE;
@@ -12291,6 +12474,7 @@ const struct elf_size_info elf32_arm_size_info =
 #define elf_backend_obj_attrs_arg_type         elf32_arm_obj_attrs_arg_type
 #undef  elf_backend_obj_attrs_section_type
 #define elf_backend_obj_attrs_section_type     SHT_ARM_ATTRIBUTES
+#define elf_backend_obj_attrs_order    elf32_arm_obj_attrs_order
 
 #include "elf32-target.h"
 
This page took 0.042982 seconds and 4 git commands to generate.