[ARM] FDPIC: Implement Thumb-only PLT for FDPIC.
[deliverable/binutils-gdb.git] / bfd / elf32-arm.c
index 9eb12e2fed786e9d3a03ca9db3a1063d9e7249a1..a42db44b2f12f22058844625cdd017ef2f80e3a2 100644 (file)
@@ -1746,7 +1746,7 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
 };
 
 /* 160 onwards: */
-static reloc_howto_type elf32_arm_howto_table_2[5] =
+static reloc_howto_type elf32_arm_howto_table_2[8] =
 {
   HOWTO (R_ARM_IRELATIVE,      /* type */
         0,                     /* rightshift */
@@ -1813,6 +1813,45 @@ static reloc_howto_type elf32_arm_howto_table_2[5] =
         0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_GD32_FDPIC, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_GD32_FDPIC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_LDM32_FDPIC,        /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_LDM32_FDPIC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_ARM_TLS_IE32_FDPIC, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_ARM_TLS_IE32_FDPIC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 };
 
 /* 249-255 extended, currently unused, relocations:  */
@@ -1970,6 +2009,9 @@ static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
     {BFD_RELOC_ARM_GOTOFFFUNCDESC,   R_ARM_GOTOFFFUNCDESC},
     {BFD_RELOC_ARM_FUNCDESC,         R_ARM_FUNCDESC},
     {BFD_RELOC_ARM_FUNCDESC_VALUE,   R_ARM_FUNCDESC_VALUE},
+    {BFD_RELOC_ARM_TLS_GD32_FDPIC,   R_ARM_TLS_GD32_FDPIC},
+    {BFD_RELOC_ARM_TLS_LDM32_FDPIC,  R_ARM_TLS_LDM32_FDPIC},
+    {BFD_RELOC_ARM_TLS_IE32_FDPIC,   R_ARM_TLS_IE32_FDPIC},
     {BFD_RELOC_VTABLE_INHERIT,      R_ARM_GNU_VTINHERIT},
     {BFD_RELOC_VTABLE_ENTRY,        R_ARM_GNU_VTENTRY},
     {BFD_RELOC_ARM_MOVW,            R_ARM_MOVW_ABS_NC},
@@ -2209,6 +2251,9 @@ typedef unsigned short int insn16;
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
 
+/* FDPIC default stack size.  */
+#define DEFAULT_STACK_SIZE 0x8000
+
 static const unsigned long tls_trampoline [] =
 {
   0xe08e0000,          /* add r0, lr, r0 */
@@ -2245,6 +2290,22 @@ static const bfd_vma elf32_arm_fdpic_plt_entry [] =
     0xe599f000,    /* ldr     pc, [r9] */
   };
 
+/* Thumb FDPIC PLT entry.  */
+/* The last 5 words contain PLT lazy fragment code and data.  */
+static const bfd_vma elf32_arm_fdpic_thumb_plt_entry [] =
+  {
+    0xc00cf8df,    /* ldr.w   r12, .L1 */
+    0x0c09eb0c,    /* add.w   r12, r12, r9 */
+    0x9004f8dc,    /* ldr.w   r9, [r12, #4] */
+    0xf000f8dc,    /* ldr.w   pc, [r12] */
+    0x00000000,    /* .L1     .word   foo(GOTOFFFUNCDESC) */
+    0x00000000,    /* .L2     .word   foo(funcdesc_value_reloc_offset) */
+    0xc008f85f,    /* ldr.w   r12, .L2 */
+    0xcd04f84d,    /* push    {r12} */
+    0xc004f8d9,    /* ldr.w   r12, [r9, #4] */
+    0xf000f8d9,    /* ldr.w   pc, [r9] */
+  };
+
 #ifdef FOUR_WORD_PLT
 
 /* The first entry in a procedure linkage table looks like
@@ -3280,7 +3341,7 @@ struct elf32_arm_link_hash_table
   /* Offset in .plt section of tls_arm_trampoline.  */
   bfd_vma tls_trampoline;
 
-  /* Data for R_ARM_TLS_LDM32 relocations.  */
+  /* Data for R_ARM_TLS_LDM32/R_ARM_TLS_LDM32_FDPIC relocations.  */
   union
   {
     bfd_signed_vma refcount;
@@ -3575,6 +3636,8 @@ elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
   return TRUE;
 }
 
+static bfd_boolean using_thumb_only (struct elf32_arm_link_hash_table *globals);
+
 /* Return true if the PLT described by ARM_PLT requires a Thumb stub
    before it.  */
 
@@ -3585,8 +3648,9 @@ elf32_arm_plt_needs_thumb_stub_p (struct bfd_link_info *info,
   struct elf32_arm_link_hash_table *htab;
 
   htab = elf32_arm_hash_table (info);
-  return (arm_plt->thumb_refcount != 0
-         || (!htab->use_blx && arm_plt->maybe_thumb_refcount != 0));
+
+  return (!using_thumb_only(htab) && (arm_plt->thumb_refcount != 0
+         || (!htab->use_blx && arm_plt->maybe_thumb_refcount != 0)));
 }
 
 /* Return a pointer to the head of the dynamic reloc list that should
@@ -8912,7 +8976,9 @@ bfd_elf32_arm_set_target_params (struct bfd *output_bfd,
     return;
 
   globals->target1_is_rel = params->target1_is_rel;
-  if (strcmp (params->target2_type, "rel") == 0)
+  if (globals->fdpic_p)
+    globals->target2_reloc = R_ARM_GOT32;
+  else if (strcmp (params->target2_type, "rel") == 0)
     globals->target2_reloc = R_ARM_REL32;
   else if (strcmp (params->target2_type, "abs") == 0)
     globals->target2_reloc = R_ARM_ABS32;
@@ -9682,6 +9748,10 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
        }
       else if (htab->fdpic_p)
        {
+         const bfd_vma *plt_entry = using_thumb_only(htab)
+           ? elf32_arm_fdpic_thumb_plt_entry
+           : elf32_arm_fdpic_plt_entry;
+
          /* Fill-up Thumb stub if needed.  */
          if (elf32_arm_plt_needs_thumb_stub_p (info, arm_plt))
            {
@@ -9690,14 +9760,13 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
              put_thumb_insn (htab, output_bfd,
                              elf32_arm_plt_thumb_stub[1], ptr - 2);
            }
-         put_arm_insn(htab, output_bfd,
-                      elf32_arm_fdpic_plt_entry[0], ptr + 0);
-         put_arm_insn(htab, output_bfd,
-                      elf32_arm_fdpic_plt_entry[1], ptr + 4);
-         put_arm_insn(htab, output_bfd,
-                      elf32_arm_fdpic_plt_entry[2], ptr + 8);
-         put_arm_insn(htab, output_bfd,
-                      elf32_arm_fdpic_plt_entry[3], ptr + 12);
+         /* As we are using 32 bit instructions even for the Thumb
+            version, we have to use 'put_arm_insn' instead of
+            'put_thumb_insn'.  */
+         put_arm_insn(htab, output_bfd, plt_entry[0], ptr + 0);
+         put_arm_insn(htab, output_bfd, plt_entry[1], ptr + 4);
+         put_arm_insn(htab, output_bfd, plt_entry[2], ptr + 8);
+         put_arm_insn(htab, output_bfd, plt_entry[3], ptr + 12);
          bfd_put_32 (output_bfd, got_offset, ptr + 16);
 
          if (!(info->flags & DF_BIND_NOW))
@@ -9706,14 +9775,10 @@ elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
              bfd_put_32 (output_bfd,
                          htab->root.srelplt->reloc_count * RELOC_SIZE (htab),
                          ptr + 20);
-             put_arm_insn(htab, output_bfd,
-                          elf32_arm_fdpic_plt_entry[6], ptr + 24);
-             put_arm_insn(htab, output_bfd,
-                          elf32_arm_fdpic_plt_entry[7], ptr + 28);
-             put_arm_insn(htab, output_bfd,
-                          elf32_arm_fdpic_plt_entry[8], ptr + 32);
-             put_arm_insn(htab, output_bfd,
-                          elf32_arm_fdpic_plt_entry[9], ptr + 36);
+             put_arm_insn(htab, output_bfd, plt_entry[6], ptr + 24);
+             put_arm_insn(htab, output_bfd, plt_entry[7], ptr + 28);
+             put_arm_insn(htab, output_bfd, plt_entry[8], ptr + 32);
+             put_arm_insn(htab, output_bfd, plt_entry[9], ptr + 36);
            }
        }
       else if (using_thumb_only (htab))
