[ARM-FDPIC,06/12,ARM] Add TLS relocations for FDPIC.

Message ID 20180322143850.1766-7-christophe.lyon@st.com
State New
Headers show
Series
  • FDPIC ABI for ARM
Related show

Commit Message

Christophe Lyon March 22, 2018, 2:38 p.m.
Define and handle TLS relocations for FDPIC in BFD and gas.

In gas, the new relocations are rejected if the --fdpic option was not
specified.

We also define the __tdata_start symbol to mark the start of the
.tdata section. This allows FDPIC static binaries to find the start of
.tdata section, since phdr->p_vaddr of TLS segment is not a valid
value for FDPIC.

2018-XX-XX  Christophe Lyon  <christophe.lyon@st.com>
	Mickaël Guêné  <mickael.guene@st.com>

	bfd/:
	* bfd-in2.h (BFD_RELOC_ARM_TLS_GD32_FDPIC)
	(BFD_RELOC_ARM_TLS_LDM32_FDPIC, BFD_RELOC_ARM_TLS_IE32_FDPIC): New
	relocations.
	* elf32-arm.c (elf32_arm_howto_table_2): Add R_ARM_TLS_GD32_FDPIC,
	R_ARM_TLS_LDM32_FDPIC, R_ARM_TLS_IE32_FDPIC relocations.
	(elf32_arm_reloc_map): Add R_ARM_TLS_GD32_FDPIC,
	R_ARM_TLS_LDM32_FDPIC, R_ARM_TLS_IE32_FDPIC.
	(struct elf32_arm_link_hash_table): Update comment.
	(elf32_arm_final_link_relocate): Handle TLS FDPIC relocations.
	(IS_ARM_TLS_RELOC): Likewise.
	(elf32_arm_check_relocs): Likewise.
	(allocate_dynrelocs_for_symbol): Likewise.
	(elf32_arm_size_dynamic_sections): Update comment.
	* reloc.c: Add BFD_RELOC_ARM_TLS_GD32_FDPIC,
	BFD_RELOC_ARM_TLS_LDM32_FDPIC, BFD_RELOC_ARM_TLS_IE32_FDPIC.

	gas/
	* config/tc-arm.c (reloc_names): Add TLSGD_FDPIC, TLSLDM_FDPIC,
	GOTTPOFF_FDIC relocations.
	(md_apply_fix): Handle the new TLS FDPIC relocations.
	(tc_gen_reloc): Likewise.
	(arm_fix_adjustable): Likewise.

	include/
	* elf/arm.h: Add R_ARM_TLS_GD32_FDPIC, R_ARM_TLS_LDM32_FDPIC,
	R_ARM_TLS_IE32_FDPIC.

	ld/
	* scripttempl/elf.sc: Define __tdata_start for .tdata section.

* Define __tdata_start symbol to mark start of .tdata section

 This allow fdpic static binaries to find start of .tdata section
since phdr->p_vaddr of TLS segment is not a valid value for fdpic.

* Add fdpic tls specific relocations
---
 bfd/bfd-in2.h         |  3 ++
 bfd/elf32-arm.c       | 79 +++++++++++++++++++++++++++++++++++++++++++--------
 bfd/reloc.c           |  6 ++++
 gas/config/tc-arm.c   | 26 ++++++++++++++++-
 include/elf/arm.h     |  3 ++
 ld/scripttempl/elf.sc |  6 +++-
 6 files changed, 109 insertions(+), 14 deletions(-)

-- 
2.6.3

Patch

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 0c2279f..82152c6 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3570,6 +3570,9 @@  pc-relative or some form of GOT-indirect relocation.  */
   BFD_RELOC_ARM_GOTOFFFUNCDESC,
   BFD_RELOC_ARM_FUNCDESC,
   BFD_RELOC_ARM_FUNCDESC_VALUE,
+  BFD_RELOC_ARM_TLS_GD32_FDPIC,
+  BFD_RELOC_ARM_TLS_LDM32_FDPIC,
+  BFD_RELOC_ARM_TLS_IE32_FDPIC,
 
 /* Relocations for setting up GOTs and PLTs for shared libraries.  */
   BFD_RELOC_ARM_JUMP_SLOT,
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index d84edb1..0e03c77 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -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},
@@ -3280,7 +3322,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;
@@ -11523,6 +11565,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 +11604,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 +11627,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 +11817,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 +11976,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.  */
@@ -12848,13 +12893,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.  */
@@ -15080,7 +15128,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:
@@ -15093,8 +15143,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:
@@ -15152,7 +15204,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.  */
 
@@ -16081,15 +16134,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;
 	    }
 
@@ -16692,7 +16747,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))
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 5715317..ff589e5 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -3224,6 +3224,12 @@  ENUMX
   BFD_RELOC_ARM_FUNCDESC
 ENUMX
   BFD_RELOC_ARM_FUNCDESC_VALUE