@@ -11523,6 +11588,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                                       rel->r_addend);
 
     case R_ARM_TLS_LDM32:
+    case R_ARM_TLS_LDM32_FDPIC:
       {
        bfd_vma off;
 
@@ -11561,7 +11627,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
            globals->tls_ldm_got.offset |= 1;
          }
 
-       if (globals->fdpic_p)
+       if (r_type == R_ARM_TLS_LDM32_FDPIC)
          {
            bfd_put_32(output_bfd,
                       globals->root.sgot->output_offset + off,
@@ -11584,7 +11650,9 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
     case R_ARM_TLS_CALL:
     case R_ARM_THM_TLS_CALL:
     case R_ARM_TLS_GD32:
+    case R_ARM_TLS_GD32_FDPIC:
     case R_ARM_TLS_IE32:
+    case R_ARM_TLS_IE32_FDPIC:
     case R_ARM_TLS_GOTDESC:
     case R_ARM_TLS_DESCSEQ:
     case R_ARM_THM_TLS_DESCSEQ:
@@ -11772,7 +11840,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
              local_got_offsets[r_symndx] |= 1;
          }
 
-       if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32)
+       if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32 && r_type != R_ARM_TLS_GD32_FDPIC)
          off += 8;
        else if (tls_type & GOT_TLS_GDESC)
          off = offplt;