+ENUMX
+  BFD_RELOC_ARM_TLS_GD32_FDPIC
+ENUMX
+  BFD_RELOC_ARM_TLS_LDM32_FDPIC
+ENUMX
+  BFD_RELOC_ARM_TLS_IE32_FDPIC
 ENUMDOC
   ARM FDPIC specific relocations.
 
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index e869084..806eb24 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -19326,7 +19326,10 @@  static struct reloc_entry reloc_names[] =
   { "gotofffuncdesc", BFD_RELOC_ARM_GOTOFFFUNCDESC },
 	{ "GOTOFFFUNCDESC", BFD_RELOC_ARM_GOTOFFFUNCDESC },
   { "funcdesc", BFD_RELOC_ARM_FUNCDESC },
-	{ "FUNCDESC", BFD_RELOC_ARM_FUNCDESC }
+	{ "FUNCDESC", BFD_RELOC_ARM_FUNCDESC },
+   { "tlsgd_fdpic", BFD_RELOC_ARM_TLS_GD32_FDPIC },      { "TLSGD_FDPIC", BFD_RELOC_ARM_TLS_GD32_FDPIC },
+   { "tlsldm_fdpic", BFD_RELOC_ARM_TLS_LDM32_FDPIC },    { "TLSLDM_FDPIC", BFD_RELOC_ARM_TLS_LDM32_FDPIC },
+   { "gottpoff_fdpic", BFD_RELOC_ARM_TLS_IE32_FDPIC },   { "GOTTPOFF_FDIC", BFD_RELOC_ARM_TLS_IE32_FDPIC },
 };
 #endif
 
@@ -24014,6 +24017,21 @@  md_apply_fix (fixS *	fixP,
       S_SET_THREAD_LOCAL (fixP->fx_addsy);
       break;
 
+      /* Same handling as above, but with the arm_fdpic guard.  */
+    case BFD_RELOC_ARM_TLS_GD32_FDPIC:
+    case BFD_RELOC_ARM_TLS_IE32_FDPIC:
+    case BFD_RELOC_ARM_TLS_LDM32_FDPIC:
+      if (arm_fdpic)
+	{
+	  S_SET_THREAD_LOCAL (fixP->fx_addsy);
+	}
+      else
+	{
+	  as_bad_where (fixP->fx_file, fixP->fx_line,
+			_("Relocation supported only in FDPIC mode"));
+	}
+      break;
+
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
       break;
@@ -24815,9 +24833,12 @@  tc_gen_reloc (asection *section, fixS *fixp)
 
     case BFD_RELOC_ARM_TLS_GOTDESC:
     case BFD_RELOC_ARM_TLS_GD32:
+    case BFD_RELOC_ARM_TLS_GD32_FDPIC:
     case BFD_RELOC_ARM_TLS_LE32:
     case BFD_RELOC_ARM_TLS_IE32:
+    case BFD_RELOC_ARM_TLS_IE32_FDPIC:
     case BFD_RELOC_ARM_TLS_LDM32:
+    case BFD_RELOC_ARM_TLS_LDM32_FDPIC:
       /* BFD will include the symbol's address in the addend.
 	 But we don't want that, so subtract it out again here.  */
       if (!S_IS_COMMON (fixp->fx_addsy))
@@ -25083,9 +25104,12 @@  arm_fix_adjustable (fixS * fixP)
       || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
       || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32_FDPIC
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32_FDPIC
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32_FDPIC
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GOTDESC
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_CALL
diff --git a/include/elf/arm.h b/include/elf/arm.h
index 158f7b1..fdae08a 100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -244,6 +244,9 @@  START_RELOC_NUMBERS (elf_arm_reloc_type)
   RELOC_NUMBER (R_ARM_GOTOFFFUNCDESC, 	162)
   RELOC_NUMBER (R_ARM_FUNCDESC,       	163)
   RELOC_NUMBER (R_ARM_FUNCDESC_VALUE, 	164)
+  RELOC_NUMBER (R_ARM_TLS_GD32_FDPIC,   165)
+  RELOC_NUMBER (R_ARM_TLS_LDM32_FDPIC,  166)
+  RELOC_NUMBER (R_ARM_TLS_IE32_FDPIC,   167)
 
   /* Extensions?  R=read-only?  */
   RELOC_NUMBER (R_ARM_RXPC25,         	249)
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index 9787ab5..5ccdd41 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -587,7 +587,11 @@  cat <<EOF
   .exception_ranges ${RELOCATING-0} : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
 
   /* Thread Local Storage sections  */
-  .tdata	${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
+  .tdata	${RELOCATING-0} :
+   {
+     ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__tdata_start = .);}}
+     *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*})
+   }
   .tbss		${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
 
   ${RELOCATING+${PREINIT_ARRAY}}