@@ -11931,8 +11999,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                   - (input_section->output_section->vma
                      + input_section->output_offset + rel->r_offset));
 
-       if (globals->fdpic_p && (r_type == R_ARM_TLS_GD32 ||
-                                r_type == R_ARM_TLS_IE32))
+       if (globals->fdpic_p && (r_type == R_ARM_TLS_GD32_FDPIC ||
+                                r_type == R_ARM_TLS_IE32_FDPIC))
          {
            /* For FDPIC relocations, resolve to the offset of the GOT
               entry from the start of GOT.  */
@@ -12845,13 +12913,16 @@ arm_add_to_rel (bfd *            abfd,
 
 #define IS_ARM_TLS_RELOC(R_TYPE)       \
   ((R_TYPE) == R_ARM_TLS_GD32          \
+   || (R_TYPE) == R_ARM_TLS_GD32_FDPIC  \
    || (R_TYPE) == R_ARM_TLS_LDO32      \
    || (R_TYPE) == R_ARM_TLS_LDM32      \
+   || (R_TYPE) == R_ARM_TLS_LDM32_FDPIC        \
    || (R_TYPE) == R_ARM_TLS_DTPOFF32   \
    || (R_TYPE) == R_ARM_TLS_DTPMOD32   \
    || (R_TYPE) == R_ARM_TLS_TPOFF32    \
    || (R_TYPE) == R_ARM_TLS_LE32       \
    || (R_TYPE) == R_ARM_TLS_IE32       \
+   || (R_TYPE) == R_ARM_TLS_IE32_FDPIC \
    || IS_ARM_TLS_GNU_RELOC (R_TYPE))
 
 /* Specific set of relocations for the gnu tls dialect.  */
@@ -15077,7 +15148,9 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
          case R_ARM_GOT32:
          case R_ARM_GOT_PREL:
          case R_ARM_TLS_GD32:
+         case R_ARM_TLS_GD32_FDPIC:
          case R_ARM_TLS_IE32:
+         case R_ARM_TLS_IE32_FDPIC:
          case R_ARM_TLS_GOTDESC:
          case R_ARM_TLS_DESCSEQ:
          case R_ARM_THM_TLS_DESCSEQ:
@@ -15090,8 +15163,10 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
              switch (r_type)
                {
                case R_ARM_TLS_GD32: tls_type = GOT_TLS_GD; break;
+               case R_ARM_TLS_GD32_FDPIC: tls_type = GOT_TLS_GD; break;
 
                case R_ARM_TLS_IE32: tls_type = GOT_TLS_IE; break;
+               case R_ARM_TLS_IE32_FDPIC: tls_type = GOT_TLS_IE; break;
 
                case R_ARM_TLS_GOTDESC:
                case R_ARM_TLS_CALL: case R_ARM_THM_TLS_CALL:
@@ -15149,7 +15224,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
            /* Fall through.  */
 
          case R_ARM_TLS_LDM32:
-           if (r_type == R_ARM_TLS_LDM32)
+         case R_ARM_TLS_LDM32_FDPIC:
+           if (r_type == R_ARM_TLS_LDM32 || r_type == R_ARM_TLS_LDM32_FDPIC)
                htab->tls_ldm_got.refcount++;
            /* Fall through.  */
 
@@ -16078,15 +16154,17 @@ allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf)
 
              if (tls_type & GOT_TLS_GD)
                {
-                 /* R_ARM_TLS_GD32 needs 2 consecutive GOT slots.  If
-                    the symbol is both GD and GDESC, got.offset may
-                    have been overwritten.  */
+                 /* R_ARM_TLS_GD32 and R_ARM_TLS_GD32_FDPIC need two
+                    consecutive GOT slots.  If the symbol is both GD
+                    and GDESC, got.offset may have been
+                    overwritten.  */
                  h->got.offset = s->size;
                  s->size += 8;
                }
 
              if (tls_type & GOT_TLS_IE)
-               /* R_ARM_TLS_IE32 needs one GOT slot.  */
+               /* R_ARM_TLS_IE32/R_ARM_TLS_IE32_FDPIC need one GOT
+                  slot.  */
                s->size += 4;
            }
 
@@ -16430,6 +16508,7 @@ maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
       /* Not an error, just cut short the traversal.  */
       return FALSE;
     }
+
   return TRUE;
 }
 
@@ -16689,7 +16768,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   if (htab->tls_ldm_got.refcount > 0)
     {
       /* Allocate two GOT entries and one dynamic relocation (if necessary)
-        for R_ARM_TLS_LDM32 relocations.  */
+        for R_ARM_TLS_LDM32/R_ARM_TLS_LDM32_FDPIC relocations.  */
       htab->tls_ldm_got.offset = htab->root.sgot->size;
       htab->root.sgot->size += 8;
       if (bfd_link_pic (info))
@@ -16900,6 +16979,9 @@ elf32_arm_always_size_sections (bfd *output_bfd,
                                struct bfd_link_info *info)
 {
   asection *tls_sec;
+  struct elf32_arm_link_hash_table *htab;
+
+  htab = elf32_arm_hash_table (info);
 
   if (bfd_link_relocatable (info))
     return TRUE;
@@ -16932,6 +17014,12 @@ elf32_arm_always_size_sections (bfd *output_bfd,
          (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
        }
     }
+
+  if (htab->fdpic_p && !bfd_link_relocatable (info)
+      && !bfd_elf_stack_segment_size (output_bfd, info,
+                                     "__stacksize", DEFAULT_STACK_SIZE))
+    return FALSE;
+
   return TRUE;
 }
 
@@ -17016,10 +17104,10 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd,
     }
 
   /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  On VxWorks,
-     the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it is relative
-     to the ".got" section.  */
+     and for FDPIC, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute:
+     it is relative to the ".got" section.  */
   if (h == htab->root.hdynamic
-      || (!htab->vxworks_p && h == htab->root.hgot))
+      || (!htab->fdpic_p && !htab->vxworks_p && h == htab->root.hgot))
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -17697,15 +17785,19 @@ elf32_arm_output_plt_map_1 (output_arch_syminfo *osi,
     }
   else if (htab->fdpic_p)
     {
+      enum map_symbol_type type = using_thumb_only(htab)
+       ? ARM_MAP_THUMB
+       : ARM_MAP_ARM;
+
       if (elf32_arm_plt_needs_thumb_stub_p (osi->info, arm_plt))
         if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr - 4))
           return FALSE;
-      if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr))
+      if (!elf32_arm_output_map_sym (osi, type, addr))
         return FALSE;
       if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 16))
         return FALSE;
       if (htab->plt_entry_size == 4 * ARRAY_SIZE(elf32_arm_fdpic_plt_entry))
-        if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 24))
+        if (!elf32_arm_output_map_sym (osi, type, addr + 24))
           return FALSE;
     }
   else if (using_thumb_only (htab))
@@ -18064,7 +18156,7 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
          if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0))
            return FALSE;
        }
-      else if (using_thumb_only (htab))
+      else if (using_thumb_only (htab) && !htab->fdpic_p)
        {
          if (!elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, 0))
            return FALSE;
This page took 0.036787 seconds and 4 git commands to generate.