public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2] x86-64: Add R_X86_64_CODE_6_GOTTPOFF
@ 2024-02-07 12:42 H.J. Lu
  2024-02-08 11:41 ` H.J. Lu
  0 siblings, 1 reply; 3+ messages in thread
From: H.J. Lu @ 2024-02-07 12:42 UTC (permalink / raw)
  To: binutils

Changes in v2:

Rewrite fx_tcbit, fx_tcbit2 and fx_tcbit3 usage to generate
R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX,
R_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTPC32_TLSDESC and
R_X86_64_CODE_6_GOTTPOFF.

---
For

	add	%reg1, name@gottpoff(%rip), %reg2
	add	name@gottpoff(%rip), %reg1, %reg2

add

 #define R_X86_64_CODE_6_GOTTPOFF		50

if the instruction starts at 6 bytes before the relocation offset.
They are similar to R_X86_64_GOTTPOFF.  Linker can covert GOTTPOFF to

	add	$name@tpoff, %reg1, %reg2

Rewrite fx_tcbit, fx_tcbit2 and fx_tcbit3 usage to generate
R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX,
R_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTPC32_TLSDESC and
R_X86_64_CODE_6_GOTTPOFF.

NB: There is no need to check BFD_RELOC_X86_64_CODE_4_GOTTPOFF in
md_assemble since there is only BFD_RELOC_X86_64_GOTTPOFF at this
stage, which will be converted to BFD_RELOC_X86_64_CODE_4_GOTTPOFF
or BFD_RELOC_X86_64_CODE_6_GOTTPOFF in i386_validate_fix.

5 relocations:

 #define R_X86_64_CODE_5_GOTPCRELX		46
 #define R_X86_64_CODE_5_GOTTPOFF		47
 #define R_X86_64_CODE_5_GOTPC32_TLSDESC	48
 #define R_X86_64_CODE_6_GOTPCRELX		49
 #define R_X86_64_CODE_6_GOTPC32_TLSDESC	51

are added for completeness and they are unused.

bfd/

	* elf64-x86-64.c (x86_64_elf_howto_table): Add
	R_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTTPOFF,
	R_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPCRELX,
	R_X86_64_CODE_6_GOTTPOFF and R_X86_64_CODE_6_GOTPC32_TLSDESC.
	(R_X86_64_standard): Updated.
	(x86_64_reloc_map): Add R_X86_64_CODE_5_GOTPCRELX,
	R_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTPC32_TLSDESC,
	R_X86_64_CODE_6_GOTPCRELX, R_X86_64_CODE_6_GOTTPOFF and
	R_X86_64_CODE_6_GOTPC32_TLSDESC.
	(elf_x86_64_check_tls_transition): Handle
	R_X86_64_CODE_6_GOTTPOFF.
	(elf_x86_64_tls_transition): Likewise.
	(elf_x86_64_scan_relocs): Handle R_X86_64_CODE_6_GOTTPOFF.
	Issue an error for R_X86_64_CODE_5_GOTPCRELX,
	R_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTPC32_TLSDESC,
	R_X86_64_CODE_6_GOTPCRELX and R_X86_64_CODE_6_GOTPC32_TLSDESC.
	(elf_x86_64_relocate_section): Handle R_X86_64_CODE_6_GOTTPOFF.
	* reloc.c (bfd_reloc_code_real): Add
	BFD_RELOC_X86_64_CODE_5_GOTPCRELX,
	BFD_RELOC_X86_64_CODE_5_GOTTPOFF,
	BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC,
	BFD_RELOC_X86_64_CODE_6_GOTPCRELX,
	BFD_RELOC_X86_64_CODE_6_GOTTPOFF and
	BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Likewise.

elfcpp/

	* x86_64.h (R_X86_64_CODE_5_GOTPCRELX): New.
	(R_X86_64_CODE_5_GOTTPOFF): Likewise.
	(R_X86_64_CODE_5_GOTPC32_TLSDESC): Likewise.
	(R_X86_64_CODE_6_GOTPCRELX): Likewise.
	(R_X86_64_CODE_6_GOTTPOFF): Likewise.
	(R_X86_64_CODE_6_GOTPC32_TLSDESC): Likewise.

gas/

	* config/tc-i386.c (tc_i386_fix_adjustable): Handle
	BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
	(md_assemble): Don't check BFD_RELOC_X86_64_CODE_4_GOTTPOFF.
	Allow "add %reg1, foo@gottpoff(%rip), %reg2".
	(output_disp): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.  Rewrite
	setting fx_tcbitX bits for BFD_RELOC_X86_64_GOTTPOFF,
	BFD_RELOC_X86_64_GOTPC32_TLSDESC and BFD_RELOC_32_PCREL.
	(md_apply_fix): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
	(i386_validate_fix): Rewrite fx_tcbitX bit checking for
	BFD_RELOC_X86_64_GOTTPOFF, BFD_RELOC_X86_64_GOTPC32_TLSDESC and
	BFD_RELOC_32_PCREL.
	(tc_gen_reloc): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
	* testsuite/gas/i386/x86-64-gottpoff.d: Updated.
	* testsuite/gas/i386/x86-64-gottpoff.s: Add tests for
	"add %reg1, foo@gottpoff(%rip), %reg2" and
	"add foo@gottpoff(%rip), %reg, %reg2".

gold/

	* x86_64.cc (Target_x86_64::optimize_tls_reloc): Handle
	R_X86_64_CODE_6_GOTTPOFF.
	(Target_x86_64::Scan::get_reference_flags): Likewise.
	(Target_x86_64::Scan::local): Likewise.
	(Target_x86_64::Scan::global): Likewise.
	(Target_x86_64::Relocate::relocate): Likewise.
	(Target_x86_64::Relocate::relocate_tls): Likewise.
	(Target_x86_64::Relocate::tls_ie_to_le): Handle.
	R_X86_64_CODE_6_GOTTPOFF.
	* testsuite/x86_64_ie_to_le.s: Add tests for
	"add %reg1, foo@gottpoff(%rip), %reg2" and
	"add foo@gottpoff(%rip), %reg, %reg2".
	* testsuite/x86_64_ie_to_le.sh: Updated.

include/

	* elf/x86-64.h (elf_x86_64_reloc_type): Add
	R_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTTPOFF,
	R_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPCRELX,
	R_X86_64_CODE_6_GOTTPOFF and R_X86_64_CODE_6_GOTPC32_TLSDESC.

ld/

	* testsuite/ld-x86-64/tlsbindesc.s: Add R_X86_64_CODE_6_GOTTPOFF
	tests.
	* testsuite/ld-x86-64/tlsbindesc.d: Updated.
	* testsuite/ld-x86-64/tlsbindesc.rd: Likewise.
---
 bfd/bfd-in2.h                            |   6 ++
 bfd/elf64-x86-64.c                       | 113 ++++++++++++++++++++++-
 bfd/libbfd.h                             |   6 ++
 bfd/reloc.c                              |  12 +++
 elfcpp/x86_64.h                          |  24 +++++
 gas/config/tc-i386.c                     | 102 +++++++++++++++-----
 gas/testsuite/gas/i386/x86-64-gottpoff.d |   4 +
 gas/testsuite/gas/i386/x86-64-gottpoff.s |  10 ++
 gold/testsuite/x86_64_ie_to_le.s         |   2 +
 gold/testsuite/x86_64_ie_to_le.sh        |   2 +
 gold/x86_64.cc                           |  47 +++++++++-
 include/elf/x86-64.h                     |  20 ++++
 ld/testsuite/ld-x86-64/tlsbindesc.dd     |  24 +++++
 ld/testsuite/ld-x86-64/tlsbindesc.rd     |  36 ++++----
 ld/testsuite/ld-x86-64/tlsbindesc.s      |   8 ++
 15 files changed, 371 insertions(+), 45 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 581d8fe0b3e..dbafcf8da36 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3894,6 +3894,12 @@ enum bfd_reloc_code_real
   BFD_RELOC_X86_64_CODE_4_GOTPCRELX,
   BFD_RELOC_X86_64_CODE_4_GOTTPOFF,
   BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC,
+  BFD_RELOC_X86_64_CODE_5_GOTPCRELX,
+  BFD_RELOC_X86_64_CODE_5_GOTTPOFF,
+  BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC,
+  BFD_RELOC_X86_64_CODE_6_GOTPCRELX,
+  BFD_RELOC_X86_64_CODE_6_GOTTPOFF,
+  BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC,
 
   /* ns32k relocations.  */
   BFD_RELOC_NS32K_IMM_8,
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index f1253751bbd..2ed120af780 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -179,12 +179,30 @@ static reloc_howto_type x86_64_elf_howto_table[] =
   HOWTO(R_X86_64_CODE_4_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
 	complain_overflow_bitfield, bfd_elf_generic_reloc,
 	"R_X86_64_CODE_4_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
+  HOWTO(R_X86_64_CODE_5_GOTPCRELX, 0, 4, 32, true, 0,
+	complain_overflow_signed, bfd_elf_generic_reloc,
+	"R_X86_64_CODE_5_GOTPCRELX", false, 0, 0xffffffff, true),
+  HOWTO(R_X86_64_CODE_5_GOTTPOFF, 0, 4, 32, true, 0,
+	complain_overflow_signed, bfd_elf_generic_reloc,
+	"R_X86_64_CODE_5_GOTTPOFF", false, 0, 0xffffffff, true),
+  HOWTO(R_X86_64_CODE_5_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
+	complain_overflow_bitfield, bfd_elf_generic_reloc,
+	"R_X86_64_CODE_5_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
+  HOWTO(R_X86_64_CODE_6_GOTPCRELX, 0, 4, 32, true, 0,
+	complain_overflow_signed, bfd_elf_generic_reloc,
+	"R_X86_64_CODE_6_GOTPCRELX", false, 0, 0xffffffff, true),
+  HOWTO(R_X86_64_CODE_6_GOTTPOFF, 0, 4, 32, true, 0,
+	complain_overflow_signed, bfd_elf_generic_reloc,
+	"R_X86_64_CODE_6_GOTTPOFF", false, 0, 0xffffffff, true),
+  HOWTO(R_X86_64_CODE_6_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
+	complain_overflow_bitfield, bfd_elf_generic_reloc,
+	"R_X86_64_CODE_6_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
 
   /* We have a gap in the reloc numbers here.
      R_X86_64_standard counts the number up to this point, and
      R_X86_64_vt_offset is the value to subtract from a reloc type of
      R_X86_64_GNU_VT* to form an index into this table.  */
-#define R_X86_64_standard (R_X86_64_CODE_4_GOTPC32_TLSDESC + 1)
+#define R_X86_64_standard (R_X86_64_CODE_6_GOTPC32_TLSDESC + 1)
 #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
 
 /* GNU extension to record C++ vtable hierarchy.  */
@@ -256,6 +274,12 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
   { BFD_RELOC_X86_64_CODE_4_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX, },
   { BFD_RELOC_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTTPOFF, },
   { BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC, R_X86_64_CODE_4_GOTPC32_TLSDESC, },
+  { BFD_RELOC_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTPCRELX, },
+  { BFD_RELOC_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTTPOFF, },
+  { BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_5_GOTPC32_TLSDESC, },
+  { BFD_RELOC_X86_64_CODE_6_GOTPCRELX, R_X86_64_CODE_6_GOTPCRELX, },
+  { BFD_RELOC_X86_64_CODE_6_GOTTPOFF, R_X86_64_CODE_6_GOTTPOFF, },
+  { BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPC32_TLSDESC, },
   { BFD_RELOC_VTABLE_INHERIT,	R_X86_64_GNU_VTINHERIT, },
   { BFD_RELOC_VTABLE_ENTRY,	R_X86_64_GNU_VTENTRY, },
 };
@@ -1283,6 +1307,23 @@ elf_x86_64_check_tls_transition (bfd *abfd,
 
       goto check_gottpoff;
 
+    case R_X86_64_CODE_6_GOTTPOFF:
+      /* Check transition from IE access model:
+		add %reg1, foo@gottpoff(%rip), %reg2
+		where reg1/reg2 are one of r16 to r31.  */
+
+      if (offset < 6
+	  || (offset + 4) > sec->size
+	  || contents[offset - 6] != 0x62)
+	return false;
+
+      val = bfd_get_8 (abfd, contents + offset - 2);
+      if (val != 0x01 && val != 0x03)
+	return false;
+
+      val = bfd_get_8 (abfd, contents + offset - 1);
+      return (val & 0xc7) == 5;
+
     case R_X86_64_GOTTPOFF:
       /* Check transition from IE access model:
 		mov foo@gottpoff(%rip), %reg
@@ -1417,6 +1458,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
     case R_X86_64_TLSDESC_CALL:
     case R_X86_64_GOTTPOFF:
     case R_X86_64_CODE_4_GOTTPOFF:
+    case R_X86_64_CODE_6_GOTTPOFF:
       if (bfd_link_executable (info))
 	{
 	  if (h == NULL)
@@ -1464,6 +1506,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
   /* Return TRUE if there is no transition.  */
   if (from_type == to_type
       || (from_type == R_X86_64_CODE_4_GOTTPOFF
+	  && to_type == R_X86_64_GOTTPOFF)
+      || (from_type == R_X86_64_CODE_6_GOTTPOFF
 	  && to_type == R_X86_64_GOTTPOFF))
     return true;
 
@@ -2177,6 +2221,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	case R_X86_64_GOTTPOFF:
 	case R_X86_64_CODE_4_GOTTPOFF:
+	case R_X86_64_CODE_6_GOTTPOFF:
 	  if (!bfd_link_executable (info))
 	    info->flags |= DF_STATIC_TLS;
 	  /* Fall through */
@@ -2214,6 +2259,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
 		break;
 	      case R_X86_64_GOTTPOFF:
 	      case R_X86_64_CODE_4_GOTTPOFF:
+	      case R_X86_64_CODE_6_GOTTPOFF:
 		tls_type = GOT_TLS_IE;
 		break;
 	      case R_X86_64_GOTPC32_TLSDESC:
@@ -2503,6 +2549,26 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
 	    }
 	  break;
 
+	case R_X86_64_CODE_5_GOTPCRELX:
+	case R_X86_64_CODE_5_GOTTPOFF:
+	case R_X86_64_CODE_5_GOTPC32_TLSDESC:
+	case R_X86_64_CODE_6_GOTPCRELX:
+	case R_X86_64_CODE_6_GOTPC32_TLSDESC:
+	    {
+	      /* These relocations are added only for completeness and
+		 aren't be used.  */
+	      if (h)
+		name = h->root.root.string;
+	      else
+		name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
+					 NULL);
+	      _bfd_error_handler
+		/* xgettext:c-format */
+		(_("%pB: unsupported relocation %s against symbol `%s'"),
+		 abfd, x86_64_elf_howto_table[r_type].name, name);
+	    }
+	  break;
+
 	  /* This relocation describes the C++ object vtable hierarchy.
 	     Reconstruct it for later use during GC.  */
 	case R_X86_64_GNU_VTINHERIT:
@@ -3570,6 +3636,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 	case R_X86_64_TLSDESC_CALL:
 	case R_X86_64_GOTTPOFF:
 	case R_X86_64_CODE_4_GOTTPOFF:
+	case R_X86_64_CODE_6_GOTTPOFF:
 	  tls_type = GOT_UNKNOWN;
 	  if (h == NULL && local_got_offsets)
 	    tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
@@ -3920,6 +3987,50 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 			      contents + roff);
 		  continue;
 		}
+	      else if (r_type == R_X86_64_CODE_6_GOTTPOFF)
+		{
+		  /* IE->LE transition:
+		     Originally it is
+		     add %reg1, foo@gottpoff(%rip), %reg2
+		     or
+		     add foo@gottpoff(%rip), %reg1, %reg2
+		     We change it into:
+		     add $foo@tpoff, %reg1, %reg2
+		   */
+		  unsigned int reg, byte1;
+		  unsigned int updated_byte1;
+
+		  if (roff < 6)
+		    goto corrupt_input;
+
+		  /* Move the R bits to the B bits in EVEX payload
+		     byte 1.  */
+		  byte1 = bfd_get_8 (input_bfd, contents + roff - 5);
+		  updated_byte1 = byte1;
+
+		  /* Set the R bits since they is inverted.  */
+		  updated_byte1 |= 1 << 7 | 1 << 4;
+
+		  /* Update the B bits from the R bits.  */
+		  if ((byte1 & (1 << 7)) == 0)
+		    updated_byte1 &= ~(1 << 5);
+		  if ((byte1 & (1 << 4)) == 0)
+		    updated_byte1 |= 1 << 3;
+
+		  reg = bfd_get_8 (input_bfd, contents + roff - 1);
+		  reg >>= 3;
+
+		  bfd_put_8 (output_bfd, updated_byte1,
+			     contents + roff - 5);
+		  bfd_put_8 (output_bfd, 0x81,
+			     contents + roff - 2);
+		  bfd_put_8 (output_bfd, 0xc0 | reg,
+			     contents + roff - 1);
+		  bfd_put_32 (output_bfd,
+			      elf_x86_64_tpoff (info, relocation),
+			      contents + roff);
+		  continue;
+		}
 	      else
 		BFD_ASSERT (false);
 	    }
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index ebd4f24149b..40bbe6a3886 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1463,6 +1463,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_X86_64_CODE_4_GOTPCRELX",
   "BFD_RELOC_X86_64_CODE_4_GOTTPOFF",
   "BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC",
+  "BFD_RELOC_X86_64_CODE_5_GOTPCRELX",
+  "BFD_RELOC_X86_64_CODE_5_GOTTPOFF",
+  "BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC",
+  "BFD_RELOC_X86_64_CODE_6_GOTPCRELX",
+  "BFD_RELOC_X86_64_CODE_6_GOTTPOFF",
+  "BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC",
   "BFD_RELOC_NS32K_IMM_8",
   "BFD_RELOC_NS32K_IMM_16",
   "BFD_RELOC_NS32K_IMM_32",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index e74cbd75e96..7583b7fd552 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2481,6 +2481,18 @@ ENUMX
   BFD_RELOC_X86_64_CODE_4_GOTTPOFF
 ENUMX
   BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC
+ENUMX
+  BFD_RELOC_X86_64_CODE_5_GOTPCRELX
+ENUMX
+  BFD_RELOC_X86_64_CODE_5_GOTTPOFF
+ENUMX
+  BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC
+ENUMX
+  BFD_RELOC_X86_64_CODE_6_GOTPCRELX
+ENUMX
+  BFD_RELOC_X86_64_CODE_6_GOTTPOFF
+ENUMX
+  BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC
 ENUMDOC
   x86-64/elf relocations.
 
diff --git a/elfcpp/x86_64.h b/elfcpp/x86_64.h
index 135f339fccf..5d254ce483b 100644
--- a/elfcpp/x86_64.h
+++ b/elfcpp/x86_64.h
@@ -110,6 +110,30 @@ enum
 					// descriptor in GOT if the
 					// instruction starts at 4 bytes
 					// before the relocation offset.
+  R_X86_64_CODE_5_GOTPCRELX = 46, // 32 bit signed PC relative offset to
+				  // GOT if the instruction starts at 5
+				  // bytes before the relocation offset,
+				  // relaxable.
+  R_X86_64_CODE_5_GOTTPOFF = 47,  // 32 bit signed PC relative offset to
+				  // GOT entry for IE symbol if the
+				  // instruction starts at 5 bytes before
+				  // the relocation offset.
+  R_X86_64_CODE_5_GOTPC32_TLSDESC = 48, // 32-bit PC relative to TLS
+					// descriptor in GOT if the
+					// instruction starts at 5 bytes
+					// before the relocation offset.
+  R_X86_64_CODE_6_GOTPCRELX = 49, // 32 bit signed PC relative offset to
+				  // GOT if the instruction starts at 6
+				  // bytes before the relocation offset,
+				  // relaxable.
+  R_X86_64_CODE_6_GOTTPOFF = 50,  // 32 bit signed PC relative offset to
+				  // GOT entry for IE symbol if the
+				  // instruction starts at 6 bytes before
+				  // the relocation offset.
+  R_X86_64_CODE_6_GOTPC32_TLSDESC = 51, // 32-bit PC relative to TLS
+					// descriptor in GOT if the
+					// instruction starts at 6 bytes
+					// before the relocation offset.
   // GNU vtable garbage collection extensions.
   R_X86_64_GNU_VTINHERIT = 250,
   R_X86_64_GNU_VTENTRY = 251
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 50d890c4481..9e7bb1dd4d6 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -3648,6 +3648,7 @@ tc_i386_fix_adjustable (fixS *fixP)
       || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF
       || fixP->fx_r_type == BFD_RELOC_X86_64_CODE_4_GOTTPOFF
+      || fixP->fx_r_type == BFD_RELOC_X86_64_CODE_6_GOTTPOFF
       || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
       || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64
@@ -6795,10 +6796,19 @@ md_assemble (char *line)
       for (j = i.imm_operands; j < i.operands; ++j)
 	switch (i.reloc[j])
 	  {
+	  case BFD_RELOC_X86_64_GOTTPOFF:
+	    if (i.tm.mnem_off == MN_add
+		&& i.tm.opcode_space == SPACE_EVEXMAP4
+		&& i.mem_operands == 1
+		&& i.base_reg
+		&& i.base_reg->reg_num == RegIP
+		&& i.tm.operand_types[0].bitfield.class == Reg
+		&& i.tm.operand_types[2].bitfield.class == Reg)
+	      /* Allow APX: add %reg1, foo@gottpoff(%rip), %reg2.  */
+	      break;
+	    /* Fall through.  */
 	  case BFD_RELOC_386_TLS_GOTIE:
 	  case BFD_RELOC_386_TLS_LE_32:
-	  case BFD_RELOC_X86_64_GOTTPOFF:
-	  case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
 	  case BFD_RELOC_X86_64_TLSLD:
 	    as_bad (_("TLS relocation cannot be used with `%s'"), insn_name (&i.tm));
 	    return;
@@ -12040,6 +12050,7 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
 		    case BFD_RELOC_X86_64_TLSLD:
 		    case BFD_RELOC_X86_64_GOTTPOFF:
 		    case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
+		    case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
 		    case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
 		    case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
 		    case BFD_RELOC_X86_64_TLSDESC_CALL:
@@ -12056,9 +12067,30 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
 		  && !i.prefix[ADDR_PREFIX])
 		fixP->fx_signed = 1;
 
-	      /* Set fx_tcbit3 for REX2 prefix.  */
-	      if (is_apx_rex2_encoding ())
-		fixP->fx_tcbit3 = 1;
+	      if (reloc_type == BFD_RELOC_X86_64_GOTTPOFF
+		  && i.tm.opcode_space == SPACE_EVEXMAP4)
+		{
+		  /* Only "add %reg1, foo@gottpoff(%rip), %reg2" is
+		     allowed in md_assemble.  Set fx_tcbit2 for EVEX
+		     prefix.  */
+		  fixP->fx_tcbit2 = 1;
+		  continue;
+		}
+
+	      if (i.base_reg && i.base_reg->reg_num == RegIP)
+		{
+		  if (reloc_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC)
+		    {
+		      /* Set fx_tcbit for REX2 prefix.  */
+		      if (is_apx_rex2_encoding ())
+			fixP->fx_tcbit = 1;
+		      continue;
+		    }
+		}
+	      /* In 64-bit, i386_validate_fix updates only (%rip)
+		 relocations.  */
+	      else if (object_64bit)
+		continue;
 
 	      /* Check for "call/jmp *mem", "mov mem, %reg",
 		 "test %reg, mem" and "binop mem, %reg" where binop
@@ -12083,10 +12115,22 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
 		{
 		  if (object_64bit)
 		    {
-		      fixP->fx_tcbit = i.rex != 0;
-		      if (i.base_reg
-			  && (i.base_reg->reg_num == RegIP))
-		      fixP->fx_tcbit2 = 1;
+		      if (reloc_type == BFD_RELOC_X86_64_GOTTPOFF)
+			{
+			  /* Set fx_tcbit for REX2 prefix.  */
+			  if (is_apx_rex2_encoding ())
+			    fixP->fx_tcbit = 1;
+			}
+		      else
+			{
+			  /* Set fx_tcbit3 for REX2 prefix.  */
+			  if (is_apx_rex2_encoding ())
+			    fixP->fx_tcbit3 = 1;
+			  else if (i.rex)
+			    fixP->fx_tcbit2 = 1;
+			  else
+			    fixP->fx_tcbit = 1;
+			}
 		    }
 		  else
 		    fixP->fx_tcbit2 = 1;
@@ -15563,6 +15607,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       case BFD_RELOC_X86_64_TLSLD:
       case BFD_RELOC_X86_64_GOTTPOFF:
       case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
+      case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
       case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
       case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
 	value = 0; /* Fully resolved at runtime.  No addend.  */
@@ -17144,13 +17189,27 @@ i386_validate_fix (fixS *fixp)
 	   && (!S_IS_DEFINED (fixp->fx_addsy)
 	       || S_IS_EXTERNAL (fixp->fx_addsy));
 
-  if (fixp->fx_tcbit3)
+  /* BFD_RELOC_X86_64_GOTTPOFF:
+      1. fx_tcbit -> BFD_RELOC_X86_64_CODE_4_GOTTPOFF
+      2. fx_tcbit2 -> BFD_RELOC_X86_64_CODE_6_GOTTPOFF
+    BFD_RELOC_X86_64_GOTPC32_TLSDESC:
+      1. fx_tcbit -> BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC
+    BFD_RELOC_32_PCREL:
+      1. fx_tcbit -> BFD_RELOC_X86_64_GOTPCRELX
+      2. fx_tcbit2 -> BFD_RELOC_X86_64_REX_GOTPCRELX
+      3. fx_tcbit3 -> BFD_RELOC_X86_64_CODE_4_GOTPCRELX
+      4. else -> BFD_RELOC_X86_64_GOTPCREL
+   */
+  if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF)
     {
-      if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF)
+      if (fixp->fx_tcbit)
 	fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTTPOFF;
-      else if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC)
-	fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC;
+      else if (fixp->fx_tcbit2)
+	fixp->fx_r_type = BFD_RELOC_X86_64_CODE_6_GOTTPOFF;
     }
+  else if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC
+	   && fixp->fx_tcbit)
+    fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC;
 #endif
 
   if (fixp->fx_subsy)
@@ -17162,15 +17221,12 @@ i386_validate_fix (fixS *fixp)
 	      if (!object_64bit)
 		abort ();
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-	      if (fixp->fx_tcbit2)
-		{
-		  if (fixp->fx_tcbit3)
-		    fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPCRELX;
-		  else
-		    fixp->fx_r_type = (fixp->fx_tcbit
-				       ? BFD_RELOC_X86_64_REX_GOTPCRELX
-				       : BFD_RELOC_X86_64_GOTPCRELX);
-		}
+	      if (fixp->fx_tcbit)
+		fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCRELX;
+	      else if (fixp->fx_tcbit2)
+		fixp->fx_r_type = BFD_RELOC_X86_64_REX_GOTPCRELX;
+	      else if (fixp->fx_tcbit3)
+		fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPCRELX;
 	      else
 #endif
 		fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
@@ -17296,6 +17352,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
     case BFD_RELOC_X86_64_DTPOFF64:
     case BFD_RELOC_X86_64_GOTTPOFF:
     case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
+    case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
     case BFD_RELOC_X86_64_TPOFF32:
     case BFD_RELOC_X86_64_TPOFF64:
     case BFD_RELOC_X86_64_GOTOFF64:
@@ -17440,6 +17497,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 	  case BFD_RELOC_X86_64_TLSLD:
 	  case BFD_RELOC_X86_64_GOTTPOFF:
 	  case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
+	  case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
 	  case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
 	  case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
 	  case BFD_RELOC_X86_64_TLSDESC_CALL:
diff --git a/gas/testsuite/gas/i386/x86-64-gottpoff.d b/gas/testsuite/gas/i386/x86-64-gottpoff.d
index d42abccc6d9..f2c039abe72 100644
--- a/gas/testsuite/gas/i386/x86-64-gottpoff.d
+++ b/gas/testsuite/gas/i386/x86-64-gottpoff.d
@@ -16,4 +16,8 @@ Disassembly of section .text:
  +[a-f0-9]+:	48 8b 05 00 00 00 00 	mov    0x0\(%rip\),%rax        # 2c <_start\+0x2c>	28: R_X86_64_GOTTPOFF	foo-0x4
  +[a-f0-9]+:	d5 48 03 05 00 00 00 00 	add    0x0\(%rip\),%r16        # 34 <_start\+0x34>	30: R_X86_64_CODE_4_GOTTPOFF	foo-0x4
  +[a-f0-9]+:	d5 48 8b 25 00 00 00 00 	mov    0x0\(%rip\),%r20        # 3c <_start\+0x3c>	38: R_X86_64_CODE_4_GOTTPOFF	foo-0x4
+ +[a-f0-9]+:	62 74 fc 10 01 05 00 00 00 00 	add    %r8,0x0\(%rip\),%r16        # 46 <_start\+0x46>	42: R_X86_64_CODE_6_GOTTPOFF	foo-0x4
+ +[a-f0-9]+:	62 f4 9c 18 03 05 00 00 00 00 	add    0x0\(%rip\),%rax,%r12        # 50 <_start\+0x50>	4c: R_X86_64_CODE_6_GOTTPOFF	foo-0x4
+ +[a-f0-9]+:	62 74 fc 10 01 05 00 00 00 00 	add    %r8,0x0\(%rip\),%r16        # 5a <_start\+0x5a>	56: R_X86_64_CODE_6_GOTTPOFF	foo-0x4
+ +[a-f0-9]+:	62 f4 9c 18 03 05 00 00 00 00 	add    0x0\(%rip\),%rax,%r12        # 64 <_start\+0x64>	60: R_X86_64_CODE_6_GOTTPOFF	foo-0x4
 #pass
diff --git a/gas/testsuite/gas/i386/x86-64-gottpoff.s b/gas/testsuite/gas/i386/x86-64-gottpoff.s
index 6f8f9d1480c..0335ec5debf 100644
--- a/gas/testsuite/gas/i386/x86-64-gottpoff.s
+++ b/gas/testsuite/gas/i386/x86-64-gottpoff.s
@@ -13,3 +13,13 @@ _start:
 
 	addq	r16, QWORD PTR [rip + foo@GOTTPOFF]
 	movq	r20, QWORD PTR [rip + foo@GOTTPOFF]
+
+	.att_syntax prefix
+
+	addq	%r8, foo@GOTTPOFF(%rip), %r16
+	addq	foo@GOTTPOFF(%rip), %rax, %r12
+
+	.intel_syntax noprefix
+
+	addq	r16, QWORD PTR [rip + foo@GOTTPOFF], r8
+	addq	r12, rax, QWORD PTR [rip + foo@GOTTPOFF]
diff --git a/gold/testsuite/x86_64_ie_to_le.s b/gold/testsuite/x86_64_ie_to_le.s
index c5752068866..bd0643dc87f 100644
--- a/gold/testsuite/x86_64_ie_to_le.s
+++ b/gold/testsuite/x86_64_ie_to_le.s
@@ -7,6 +7,8 @@ _start:
 	movq	foo@gottpoff(%rip), %rax
 	addq	foo@gottpoff(%rip), %r16
 	movq	foo@gottpoff(%rip), %r20
+	addq	%r30, foo@gottpoff(%rip), %r8
+	addq	foo@gottpoff(%rip), %rax, %r20
 	.size	_start, .-_start
 	.section	.tdata,"awT",@progbits
 	.align 4
diff --git a/gold/testsuite/x86_64_ie_to_le.sh b/gold/testsuite/x86_64_ie_to_le.sh
index 9d2e082f3e0..5308712ddbd 100755
--- a/gold/testsuite/x86_64_ie_to_le.sh
+++ b/gold/testsuite/x86_64_ie_to_le.sh
@@ -27,3 +27,5 @@ grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r12" x86_64_ie_to_le.stdout
 grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%rax" x86_64_ie_to_le.stdout
 grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r16" x86_64_ie_to_le.stdout
 grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%r20" x86_64_ie_to_le.stdout
+grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r30,%r8" x86_64_ie_to_le.stdout
+grep -q "add[ \t]\+\$0x[a-f0-9]\+,%rax,%r20" x86_64_ie_to_le.stdout
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 58e191a055a..f77430bfb3d 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -2920,6 +2920,11 @@ Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type,
       // Another Local-Dynamic reloc.
       return tls::TLSOPT_TO_LE;
 
+    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
+      if (r_offset <= 6 || *(reloc_view - 6) != 0x62)
+	return tls::TLSOPT_NONE;
+      goto handle_gottpoff;
+
     case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
       if (r_offset <= 4 || *(reloc_view - 4) != 0xd5)
 	return tls::TLSOPT_NONE;
@@ -2929,6 +2934,7 @@ Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type,
       // from the GOT.  If we know that we are linking against the
       // local symbol, we can switch to Local-Exec, which links the
       // thread offset into the instruction.
+handle_gottpoff:
       if (is_final)
 	return tls::TLSOPT_TO_LE;
       return tls::TLSOPT_NONE;
@@ -2997,6 +3003,7 @@ Target_x86_64<size>::Scan::get_reference_flags(unsigned int r_type)
     case elfcpp::R_X86_64_DTPOFF64:
     case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
     case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
+    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
     case elfcpp::R_X86_64_TPOFF32:          // Local-exec
       return Symbol::TLS_REF;
 
@@ -3362,6 +3369,7 @@ need_got:
       // These are initial tls relocs, which are expected when linking
     case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
     case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
+    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
       {
 	section_size_type stype;
 	reloc_view = object->section_contents(data_shndx, &stype, true);
@@ -3464,6 +3472,7 @@ need_got:
 
 	  case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
 	  case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
+	  case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
 	    layout->set_has_static_tls();
 	    if (optimized_type == tls::TLSOPT_NONE)
 	      {
@@ -3902,6 +3911,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
       // These are initial tls relocs, which are expected for global()
     case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
     case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
+    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
       {
 	section_size_type stype;
 	reloc_view = object->section_contents(data_shndx, &stype, true);
@@ -3920,7 +3930,8 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
 	// when building an executable.
 	const bool is_final = (gsym->final_value_is_known() ||
 			       ((r_type == elfcpp::R_X86_64_GOTTPOFF ||
-				 r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF) &&
+				 r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF||
+				 r_type == elfcpp::R_X86_64_CODE_6_GOTTPOFF) &&
 			        gsym->is_undefined() &&
 				parameters->options().output_is_executable()));
 	size_t r_offset = reloc.get_r_offset();
@@ -4006,6 +4017,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
 
 	  case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
 	  case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
+	  case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
 	    layout->set_has_static_tls();
 	    if (optimized_type == tls::TLSOPT_NONE)
 	      {
@@ -4608,6 +4620,7 @@ Target_x86_64<size>::Relocate::relocate(
     case elfcpp::R_X86_64_DTPOFF64:
     case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
     case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
+    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
     case elfcpp::R_X86_64_TPOFF32:          // Local-exec
       this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval,
 			 view, address, view_size);
@@ -4894,6 +4907,7 @@ Target_x86_64<size>::Relocate::relocate_tls(
 
     case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
     case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
+    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
       if (gsym != NULL
 	  && gsym->is_undefined()
 	  && parameters->options().output_is_executable())
@@ -5308,11 +5322,19 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
 
   // movq foo@gottpoff(%rip),%reg  ==>  movq $YY,%reg
   // addq foo@gottpoff(%rip),%reg  ==>  addq $YY,%reg
+  // addq %reg1,foo@gottpoff(%rip),%reg2  ==>  addq $YY,%reg1,%reg2
+  // addq foo@gottpoff(%rip),%reg1,%reg2  ==>  addq $YY,%reg1,%reg2
 
-  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
+  int off1;
+  if (r_type == elfcpp::R_X86_64_CODE_6_GOTTPOFF)
+    off1 = -5;
+  else
+    off1 = -3;
+
+  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, off1);
   tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
 
-  unsigned char op1 = view[-3];
+  unsigned char op1 = view[off1];
   unsigned char op2 = view[-2];
   unsigned char op3 = view[-1];
   unsigned char reg = op3 >> 3;
@@ -5350,7 +5372,7 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
 	  view[-1] = 0x80 | reg | (reg << 3);
 	}
     }
-  else
+  else if (r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF)
     {
       if (op2 == 0x8b)
 	op2 = 0xc7;
@@ -5362,6 +5384,23 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
       view[-2] = op2;
       view[-1] = 0xc0 | reg;
     }
+  else
+    {
+      unsigned char updated_op1 = op1;
+
+      // Set the R bits since they is inverted.
+      updated_op1 |= 1 << 7 | 1 << 4;
+
+      // Update the B bits from the R bits.
+      if ((op1 & (1 << 7)) == 0)
+	updated_op1 &= ~(1 << 5);
+      if ((op1 & (1 << 4)) == 0)
+	updated_op1 |= 1 << 3;
+
+      view[-5] = updated_op1;
+      view[-2] = 0x81;
+      view[-1] = 0xc0 | reg;
+    }
 
   if (tls_segment != NULL)
     value -= tls_segment->memsz();
diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h
index 33a824620a6..ea5036a8bbf 100644
--- a/include/elf/x86-64.h
+++ b/include/elf/x86-64.h
@@ -92,6 +92,26 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_type)
      /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
 	instruction starts at 4 bytes before the relocation offset.  */
      RELOC_NUMBER (R_X86_64_CODE_4_GOTPC32_TLSDESC, 45)
+     /* Load from 32 bit signed pc relative offset to GOT entry if the
+	instruction starts at 5 bytes before the relocation offset,
+	relaxable.  */
+     RELOC_NUMBER (R_X86_64_CODE_5_GOTPCRELX, 46)
+     /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
+	instruction starts at 5 bytes before the relocation offset.  */
+     RELOC_NUMBER (R_X86_64_CODE_5_GOTPC32_TLSDESC, 47)
+    /* PC relative offset to IE GOT entry if the instruction starts at
+       5 bytes before the relocation offset.  */
+     RELOC_NUMBER (R_X86_64_CODE_5_GOTTPOFF, 48)
+     /* Load from 32 bit signed pc relative offset to GOT entry if the
+	instruction starts at 6 bytes before the relocation offset,
+	relaxable.  */
+     RELOC_NUMBER (R_X86_64_CODE_6_GOTPCRELX, 49)
+    /* PC relative offset to IE GOT entry if the instruction starts at
+       6 bytes before the relocation offset.  */
+     RELOC_NUMBER (R_X86_64_CODE_6_GOTTPOFF, 50)
+     /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
+	instruction starts at 6 bytes before the relocation offset.  */
+     RELOC_NUMBER (R_X86_64_CODE_6_GOTPC32_TLSDESC, 51)
      RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250)       /* GNU C++ hack  */
      RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251)         /* GNU C++ hack  */
 END_RELOC_NUMBERS (R_X86_64_max)
diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.dd b/ld/testsuite/ld-x86-64/tlsbindesc.dd
index 4587cc751b4..be89f38199d 100644
--- a/ld/testsuite/ld-x86-64/tlsbindesc.dd
+++ b/ld/testsuite/ld-x86-64/tlsbindesc.dd
@@ -169,18 +169,42 @@ Disassembly of section .text:
  +[0-9a-f]+:	d5 48 03 05 ([0-9a-f]{2} ){3}[ 	]+add    0x[0-9a-f]+\(%rip\),%r16 +# [0-9a-f]+ <sG2>
 #				-> R_X86_64_TPOFF64	sG2
  +[0-9a-f]+:	00 *
+ +[0-9a-f]+:	62 f4 fc 10 01 ([0-9a-f]{2} ){2}[ 	]+add    %rax,0x[0-9a-f]+\(%rip\),%r16 +# [0-9a-f]+ <sG2>
+#				-> R_X86_64_TPOFF64	sG2
+ +[0-9a-f]+:	([0-9a-f]{2} ){3} *
+ +[0-9a-f]+:	62 f4 fc 10 03 ([0-9a-f]{2} ){2}[ 	]+add    0x[0-9a-f]+\(%rip\),%rax,%r16 +# [0-9a-f]+ <sG2>
+#				-> R_X86_64_TPOFF64	sG2
+ +[0-9a-f]+:	([0-9a-f]{2} ){3} *
 #  IE -> LE against global var defined in exec
  +[0-9a-f]+:	d5 18 81 c1 60 ff ff[ 	]+add    \$0xf+60,%r17
 #							sg1
  +[0-9a-f]+:	ff *
+ +[0-9a-f]+:	62 d4 f4 10 81 ([0-9a-f]{2} ){2}[ 	]+add    \$0x[0-9a-f]+,%r8,%r17
+#							sg1
+ +[0-9a-f]+:	ff ff ff *
+ +[0-9a-f]+:	62 d4 f4 10 81 ([0-9a-f]{2} ){2}[ 	]+add    \$0x[0-9a-f]+,%r8,%r17
+#							sg1
+ +[0-9a-f]+:	ff ff ff *
 #  IE -> LE against local var
  +[0-9a-f]+:	d5 18 81 c2 80 ff ff[ 	]+add    \$0xf+80,%r18
 #							sl1
  +[0-9a-f]+:	ff *
+ +[0-9a-f]+:	62 d4 fc 18 81 ([0-9a-f]{2} ){2}[ 	]+add    \$0x[0-9a-f]+,%r8,%rax
+#							sl1
+ +[0-9a-f]+:	ff ff ff *
+ +[0-9a-f]+:	62 d4 fc 18 81 ([0-9a-f]{2} ){2}[ 	]+add    \$0x[0-9a-f]+,%r8,%rax
+#							sl1
+ +[0-9a-f]+:	ff ff ff *
 #  IE -> LE against hidden var
  +[0-9a-f]+:	d5 18 81 c3 a0 ff ff[ 	]+add    \$0xf+a0,%r19
 #							sh1
  +[0-9a-f]+:	ff *
+ +[0-9a-f]+:	62 fc bc 18 81 ([0-9a-f]{2} ){2}[ 	]+add    \$0x[0-9a-f]+,%r19,%r8
+#							sh1
+ +[0-9a-f]+:	ff ff ff *
+ +[0-9a-f]+:	62 fc bc 18 81 ([0-9a-f]{2} ){2}[ 	]+add    \$0x[0-9a-f]+,%r19,%r8
+#							sh1
+ +[0-9a-f]+:	ff ff ff *
 #  Direct access through %fs
 #  IE against global var
  +[0-9a-f]+:	d5 48 8b 25 ([0-9a-f]{2} ){3}[ 	]+mov    0x[0-9a-f]+\(%rip\),%r20 +# [0-9a-f]+ <sG5>
diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.rd b/ld/testsuite/ld-x86-64/tlsbindesc.rd
index daaea7a5371..59325b04e19 100644
--- a/ld/testsuite/ld-x86-64/tlsbindesc.rd
+++ b/ld/testsuite/ld-x86-64/tlsbindesc.rd
@@ -15,12 +15,12 @@ Section Headers:
  +\[[ 0-9]+\] .dynsym +.*
  +\[[ 0-9]+\] .dynstr +.*
  +\[[ 0-9]+\] .rela.dyn +.*
- +\[[ 0-9]+\] .text +PROGBITS +0+401000 0+1000 0+25d 00 +AX +0 +0 +4096
- +\[[ 0-9]+\] .tdata +PROGBITS +0+60125d 0+125d 0+60 00 WAT +0 +0 +1
- +\[[ 0-9]+\] .tbss +NOBITS +0+6012bd 0+12bd 0+40 00 WAT +0 +0 +1
- +\[[ 0-9]+\] .dynamic +DYNAMIC +0+6012c0 0+12c0 0+100 10 +WA +4 +0 +8
- +\[[ 0-9]+\] .got +PROGBITS +0+6013c0 0+13c0 0+20 08 +WA +0 +0 +8
- +\[[ 0-9]+\] .got.plt +PROGBITS +0+6013e0 0+13e0 0+18 08 +WA +0 +0 +8
+ +\[[ 0-9]+\] .text +PROGBITS +0+401000 0+1000 0+2ad 00 +AX +0 +0 +4096
+ +\[[ 0-9]+\] .tdata +PROGBITS +0+6012ad 0+12ad 0+60 00 WAT +0 +0 +1
+ +\[[ 0-9]+\] .tbss +NOBITS +0+60130d 0+130d 0+40 00 WAT +0 +0 +1
+ +\[[ 0-9]+\] .dynamic +DYNAMIC +0+601310 0+1310 0+100 10 +WA +4 +0 +8
+ +\[[ 0-9]+\] .got +PROGBITS +0+601410 0+1410 0+20 08 +WA +0 +0 +8
+ +\[[ 0-9]+\] .got.plt +PROGBITS +0+601430 0+1430 0+18 08 +WA +0 +0 +8
  +\[[ 0-9]+\] .symtab +.*
  +\[[ 0-9]+\] .strtab +.*
  +\[[ 0-9]+\] .shstrtab +.*
@@ -28,7 +28,7 @@ Key to Flags:
 #...
 
 Elf file type is EXEC \(Executable file\)
-Entry point 0x401165
+Entry point 0x4011b5
 There are [0-9]+ program headers, starting at offset [0-9]+
 
 Program Headers:
@@ -36,10 +36,10 @@ Program Headers:
  +PHDR.*
  +INTERP.*
 .*Requesting program interpreter.*
- +LOAD +0x0+ 0x0+400000 0x0+400000 0x0+125d 0x0+125d R E 0x200000
- +LOAD +0x0+125d 0x0+60125d 0x0+60125d 0x0+19b 0x0+19b RW +0x200000
- +DYNAMIC +0x0+12c0 0x0+6012c0 0x0+6012c0 0x0+100 0x0+100 RW +0x8
- +TLS +0x0+125d 0x0+60125d 0x0+60125d 0x0+60 0x0+a0 R +0x1
+ +LOAD +0x0+ 0x0+400000 0x0+400000 0x0+12ad 0x0+12ad R E 0x200000
+ +LOAD +0x0+12ad 0x0+6012ad 0x0+6012ad 0x0+19b 0x0+19b RW +0x200000
+ +DYNAMIC +0x0+1310 0x0+601310 0x0+601310 0x0+100 0x0+100 RW +0x8
+ +TLS +0x0+12ad 0x0+6012ad 0x0+6012ad 0x0+60 0x0+a0 R +0x1
 
  Section to Segment mapping:
  +Segment Sections...
@@ -52,10 +52,10 @@ Program Headers:
 
 Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 4 entries:
  +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
-0+6013c0 +0+100000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
-0+6013c8 +0+200000012 R_X86_64_TPOFF64 +0+ sG2 \+ 0
-0+6013d0 +0+300000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
-0+6013d8 +0+400000012 R_X86_64_TPOFF64 +0+ sG1 \+ 0
+0+601410 +0+100000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
+0+601418 +0+200000012 R_X86_64_TPOFF64 +0+ sG2 \+ 0
+0+601420 +0+300000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
+0+601428 +0+400000012 R_X86_64_TPOFF64 +0+ sG1 \+ 0
 
 Symbol table '\.dynsym' contains [0-9]+ entries:
  +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
@@ -88,8 +88,8 @@ Symbol table '\.symtab' contains [0-9]+ entries:
  +[0-9]+: 0+9c +0 +TLS +LOCAL +DEFAULT +8 bl8
 .* FILE +LOCAL +DEFAULT +ABS 
  +[0-9]+: 0+a0 +0 +TLS +LOCAL +DEFAULT +7 _TLS_MODULE_BASE_
- +[0-9]+: 0+6012c0 +0 +OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
- +[0-9]+: 0+6013e0 +0 +OBJECT +LOCAL +DEFAULT +11 _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+601310 +0 +OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
+ +[0-9]+: 0+601430 +0 +OBJECT +LOCAL +DEFAULT +11 _GLOBAL_OFFSET_TABLE_
  +[0-9]+: 0+1c +0 +TLS +GLOBAL +DEFAULT +7 sg8
  +[0-9]+: 0+7c +0 +TLS +GLOBAL +DEFAULT +8 bg8
  +[0-9]+: 0+74 +0 +TLS +GLOBAL +DEFAULT +8 bg6
@@ -104,7 +104,7 @@ Symbol table '\.symtab' contains [0-9]+ entries:
  +[0-9]+: 0+58 +0 +TLS +GLOBAL +HIDDEN +7 sh7
  +[0-9]+: 0+5c +0 +TLS +GLOBAL +HIDDEN +7 sh8
  +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +7 sg1
- +[0-9]+: 0+401165 +0 +FUNC +GLOBAL +DEFAULT +6 _start
+ +[0-9]+: 0+4011b5 +0 +FUNC +GLOBAL +DEFAULT +6 _start
  +[0-9]+: 0+4c +0 +TLS +GLOBAL +HIDDEN +7 sh4
  +[0-9]+: 0+78 +0 +TLS +GLOBAL +DEFAULT +8 bg7
  +[0-9]+: 0+50 +0 +TLS +GLOBAL +HIDDEN +7 sh5
diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.s b/ld/testsuite/ld-x86-64/tlsbindesc.s
index b80e5f192c0..4747fc1bc30 100644
--- a/ld/testsuite/ld-x86-64/tlsbindesc.s
+++ b/ld/testsuite/ld-x86-64/tlsbindesc.s
@@ -129,15 +129,23 @@ fn2:
 
 	/* IE against global var  */
 	addq	sG2@gottpoff(%rip), %r16
+	addq	%rax, sG2@gottpoff(%rip), %r16
+	addq	sG2@gottpoff(%rip), %rax, %r16
 
 	/* IE -> LE against global var defined in exec */
 	addq	sg1@gottpoff(%rip), %r17
+	addq	%r8, sg1@gottpoff(%rip), %r17
+	addq	sg1@gottpoff(%rip), %r8, %r17
 
 	/* IE -> LE against local var */
 	addq	sl1@gottpoff(%rip), %r18
+	addq	%r8, sl1@gottpoff(%rip), %rax
+	addq	sl1@gottpoff(%rip), %r8, %rax
 
 	/* IE -> LE against hidden var */
 	addq	sh1@gottpoff(%rip), %r19
+	addq	%r19, sh1@gottpoff(%rip), %r8
+	addq	sh1@gottpoff(%rip), %r19, %r8
 
 	/* Direct access through %fs  */
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] x86-64: Add R_X86_64_CODE_6_GOTTPOFF
  2024-02-07 12:42 [PATCH v2] x86-64: Add R_X86_64_CODE_6_GOTTPOFF H.J. Lu
@ 2024-02-08 11:41 ` H.J. Lu
  2024-02-10 16:22   ` H.J. Lu
  0 siblings, 1 reply; 3+ messages in thread
From: H.J. Lu @ 2024-02-08 11:41 UTC (permalink / raw)
  To: binutils

On Wed, Feb 7, 2024 at 4:42 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> Changes in v2:
>
> Rewrite fx_tcbit, fx_tcbit2 and fx_tcbit3 usage to generate
> R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX,
> R_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTPC32_TLSDESC and
> R_X86_64_CODE_6_GOTTPOFF.
>
> ---
> For
>
>         add     %reg1, name@gottpoff(%rip), %reg2
>         add     name@gottpoff(%rip), %reg1, %reg2
>
> add
>
>  #define R_X86_64_CODE_6_GOTTPOFF               50
>
> if the instruction starts at 6 bytes before the relocation offset.
> They are similar to R_X86_64_GOTTPOFF.  Linker can covert GOTTPOFF to
>
>         add     $name@tpoff, %reg1, %reg2
>
> Rewrite fx_tcbit, fx_tcbit2 and fx_tcbit3 usage to generate
> R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX,
> R_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTPC32_TLSDESC and
> R_X86_64_CODE_6_GOTTPOFF.
>
> NB: There is no need to check BFD_RELOC_X86_64_CODE_4_GOTTPOFF in
> md_assemble since there is only BFD_RELOC_X86_64_GOTTPOFF at this
> stage, which will be converted to BFD_RELOC_X86_64_CODE_4_GOTTPOFF
> or BFD_RELOC_X86_64_CODE_6_GOTTPOFF in i386_validate_fix.
>
> 5 relocations:
>
>  #define R_X86_64_CODE_5_GOTPCRELX              46
>  #define R_X86_64_CODE_5_GOTTPOFF               47
>  #define R_X86_64_CODE_5_GOTPC32_TLSDESC        48
>  #define R_X86_64_CODE_6_GOTPCRELX              49
>  #define R_X86_64_CODE_6_GOTPC32_TLSDESC        51
>
> are added for completeness and they are unused.
>
> bfd/
>
>         * elf64-x86-64.c (x86_64_elf_howto_table): Add
>         R_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTTPOFF,
>         R_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPCRELX,
>         R_X86_64_CODE_6_GOTTPOFF and R_X86_64_CODE_6_GOTPC32_TLSDESC.
>         (R_X86_64_standard): Updated.
>         (x86_64_reloc_map): Add R_X86_64_CODE_5_GOTPCRELX,
>         R_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTPC32_TLSDESC,
>         R_X86_64_CODE_6_GOTPCRELX, R_X86_64_CODE_6_GOTTPOFF and
>         R_X86_64_CODE_6_GOTPC32_TLSDESC.
>         (elf_x86_64_check_tls_transition): Handle
>         R_X86_64_CODE_6_GOTTPOFF.
>         (elf_x86_64_tls_transition): Likewise.
>         (elf_x86_64_scan_relocs): Handle R_X86_64_CODE_6_GOTTPOFF.
>         Issue an error for R_X86_64_CODE_5_GOTPCRELX,
>         R_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTPC32_TLSDESC,
>         R_X86_64_CODE_6_GOTPCRELX and R_X86_64_CODE_6_GOTPC32_TLSDESC.
>         (elf_x86_64_relocate_section): Handle R_X86_64_CODE_6_GOTTPOFF.
>         * reloc.c (bfd_reloc_code_real): Add
>         BFD_RELOC_X86_64_CODE_5_GOTPCRELX,
>         BFD_RELOC_X86_64_CODE_5_GOTTPOFF,
>         BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC,
>         BFD_RELOC_X86_64_CODE_6_GOTPCRELX,
>         BFD_RELOC_X86_64_CODE_6_GOTTPOFF and
>         BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC.
>         * bfd-in2.h: Regenerated.
>         * libbfd.h: Likewise.
>
> elfcpp/
>
>         * x86_64.h (R_X86_64_CODE_5_GOTPCRELX): New.
>         (R_X86_64_CODE_5_GOTTPOFF): Likewise.
>         (R_X86_64_CODE_5_GOTPC32_TLSDESC): Likewise.
>         (R_X86_64_CODE_6_GOTPCRELX): Likewise.
>         (R_X86_64_CODE_6_GOTTPOFF): Likewise.
>         (R_X86_64_CODE_6_GOTPC32_TLSDESC): Likewise.
>
> gas/
>
>         * config/tc-i386.c (tc_i386_fix_adjustable): Handle
>         BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
>         (md_assemble): Don't check BFD_RELOC_X86_64_CODE_4_GOTTPOFF.
>         Allow "add %reg1, foo@gottpoff(%rip), %reg2".
>         (output_disp): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.  Rewrite
>         setting fx_tcbitX bits for BFD_RELOC_X86_64_GOTTPOFF,
>         BFD_RELOC_X86_64_GOTPC32_TLSDESC and BFD_RELOC_32_PCREL.
>         (md_apply_fix): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
>         (i386_validate_fix): Rewrite fx_tcbitX bit checking for
>         BFD_RELOC_X86_64_GOTTPOFF, BFD_RELOC_X86_64_GOTPC32_TLSDESC and
>         BFD_RELOC_32_PCREL.
>         (tc_gen_reloc): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
>         * testsuite/gas/i386/x86-64-gottpoff.d: Updated.
>         * testsuite/gas/i386/x86-64-gottpoff.s: Add tests for
>         "add %reg1, foo@gottpoff(%rip), %reg2" and
>         "add foo@gottpoff(%rip), %reg, %reg2".
>
> gold/
>
>         * x86_64.cc (Target_x86_64::optimize_tls_reloc): Handle
>         R_X86_64_CODE_6_GOTTPOFF.
>         (Target_x86_64::Scan::get_reference_flags): Likewise.
>         (Target_x86_64::Scan::local): Likewise.
>         (Target_x86_64::Scan::global): Likewise.
>         (Target_x86_64::Relocate::relocate): Likewise.
>         (Target_x86_64::Relocate::relocate_tls): Likewise.
>         (Target_x86_64::Relocate::tls_ie_to_le): Handle.
>         R_X86_64_CODE_6_GOTTPOFF.
>         * testsuite/x86_64_ie_to_le.s: Add tests for
>         "add %reg1, foo@gottpoff(%rip), %reg2" and
>         "add foo@gottpoff(%rip), %reg, %reg2".
>         * testsuite/x86_64_ie_to_le.sh: Updated.
>
> include/
>
>         * elf/x86-64.h (elf_x86_64_reloc_type): Add
>         R_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTTPOFF,
>         R_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPCRELX,
>         R_X86_64_CODE_6_GOTTPOFF and R_X86_64_CODE_6_GOTPC32_TLSDESC.
>
> ld/
>
>         * testsuite/ld-x86-64/tlsbindesc.s: Add R_X86_64_CODE_6_GOTTPOFF
>         tests.
>         * testsuite/ld-x86-64/tlsbindesc.d: Updated.
>         * testsuite/ld-x86-64/tlsbindesc.rd: Likewise.
> ---
>  bfd/bfd-in2.h                            |   6 ++
>  bfd/elf64-x86-64.c                       | 113 ++++++++++++++++++++++-
>  bfd/libbfd.h                             |   6 ++
>  bfd/reloc.c                              |  12 +++
>  elfcpp/x86_64.h                          |  24 +++++
>  gas/config/tc-i386.c                     | 102 +++++++++++++++-----
>  gas/testsuite/gas/i386/x86-64-gottpoff.d |   4 +
>  gas/testsuite/gas/i386/x86-64-gottpoff.s |  10 ++
>  gold/testsuite/x86_64_ie_to_le.s         |   2 +
>  gold/testsuite/x86_64_ie_to_le.sh        |   2 +
>  gold/x86_64.cc                           |  47 +++++++++-
>  include/elf/x86-64.h                     |  20 ++++
>  ld/testsuite/ld-x86-64/tlsbindesc.dd     |  24 +++++
>  ld/testsuite/ld-x86-64/tlsbindesc.rd     |  36 ++++----
>  ld/testsuite/ld-x86-64/tlsbindesc.s      |   8 ++
>  15 files changed, 371 insertions(+), 45 deletions(-)
>
> diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> index 581d8fe0b3e..dbafcf8da36 100644
> --- a/bfd/bfd-in2.h
> +++ b/bfd/bfd-in2.h
> @@ -3894,6 +3894,12 @@ enum bfd_reloc_code_real
>    BFD_RELOC_X86_64_CODE_4_GOTPCRELX,
>    BFD_RELOC_X86_64_CODE_4_GOTTPOFF,
>    BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC,
> +  BFD_RELOC_X86_64_CODE_5_GOTPCRELX,
> +  BFD_RELOC_X86_64_CODE_5_GOTTPOFF,
> +  BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC,
> +  BFD_RELOC_X86_64_CODE_6_GOTPCRELX,
> +  BFD_RELOC_X86_64_CODE_6_GOTTPOFF,
> +  BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC,
>
>    /* ns32k relocations.  */
>    BFD_RELOC_NS32K_IMM_8,
> diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
> index f1253751bbd..2ed120af780 100644
> --- a/bfd/elf64-x86-64.c
> +++ b/bfd/elf64-x86-64.c
> @@ -179,12 +179,30 @@ static reloc_howto_type x86_64_elf_howto_table[] =
>    HOWTO(R_X86_64_CODE_4_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
>         complain_overflow_bitfield, bfd_elf_generic_reloc,
>         "R_X86_64_CODE_4_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
> +  HOWTO(R_X86_64_CODE_5_GOTPCRELX, 0, 4, 32, true, 0,
> +       complain_overflow_signed, bfd_elf_generic_reloc,
> +       "R_X86_64_CODE_5_GOTPCRELX", false, 0, 0xffffffff, true),
> +  HOWTO(R_X86_64_CODE_5_GOTTPOFF, 0, 4, 32, true, 0,
> +       complain_overflow_signed, bfd_elf_generic_reloc,
> +       "R_X86_64_CODE_5_GOTTPOFF", false, 0, 0xffffffff, true),
> +  HOWTO(R_X86_64_CODE_5_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
> +       complain_overflow_bitfield, bfd_elf_generic_reloc,
> +       "R_X86_64_CODE_5_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
> +  HOWTO(R_X86_64_CODE_6_GOTPCRELX, 0, 4, 32, true, 0,
> +       complain_overflow_signed, bfd_elf_generic_reloc,
> +       "R_X86_64_CODE_6_GOTPCRELX", false, 0, 0xffffffff, true),
> +  HOWTO(R_X86_64_CODE_6_GOTTPOFF, 0, 4, 32, true, 0,
> +       complain_overflow_signed, bfd_elf_generic_reloc,
> +       "R_X86_64_CODE_6_GOTTPOFF", false, 0, 0xffffffff, true),
> +  HOWTO(R_X86_64_CODE_6_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
> +       complain_overflow_bitfield, bfd_elf_generic_reloc,
> +       "R_X86_64_CODE_6_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
>
>    /* We have a gap in the reloc numbers here.
>       R_X86_64_standard counts the number up to this point, and
>       R_X86_64_vt_offset is the value to subtract from a reloc type of
>       R_X86_64_GNU_VT* to form an index into this table.  */
> -#define R_X86_64_standard (R_X86_64_CODE_4_GOTPC32_TLSDESC + 1)
> +#define R_X86_64_standard (R_X86_64_CODE_6_GOTPC32_TLSDESC + 1)
>  #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
>
>  /* GNU extension to record C++ vtable hierarchy.  */
> @@ -256,6 +274,12 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
>    { BFD_RELOC_X86_64_CODE_4_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX, },
>    { BFD_RELOC_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTTPOFF, },
>    { BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC, R_X86_64_CODE_4_GOTPC32_TLSDESC, },
> +  { BFD_RELOC_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTPCRELX, },
> +  { BFD_RELOC_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTTPOFF, },
> +  { BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_5_GOTPC32_TLSDESC, },
> +  { BFD_RELOC_X86_64_CODE_6_GOTPCRELX, R_X86_64_CODE_6_GOTPCRELX, },
> +  { BFD_RELOC_X86_64_CODE_6_GOTTPOFF, R_X86_64_CODE_6_GOTTPOFF, },
> +  { BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPC32_TLSDESC, },
>    { BFD_RELOC_VTABLE_INHERIT,  R_X86_64_GNU_VTINHERIT, },
>    { BFD_RELOC_VTABLE_ENTRY,    R_X86_64_GNU_VTENTRY, },
>  };
> @@ -1283,6 +1307,23 @@ elf_x86_64_check_tls_transition (bfd *abfd,
>
>        goto check_gottpoff;
>
> +    case R_X86_64_CODE_6_GOTTPOFF:
> +      /* Check transition from IE access model:
> +               add %reg1, foo@gottpoff(%rip), %reg2
> +               where reg1/reg2 are one of r16 to r31.  */
> +
> +      if (offset < 6
> +         || (offset + 4) > sec->size
> +         || contents[offset - 6] != 0x62)
> +       return false;
> +
> +      val = bfd_get_8 (abfd, contents + offset - 2);
> +      if (val != 0x01 && val != 0x03)
> +       return false;
> +
> +      val = bfd_get_8 (abfd, contents + offset - 1);
> +      return (val & 0xc7) == 5;
> +
>      case R_X86_64_GOTTPOFF:
>        /* Check transition from IE access model:
>                 mov foo@gottpoff(%rip), %reg
> @@ -1417,6 +1458,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
>      case R_X86_64_TLSDESC_CALL:
>      case R_X86_64_GOTTPOFF:
>      case R_X86_64_CODE_4_GOTTPOFF:
> +    case R_X86_64_CODE_6_GOTTPOFF:
>        if (bfd_link_executable (info))
>         {
>           if (h == NULL)
> @@ -1464,6 +1506,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
>    /* Return TRUE if there is no transition.  */
>    if (from_type == to_type
>        || (from_type == R_X86_64_CODE_4_GOTTPOFF
> +         && to_type == R_X86_64_GOTTPOFF)
> +      || (from_type == R_X86_64_CODE_6_GOTTPOFF
>           && to_type == R_X86_64_GOTTPOFF))
>      return true;
>
> @@ -2177,6 +2221,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
>
>         case R_X86_64_GOTTPOFF:
>         case R_X86_64_CODE_4_GOTTPOFF:
> +       case R_X86_64_CODE_6_GOTTPOFF:
>           if (!bfd_link_executable (info))
>             info->flags |= DF_STATIC_TLS;
>           /* Fall through */
> @@ -2214,6 +2259,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
>                 break;
>               case R_X86_64_GOTTPOFF:
>               case R_X86_64_CODE_4_GOTTPOFF:
> +             case R_X86_64_CODE_6_GOTTPOFF:
>                 tls_type = GOT_TLS_IE;
>                 break;
>               case R_X86_64_GOTPC32_TLSDESC:
> @@ -2503,6 +2549,26 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
>             }
>           break;
>
> +       case R_X86_64_CODE_5_GOTPCRELX:
> +       case R_X86_64_CODE_5_GOTTPOFF:
> +       case R_X86_64_CODE_5_GOTPC32_TLSDESC:
> +       case R_X86_64_CODE_6_GOTPCRELX:
> +       case R_X86_64_CODE_6_GOTPC32_TLSDESC:
> +           {
> +             /* These relocations are added only for completeness and
> +                aren't be used.  */
> +             if (h)
> +               name = h->root.root.string;
> +             else
> +               name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
> +                                        NULL);
> +             _bfd_error_handler
> +               /* xgettext:c-format */
> +               (_("%pB: unsupported relocation %s against symbol `%s'"),
> +                abfd, x86_64_elf_howto_table[r_type].name, name);
> +           }
> +         break;
> +
>           /* This relocation describes the C++ object vtable hierarchy.
>              Reconstruct it for later use during GC.  */
>         case R_X86_64_GNU_VTINHERIT:
> @@ -3570,6 +3636,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
>         case R_X86_64_TLSDESC_CALL:
>         case R_X86_64_GOTTPOFF:
>         case R_X86_64_CODE_4_GOTTPOFF:
> +       case R_X86_64_CODE_6_GOTTPOFF:
>           tls_type = GOT_UNKNOWN;
>           if (h == NULL && local_got_offsets)
>             tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
> @@ -3920,6 +3987,50 @@ elf_x86_64_relocate_section (bfd *output_bfd,
>                               contents + roff);
>                   continue;
>                 }
> +             else if (r_type == R_X86_64_CODE_6_GOTTPOFF)
> +               {
> +                 /* IE->LE transition:
> +                    Originally it is
> +                    add %reg1, foo@gottpoff(%rip), %reg2
> +                    or
> +                    add foo@gottpoff(%rip), %reg1, %reg2
> +                    We change it into:
> +                    add $foo@tpoff, %reg1, %reg2
> +                  */
> +                 unsigned int reg, byte1;
> +                 unsigned int updated_byte1;
> +
> +                 if (roff < 6)
> +                   goto corrupt_input;
> +
> +                 /* Move the R bits to the B bits in EVEX payload
> +                    byte 1.  */
> +                 byte1 = bfd_get_8 (input_bfd, contents + roff - 5);
> +                 updated_byte1 = byte1;
> +
> +                 /* Set the R bits since they is inverted.  */
> +                 updated_byte1 |= 1 << 7 | 1 << 4;
> +
> +                 /* Update the B bits from the R bits.  */
> +                 if ((byte1 & (1 << 7)) == 0)
> +                   updated_byte1 &= ~(1 << 5);
> +                 if ((byte1 & (1 << 4)) == 0)
> +                   updated_byte1 |= 1 << 3;
> +
> +                 reg = bfd_get_8 (input_bfd, contents + roff - 1);
> +                 reg >>= 3;
> +
> +                 bfd_put_8 (output_bfd, updated_byte1,
> +                            contents + roff - 5);
> +                 bfd_put_8 (output_bfd, 0x81,
> +                            contents + roff - 2);
> +                 bfd_put_8 (output_bfd, 0xc0 | reg,
> +                            contents + roff - 1);
> +                 bfd_put_32 (output_bfd,
> +                             elf_x86_64_tpoff (info, relocation),
> +                             contents + roff);
> +                 continue;
> +               }
>               else
>                 BFD_ASSERT (false);
>             }
> diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> index ebd4f24149b..40bbe6a3886 100644
> --- a/bfd/libbfd.h
> +++ b/bfd/libbfd.h
> @@ -1463,6 +1463,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
>    "BFD_RELOC_X86_64_CODE_4_GOTPCRELX",
>    "BFD_RELOC_X86_64_CODE_4_GOTTPOFF",
>    "BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC",
> +  "BFD_RELOC_X86_64_CODE_5_GOTPCRELX",
> +  "BFD_RELOC_X86_64_CODE_5_GOTTPOFF",
> +  "BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC",
> +  "BFD_RELOC_X86_64_CODE_6_GOTPCRELX",
> +  "BFD_RELOC_X86_64_CODE_6_GOTTPOFF",
> +  "BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC",
>    "BFD_RELOC_NS32K_IMM_8",
>    "BFD_RELOC_NS32K_IMM_16",
>    "BFD_RELOC_NS32K_IMM_32",
> diff --git a/bfd/reloc.c b/bfd/reloc.c
> index e74cbd75e96..7583b7fd552 100644
> --- a/bfd/reloc.c
> +++ b/bfd/reloc.c
> @@ -2481,6 +2481,18 @@ ENUMX
>    BFD_RELOC_X86_64_CODE_4_GOTTPOFF
>  ENUMX
>    BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC
> +ENUMX
> +  BFD_RELOC_X86_64_CODE_5_GOTPCRELX
> +ENUMX
> +  BFD_RELOC_X86_64_CODE_5_GOTTPOFF
> +ENUMX
> +  BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC
> +ENUMX
> +  BFD_RELOC_X86_64_CODE_6_GOTPCRELX
> +ENUMX
> +  BFD_RELOC_X86_64_CODE_6_GOTTPOFF
> +ENUMX
> +  BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC
>  ENUMDOC
>    x86-64/elf relocations.
>
> diff --git a/elfcpp/x86_64.h b/elfcpp/x86_64.h
> index 135f339fccf..5d254ce483b 100644
> --- a/elfcpp/x86_64.h
> +++ b/elfcpp/x86_64.h
> @@ -110,6 +110,30 @@ enum
>                                         // descriptor in GOT if the
>                                         // instruction starts at 4 bytes
>                                         // before the relocation offset.
> +  R_X86_64_CODE_5_GOTPCRELX = 46, // 32 bit signed PC relative offset to
> +                                 // GOT if the instruction starts at 5
> +                                 // bytes before the relocation offset,
> +                                 // relaxable.
> +  R_X86_64_CODE_5_GOTTPOFF = 47,  // 32 bit signed PC relative offset to
> +                                 // GOT entry for IE symbol if the
> +                                 // instruction starts at 5 bytes before
> +                                 // the relocation offset.
> +  R_X86_64_CODE_5_GOTPC32_TLSDESC = 48, // 32-bit PC relative to TLS
> +                                       // descriptor in GOT if the
> +                                       // instruction starts at 5 bytes
> +                                       // before the relocation offset.
> +  R_X86_64_CODE_6_GOTPCRELX = 49, // 32 bit signed PC relative offset to
> +                                 // GOT if the instruction starts at 6
> +                                 // bytes before the relocation offset,
> +                                 // relaxable.
> +  R_X86_64_CODE_6_GOTTPOFF = 50,  // 32 bit signed PC relative offset to
> +                                 // GOT entry for IE symbol if the
> +                                 // instruction starts at 6 bytes before
> +                                 // the relocation offset.
> +  R_X86_64_CODE_6_GOTPC32_TLSDESC = 51, // 32-bit PC relative to TLS
> +                                       // descriptor in GOT if the
> +                                       // instruction starts at 6 bytes
> +                                       // before the relocation offset.
>    // GNU vtable garbage collection extensions.
>    R_X86_64_GNU_VTINHERIT = 250,
>    R_X86_64_GNU_VTENTRY = 251
> diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
> index 50d890c4481..9e7bb1dd4d6 100644
> --- a/gas/config/tc-i386.c
> +++ b/gas/config/tc-i386.c
> @@ -3648,6 +3648,7 @@ tc_i386_fix_adjustable (fixS *fixP)
>        || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64
>        || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF
>        || fixP->fx_r_type == BFD_RELOC_X86_64_CODE_4_GOTTPOFF
> +      || fixP->fx_r_type == BFD_RELOC_X86_64_CODE_6_GOTTPOFF
>        || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
>        || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64
>        || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64
> @@ -6795,10 +6796,19 @@ md_assemble (char *line)
>        for (j = i.imm_operands; j < i.operands; ++j)
>         switch (i.reloc[j])
>           {
> +         case BFD_RELOC_X86_64_GOTTPOFF:
> +           if (i.tm.mnem_off == MN_add
> +               && i.tm.opcode_space == SPACE_EVEXMAP4
> +               && i.mem_operands == 1
> +               && i.base_reg
> +               && i.base_reg->reg_num == RegIP
> +               && i.tm.operand_types[0].bitfield.class == Reg
> +               && i.tm.operand_types[2].bitfield.class == Reg)
> +             /* Allow APX: add %reg1, foo@gottpoff(%rip), %reg2.  */
> +             break;
> +           /* Fall through.  */
>           case BFD_RELOC_386_TLS_GOTIE:
>           case BFD_RELOC_386_TLS_LE_32:
> -         case BFD_RELOC_X86_64_GOTTPOFF:
> -         case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
>           case BFD_RELOC_X86_64_TLSLD:
>             as_bad (_("TLS relocation cannot be used with `%s'"), insn_name (&i.tm));
>             return;
> @@ -12040,6 +12050,7 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
>                     case BFD_RELOC_X86_64_TLSLD:
>                     case BFD_RELOC_X86_64_GOTTPOFF:
>                     case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> +                   case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
>                     case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
>                     case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
>                     case BFD_RELOC_X86_64_TLSDESC_CALL:
> @@ -12056,9 +12067,30 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
>                   && !i.prefix[ADDR_PREFIX])
>                 fixP->fx_signed = 1;
>
> -             /* Set fx_tcbit3 for REX2 prefix.  */
> -             if (is_apx_rex2_encoding ())
> -               fixP->fx_tcbit3 = 1;
> +             if (reloc_type == BFD_RELOC_X86_64_GOTTPOFF
> +                 && i.tm.opcode_space == SPACE_EVEXMAP4)
> +               {
> +                 /* Only "add %reg1, foo@gottpoff(%rip), %reg2" is
> +                    allowed in md_assemble.  Set fx_tcbit2 for EVEX
> +                    prefix.  */
> +                 fixP->fx_tcbit2 = 1;
> +                 continue;
> +               }
> +
> +             if (i.base_reg && i.base_reg->reg_num == RegIP)
> +               {
> +                 if (reloc_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC)
> +                   {
> +                     /* Set fx_tcbit for REX2 prefix.  */
> +                     if (is_apx_rex2_encoding ())
> +                       fixP->fx_tcbit = 1;
> +                     continue;
> +                   }
> +               }
> +             /* In 64-bit, i386_validate_fix updates only (%rip)
> +                relocations.  */
> +             else if (object_64bit)
> +               continue;
>
>               /* Check for "call/jmp *mem", "mov mem, %reg",
>                  "test %reg, mem" and "binop mem, %reg" where binop
> @@ -12083,10 +12115,22 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
>                 {
>                   if (object_64bit)
>                     {
> -                     fixP->fx_tcbit = i.rex != 0;
> -                     if (i.base_reg
> -                         && (i.base_reg->reg_num == RegIP))
> -                     fixP->fx_tcbit2 = 1;
> +                     if (reloc_type == BFD_RELOC_X86_64_GOTTPOFF)
> +                       {
> +                         /* Set fx_tcbit for REX2 prefix.  */
> +                         if (is_apx_rex2_encoding ())
> +                           fixP->fx_tcbit = 1;
> +                       }
> +                     else
> +                       {
> +                         /* Set fx_tcbit3 for REX2 prefix.  */
> +                         if (is_apx_rex2_encoding ())
> +                           fixP->fx_tcbit3 = 1;
> +                         else if (i.rex)
> +                           fixP->fx_tcbit2 = 1;
> +                         else
> +                           fixP->fx_tcbit = 1;
> +                       }
>                     }
>                   else
>                     fixP->fx_tcbit2 = 1;
> @@ -15563,6 +15607,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
>        case BFD_RELOC_X86_64_TLSLD:
>        case BFD_RELOC_X86_64_GOTTPOFF:
>        case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> +      case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
>        case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
>        case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
>         value = 0; /* Fully resolved at runtime.  No addend.  */
> @@ -17144,13 +17189,27 @@ i386_validate_fix (fixS *fixp)
>            && (!S_IS_DEFINED (fixp->fx_addsy)
>                || S_IS_EXTERNAL (fixp->fx_addsy));
>
> -  if (fixp->fx_tcbit3)
> +  /* BFD_RELOC_X86_64_GOTTPOFF:
> +      1. fx_tcbit -> BFD_RELOC_X86_64_CODE_4_GOTTPOFF
> +      2. fx_tcbit2 -> BFD_RELOC_X86_64_CODE_6_GOTTPOFF
> +    BFD_RELOC_X86_64_GOTPC32_TLSDESC:
> +      1. fx_tcbit -> BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC
> +    BFD_RELOC_32_PCREL:
> +      1. fx_tcbit -> BFD_RELOC_X86_64_GOTPCRELX
> +      2. fx_tcbit2 -> BFD_RELOC_X86_64_REX_GOTPCRELX
> +      3. fx_tcbit3 -> BFD_RELOC_X86_64_CODE_4_GOTPCRELX
> +      4. else -> BFD_RELOC_X86_64_GOTPCREL
> +   */
> +  if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF)
>      {
> -      if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF)
> +      if (fixp->fx_tcbit)
>         fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTTPOFF;
> -      else if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC)
> -       fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC;
> +      else if (fixp->fx_tcbit2)
> +       fixp->fx_r_type = BFD_RELOC_X86_64_CODE_6_GOTTPOFF;
>      }
> +  else if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC
> +          && fixp->fx_tcbit)
> +    fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC;
>  #endif
>
>    if (fixp->fx_subsy)
> @@ -17162,15 +17221,12 @@ i386_validate_fix (fixS *fixp)
>               if (!object_64bit)
>                 abort ();
>  #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
> -             if (fixp->fx_tcbit2)
> -               {
> -                 if (fixp->fx_tcbit3)
> -                   fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPCRELX;
> -                 else
> -                   fixp->fx_r_type = (fixp->fx_tcbit
> -                                      ? BFD_RELOC_X86_64_REX_GOTPCRELX
> -                                      : BFD_RELOC_X86_64_GOTPCRELX);
> -               }
> +             if (fixp->fx_tcbit)
> +               fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCRELX;
> +             else if (fixp->fx_tcbit2)
> +               fixp->fx_r_type = BFD_RELOC_X86_64_REX_GOTPCRELX;
> +             else if (fixp->fx_tcbit3)
> +               fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPCRELX;
>               else
>  #endif
>                 fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
> @@ -17296,6 +17352,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
>      case BFD_RELOC_X86_64_DTPOFF64:
>      case BFD_RELOC_X86_64_GOTTPOFF:
>      case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> +    case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
>      case BFD_RELOC_X86_64_TPOFF32:
>      case BFD_RELOC_X86_64_TPOFF64:
>      case BFD_RELOC_X86_64_GOTOFF64:
> @@ -17440,6 +17497,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
>           case BFD_RELOC_X86_64_TLSLD:
>           case BFD_RELOC_X86_64_GOTTPOFF:
>           case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> +         case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
>           case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
>           case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
>           case BFD_RELOC_X86_64_TLSDESC_CALL:
> diff --git a/gas/testsuite/gas/i386/x86-64-gottpoff.d b/gas/testsuite/gas/i386/x86-64-gottpoff.d
> index d42abccc6d9..f2c039abe72 100644
> --- a/gas/testsuite/gas/i386/x86-64-gottpoff.d
> +++ b/gas/testsuite/gas/i386/x86-64-gottpoff.d
> @@ -16,4 +16,8 @@ Disassembly of section .text:
>   +[a-f0-9]+:   48 8b 05 00 00 00 00    mov    0x0\(%rip\),%rax        # 2c <_start\+0x2c>      28: R_X86_64_GOTTPOFF   foo-0x4
>   +[a-f0-9]+:   d5 48 03 05 00 00 00 00         add    0x0\(%rip\),%r16        # 34 <_start\+0x34>      30: R_X86_64_CODE_4_GOTTPOFF    foo-0x4
>   +[a-f0-9]+:   d5 48 8b 25 00 00 00 00         mov    0x0\(%rip\),%r20        # 3c <_start\+0x3c>      38: R_X86_64_CODE_4_GOTTPOFF    foo-0x4
> + +[a-f0-9]+:   62 74 fc 10 01 05 00 00 00 00   add    %r8,0x0\(%rip\),%r16        # 46 <_start\+0x46>  42: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> + +[a-f0-9]+:   62 f4 9c 18 03 05 00 00 00 00   add    0x0\(%rip\),%rax,%r12        # 50 <_start\+0x50> 4c: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> + +[a-f0-9]+:   62 74 fc 10 01 05 00 00 00 00   add    %r8,0x0\(%rip\),%r16        # 5a <_start\+0x5a>  56: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> + +[a-f0-9]+:   62 f4 9c 18 03 05 00 00 00 00   add    0x0\(%rip\),%rax,%r12        # 64 <_start\+0x64> 60: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
>  #pass
> diff --git a/gas/testsuite/gas/i386/x86-64-gottpoff.s b/gas/testsuite/gas/i386/x86-64-gottpoff.s
> index 6f8f9d1480c..0335ec5debf 100644
> --- a/gas/testsuite/gas/i386/x86-64-gottpoff.s
> +++ b/gas/testsuite/gas/i386/x86-64-gottpoff.s
> @@ -13,3 +13,13 @@ _start:
>
>         addq    r16, QWORD PTR [rip + foo@GOTTPOFF]
>         movq    r20, QWORD PTR [rip + foo@GOTTPOFF]
> +
> +       .att_syntax prefix
> +
> +       addq    %r8, foo@GOTTPOFF(%rip), %r16
> +       addq    foo@GOTTPOFF(%rip), %rax, %r12
> +
> +       .intel_syntax noprefix
> +
> +       addq    r16, QWORD PTR [rip + foo@GOTTPOFF], r8
> +       addq    r12, rax, QWORD PTR [rip + foo@GOTTPOFF]
> diff --git a/gold/testsuite/x86_64_ie_to_le.s b/gold/testsuite/x86_64_ie_to_le.s
> index c5752068866..bd0643dc87f 100644
> --- a/gold/testsuite/x86_64_ie_to_le.s
> +++ b/gold/testsuite/x86_64_ie_to_le.s
> @@ -7,6 +7,8 @@ _start:
>         movq    foo@gottpoff(%rip), %rax
>         addq    foo@gottpoff(%rip), %r16
>         movq    foo@gottpoff(%rip), %r20
> +       addq    %r30, foo@gottpoff(%rip), %r8
> +       addq    foo@gottpoff(%rip), %rax, %r20
>         .size   _start, .-_start
>         .section        .tdata,"awT",@progbits
>         .align 4
> diff --git a/gold/testsuite/x86_64_ie_to_le.sh b/gold/testsuite/x86_64_ie_to_le.sh
> index 9d2e082f3e0..5308712ddbd 100755
> --- a/gold/testsuite/x86_64_ie_to_le.sh
> +++ b/gold/testsuite/x86_64_ie_to_le.sh
> @@ -27,3 +27,5 @@ grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r12" x86_64_ie_to_le.stdout
>  grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%rax" x86_64_ie_to_le.stdout
>  grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r16" x86_64_ie_to_le.stdout
>  grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%r20" x86_64_ie_to_le.stdout
> +grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r30,%r8" x86_64_ie_to_le.stdout
> +grep -q "add[ \t]\+\$0x[a-f0-9]\+,%rax,%r20" x86_64_ie_to_le.stdout
> diff --git a/gold/x86_64.cc b/gold/x86_64.cc
> index 58e191a055a..f77430bfb3d 100644
> --- a/gold/x86_64.cc
> +++ b/gold/x86_64.cc
> @@ -2920,6 +2920,11 @@ Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type,
>        // Another Local-Dynamic reloc.
>        return tls::TLSOPT_TO_LE;
>
> +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> +      if (r_offset <= 6 || *(reloc_view - 6) != 0x62)
> +       return tls::TLSOPT_NONE;
> +      goto handle_gottpoff;
> +
>      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
>        if (r_offset <= 4 || *(reloc_view - 4) != 0xd5)
>         return tls::TLSOPT_NONE;
> @@ -2929,6 +2934,7 @@ Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type,
>        // from the GOT.  If we know that we are linking against the
>        // local symbol, we can switch to Local-Exec, which links the
>        // thread offset into the instruction.
> +handle_gottpoff:
>        if (is_final)
>         return tls::TLSOPT_TO_LE;
>        return tls::TLSOPT_NONE;
> @@ -2997,6 +3003,7 @@ Target_x86_64<size>::Scan::get_reference_flags(unsigned int r_type)
>      case elfcpp::R_X86_64_DTPOFF64:
>      case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
>      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
>      case elfcpp::R_X86_64_TPOFF32:          // Local-exec
>        return Symbol::TLS_REF;
>
> @@ -3362,6 +3369,7 @@ need_got:
>        // These are initial tls relocs, which are expected when linking
>      case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
>      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
>        {
>         section_size_type stype;
>         reloc_view = object->section_contents(data_shndx, &stype, true);
> @@ -3464,6 +3472,7 @@ need_got:
>
>           case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
>           case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> +         case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
>             layout->set_has_static_tls();
>             if (optimized_type == tls::TLSOPT_NONE)
>               {
> @@ -3902,6 +3911,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
>        // These are initial tls relocs, which are expected for global()
>      case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
>      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
>        {
>         section_size_type stype;
>         reloc_view = object->section_contents(data_shndx, &stype, true);
> @@ -3920,7 +3930,8 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
>         // when building an executable.
>         const bool is_final = (gsym->final_value_is_known() ||
>                                ((r_type == elfcpp::R_X86_64_GOTTPOFF ||
> -                                r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF) &&
> +                                r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF||
> +                                r_type == elfcpp::R_X86_64_CODE_6_GOTTPOFF) &&
>                                 gsym->is_undefined() &&
>                                 parameters->options().output_is_executable()));
>         size_t r_offset = reloc.get_r_offset();
> @@ -4006,6 +4017,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
>
>           case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
>           case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> +         case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
>             layout->set_has_static_tls();
>             if (optimized_type == tls::TLSOPT_NONE)
>               {
> @@ -4608,6 +4620,7 @@ Target_x86_64<size>::Relocate::relocate(
>      case elfcpp::R_X86_64_DTPOFF64:
>      case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
>      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
>      case elfcpp::R_X86_64_TPOFF32:          // Local-exec
>        this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval,
>                          view, address, view_size);
> @@ -4894,6 +4907,7 @@ Target_x86_64<size>::Relocate::relocate_tls(
>
>      case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
>      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
>        if (gsym != NULL
>           && gsym->is_undefined()
>           && parameters->options().output_is_executable())
> @@ -5308,11 +5322,19 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
>
>    // movq foo@gottpoff(%rip),%reg  ==>  movq $YY,%reg
>    // addq foo@gottpoff(%rip),%reg  ==>  addq $YY,%reg
> +  // addq %reg1,foo@gottpoff(%rip),%reg2  ==>  addq $YY,%reg1,%reg2
> +  // addq foo@gottpoff(%rip),%reg1,%reg2  ==>  addq $YY,%reg1,%reg2
>
> -  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
> +  int off1;
> +  if (r_type == elfcpp::R_X86_64_CODE_6_GOTTPOFF)
> +    off1 = -5;
> +  else
> +    off1 = -3;
> +
> +  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, off1);
>    tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
>
> -  unsigned char op1 = view[-3];
> +  unsigned char op1 = view[off1];
>    unsigned char op2 = view[-2];
>    unsigned char op3 = view[-1];
>    unsigned char reg = op3 >> 3;
> @@ -5350,7 +5372,7 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
>           view[-1] = 0x80 | reg | (reg << 3);
>         }
>      }
> -  else
> +  else if (r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF)
>      {
>        if (op2 == 0x8b)
>         op2 = 0xc7;
> @@ -5362,6 +5384,23 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
>        view[-2] = op2;
>        view[-1] = 0xc0 | reg;
>      }
> +  else
> +    {
> +      unsigned char updated_op1 = op1;
> +
> +      // Set the R bits since they is inverted.
> +      updated_op1 |= 1 << 7 | 1 << 4;
> +
> +      // Update the B bits from the R bits.
> +      if ((op1 & (1 << 7)) == 0)
> +       updated_op1 &= ~(1 << 5);
> +      if ((op1 & (1 << 4)) == 0)
> +       updated_op1 |= 1 << 3;
> +
> +      view[-5] = updated_op1;
> +      view[-2] = 0x81;
> +      view[-1] = 0xc0 | reg;
> +    }
>
>    if (tls_segment != NULL)
>      value -= tls_segment->memsz();
> diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h
> index 33a824620a6..ea5036a8bbf 100644
> --- a/include/elf/x86-64.h
> +++ b/include/elf/x86-64.h
> @@ -92,6 +92,26 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_type)
>       /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
>         instruction starts at 4 bytes before the relocation offset.  */
>       RELOC_NUMBER (R_X86_64_CODE_4_GOTPC32_TLSDESC, 45)
> +     /* Load from 32 bit signed pc relative offset to GOT entry if the
> +       instruction starts at 5 bytes before the relocation offset,
> +       relaxable.  */
> +     RELOC_NUMBER (R_X86_64_CODE_5_GOTPCRELX, 46)
> +     /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
> +       instruction starts at 5 bytes before the relocation offset.  */
> +     RELOC_NUMBER (R_X86_64_CODE_5_GOTPC32_TLSDESC, 47)
> +    /* PC relative offset to IE GOT entry if the instruction starts at
> +       5 bytes before the relocation offset.  */
> +     RELOC_NUMBER (R_X86_64_CODE_5_GOTTPOFF, 48)
> +     /* Load from 32 bit signed pc relative offset to GOT entry if the
> +       instruction starts at 6 bytes before the relocation offset,
> +       relaxable.  */
> +     RELOC_NUMBER (R_X86_64_CODE_6_GOTPCRELX, 49)
> +    /* PC relative offset to IE GOT entry if the instruction starts at
> +       6 bytes before the relocation offset.  */
> +     RELOC_NUMBER (R_X86_64_CODE_6_GOTTPOFF, 50)
> +     /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
> +       instruction starts at 6 bytes before the relocation offset.  */
> +     RELOC_NUMBER (R_X86_64_CODE_6_GOTPC32_TLSDESC, 51)
>       RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250)       /* GNU C++ hack  */
>       RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251)         /* GNU C++ hack  */
>  END_RELOC_NUMBERS (R_X86_64_max)
> diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.dd b/ld/testsuite/ld-x86-64/tlsbindesc.dd
> index 4587cc751b4..be89f38199d 100644
> --- a/ld/testsuite/ld-x86-64/tlsbindesc.dd
> +++ b/ld/testsuite/ld-x86-64/tlsbindesc.dd
> @@ -169,18 +169,42 @@ Disassembly of section .text:
>   +[0-9a-f]+:   d5 48 03 05 ([0-9a-f]{2} ){3}[  ]+add    0x[0-9a-f]+\(%rip\),%r16 +# [0-9a-f]+ <sG2>
>  #                              -> R_X86_64_TPOFF64     sG2
>   +[0-9a-f]+:   00 *
> + +[0-9a-f]+:   62 f4 fc 10 01 ([0-9a-f]{2} ){2}[       ]+add    %rax,0x[0-9a-f]+\(%rip\),%r16 +# [0-9a-f]+ <sG2>
> +#                              -> R_X86_64_TPOFF64     sG2
> + +[0-9a-f]+:   ([0-9a-f]{2} ){3} *
> + +[0-9a-f]+:   62 f4 fc 10 03 ([0-9a-f]{2} ){2}[       ]+add    0x[0-9a-f]+\(%rip\),%rax,%r16 +# [0-9a-f]+ <sG2>
> +#                              -> R_X86_64_TPOFF64     sG2
> + +[0-9a-f]+:   ([0-9a-f]{2} ){3} *
>  #  IE -> LE against global var defined in exec
>   +[0-9a-f]+:   d5 18 81 c1 60 ff ff[   ]+add    \$0xf+60,%r17
>  #                                                      sg1
>   +[0-9a-f]+:   ff *
> + +[0-9a-f]+:   62 d4 f4 10 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r8,%r17
> +#                                                      sg1
> + +[0-9a-f]+:   ff ff ff *
> + +[0-9a-f]+:   62 d4 f4 10 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r8,%r17
> +#                                                      sg1
> + +[0-9a-f]+:   ff ff ff *
>  #  IE -> LE against local var
>   +[0-9a-f]+:   d5 18 81 c2 80 ff ff[   ]+add    \$0xf+80,%r18
>  #                                                      sl1
>   +[0-9a-f]+:   ff *
> + +[0-9a-f]+:   62 d4 fc 18 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r8,%rax
> +#                                                      sl1
> + +[0-9a-f]+:   ff ff ff *
> + +[0-9a-f]+:   62 d4 fc 18 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r8,%rax
> +#                                                      sl1
> + +[0-9a-f]+:   ff ff ff *
>  #  IE -> LE against hidden var
>   +[0-9a-f]+:   d5 18 81 c3 a0 ff ff[   ]+add    \$0xf+a0,%r19
>  #                                                      sh1
>   +[0-9a-f]+:   ff *
> + +[0-9a-f]+:   62 fc bc 18 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r19,%r8
> +#                                                      sh1
> + +[0-9a-f]+:   ff ff ff *
> + +[0-9a-f]+:   62 fc bc 18 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r19,%r8
> +#                                                      sh1
> + +[0-9a-f]+:   ff ff ff *
>  #  Direct access through %fs
>  #  IE against global var
>   +[0-9a-f]+:   d5 48 8b 25 ([0-9a-f]{2} ){3}[  ]+mov    0x[0-9a-f]+\(%rip\),%r20 +# [0-9a-f]+ <sG5>
> diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.rd b/ld/testsuite/ld-x86-64/tlsbindesc.rd
> index daaea7a5371..59325b04e19 100644
> --- a/ld/testsuite/ld-x86-64/tlsbindesc.rd
> +++ b/ld/testsuite/ld-x86-64/tlsbindesc.rd
> @@ -15,12 +15,12 @@ Section Headers:
>   +\[[ 0-9]+\] .dynsym +.*
>   +\[[ 0-9]+\] .dynstr +.*
>   +\[[ 0-9]+\] .rela.dyn +.*
> - +\[[ 0-9]+\] .text +PROGBITS +0+401000 0+1000 0+25d 00 +AX +0 +0 +4096
> - +\[[ 0-9]+\] .tdata +PROGBITS +0+60125d 0+125d 0+60 00 WAT +0 +0 +1
> - +\[[ 0-9]+\] .tbss +NOBITS +0+6012bd 0+12bd 0+40 00 WAT +0 +0 +1
> - +\[[ 0-9]+\] .dynamic +DYNAMIC +0+6012c0 0+12c0 0+100 10 +WA +4 +0 +8
> - +\[[ 0-9]+\] .got +PROGBITS +0+6013c0 0+13c0 0+20 08 +WA +0 +0 +8
> - +\[[ 0-9]+\] .got.plt +PROGBITS +0+6013e0 0+13e0 0+18 08 +WA +0 +0 +8
> + +\[[ 0-9]+\] .text +PROGBITS +0+401000 0+1000 0+2ad 00 +AX +0 +0 +4096
> + +\[[ 0-9]+\] .tdata +PROGBITS +0+6012ad 0+12ad 0+60 00 WAT +0 +0 +1
> + +\[[ 0-9]+\] .tbss +NOBITS +0+60130d 0+130d 0+40 00 WAT +0 +0 +1
> + +\[[ 0-9]+\] .dynamic +DYNAMIC +0+601310 0+1310 0+100 10 +WA +4 +0 +8
> + +\[[ 0-9]+\] .got +PROGBITS +0+601410 0+1410 0+20 08 +WA +0 +0 +8
> + +\[[ 0-9]+\] .got.plt +PROGBITS +0+601430 0+1430 0+18 08 +WA +0 +0 +8
>   +\[[ 0-9]+\] .symtab +.*
>   +\[[ 0-9]+\] .strtab +.*
>   +\[[ 0-9]+\] .shstrtab +.*
> @@ -28,7 +28,7 @@ Key to Flags:
>  #...
>
>  Elf file type is EXEC \(Executable file\)
> -Entry point 0x401165
> +Entry point 0x4011b5
>  There are [0-9]+ program headers, starting at offset [0-9]+
>
>  Program Headers:
> @@ -36,10 +36,10 @@ Program Headers:
>   +PHDR.*
>   +INTERP.*
>  .*Requesting program interpreter.*
> - +LOAD +0x0+ 0x0+400000 0x0+400000 0x0+125d 0x0+125d R E 0x200000
> - +LOAD +0x0+125d 0x0+60125d 0x0+60125d 0x0+19b 0x0+19b RW +0x200000
> - +DYNAMIC +0x0+12c0 0x0+6012c0 0x0+6012c0 0x0+100 0x0+100 RW +0x8
> - +TLS +0x0+125d 0x0+60125d 0x0+60125d 0x0+60 0x0+a0 R +0x1
> + +LOAD +0x0+ 0x0+400000 0x0+400000 0x0+12ad 0x0+12ad R E 0x200000
> + +LOAD +0x0+12ad 0x0+6012ad 0x0+6012ad 0x0+19b 0x0+19b RW +0x200000
> + +DYNAMIC +0x0+1310 0x0+601310 0x0+601310 0x0+100 0x0+100 RW +0x8
> + +TLS +0x0+12ad 0x0+6012ad 0x0+6012ad 0x0+60 0x0+a0 R +0x1
>
>   Section to Segment mapping:
>   +Segment Sections...
> @@ -52,10 +52,10 @@ Program Headers:
>
>  Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 4 entries:
>   +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
> -0+6013c0 +0+100000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
> -0+6013c8 +0+200000012 R_X86_64_TPOFF64 +0+ sG2 \+ 0
> -0+6013d0 +0+300000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
> -0+6013d8 +0+400000012 R_X86_64_TPOFF64 +0+ sG1 \+ 0
> +0+601410 +0+100000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
> +0+601418 +0+200000012 R_X86_64_TPOFF64 +0+ sG2 \+ 0
> +0+601420 +0+300000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
> +0+601428 +0+400000012 R_X86_64_TPOFF64 +0+ sG1 \+ 0
>
>  Symbol table '\.dynsym' contains [0-9]+ entries:
>   +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
> @@ -88,8 +88,8 @@ Symbol table '\.symtab' contains [0-9]+ entries:
>   +[0-9]+: 0+9c +0 +TLS +LOCAL +DEFAULT +8 bl8
>  .* FILE +LOCAL +DEFAULT +ABS
>   +[0-9]+: 0+a0 +0 +TLS +LOCAL +DEFAULT +7 _TLS_MODULE_BASE_
> - +[0-9]+: 0+6012c0 +0 +OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
> - +[0-9]+: 0+6013e0 +0 +OBJECT +LOCAL +DEFAULT +11 _GLOBAL_OFFSET_TABLE_
> + +[0-9]+: 0+601310 +0 +OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
> + +[0-9]+: 0+601430 +0 +OBJECT +LOCAL +DEFAULT +11 _GLOBAL_OFFSET_TABLE_
>   +[0-9]+: 0+1c +0 +TLS +GLOBAL +DEFAULT +7 sg8
>   +[0-9]+: 0+7c +0 +TLS +GLOBAL +DEFAULT +8 bg8
>   +[0-9]+: 0+74 +0 +TLS +GLOBAL +DEFAULT +8 bg6
> @@ -104,7 +104,7 @@ Symbol table '\.symtab' contains [0-9]+ entries:
>   +[0-9]+: 0+58 +0 +TLS +GLOBAL +HIDDEN +7 sh7
>   +[0-9]+: 0+5c +0 +TLS +GLOBAL +HIDDEN +7 sh8
>   +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +7 sg1
> - +[0-9]+: 0+401165 +0 +FUNC +GLOBAL +DEFAULT +6 _start
> + +[0-9]+: 0+4011b5 +0 +FUNC +GLOBAL +DEFAULT +6 _start
>   +[0-9]+: 0+4c +0 +TLS +GLOBAL +HIDDEN +7 sh4
>   +[0-9]+: 0+78 +0 +TLS +GLOBAL +DEFAULT +8 bg7
>   +[0-9]+: 0+50 +0 +TLS +GLOBAL +HIDDEN +7 sh5
> diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.s b/ld/testsuite/ld-x86-64/tlsbindesc.s
> index b80e5f192c0..4747fc1bc30 100644
> --- a/ld/testsuite/ld-x86-64/tlsbindesc.s
> +++ b/ld/testsuite/ld-x86-64/tlsbindesc.s
> @@ -129,15 +129,23 @@ fn2:
>
>         /* IE against global var  */
>         addq    sG2@gottpoff(%rip), %r16
> +       addq    %rax, sG2@gottpoff(%rip), %r16
> +       addq    sG2@gottpoff(%rip), %rax, %r16
>
>         /* IE -> LE against global var defined in exec */
>         addq    sg1@gottpoff(%rip), %r17
> +       addq    %r8, sg1@gottpoff(%rip), %r17
> +       addq    sg1@gottpoff(%rip), %r8, %r17
>
>         /* IE -> LE against local var */
>         addq    sl1@gottpoff(%rip), %r18
> +       addq    %r8, sl1@gottpoff(%rip), %rax
> +       addq    sl1@gottpoff(%rip), %r8, %rax
>
>         /* IE -> LE against hidden var */
>         addq    sh1@gottpoff(%rip), %r19
> +       addq    %r19, sh1@gottpoff(%rip), %r8
> +       addq    sh1@gottpoff(%rip), %r19, %r8
>
>         /* Direct access through %fs  */
>
> --
> 2.43.0
>

I am checking it in.

-- 
H.J.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] x86-64: Add R_X86_64_CODE_6_GOTTPOFF
  2024-02-08 11:41 ` H.J. Lu
@ 2024-02-10 16:22   ` H.J. Lu
  0 siblings, 0 replies; 3+ messages in thread
From: H.J. Lu @ 2024-02-10 16:22 UTC (permalink / raw)
  To: binutils

On Thu, Feb 8, 2024 at 3:41 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Wed, Feb 7, 2024 at 4:42 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > Changes in v2:
> >
> > Rewrite fx_tcbit, fx_tcbit2 and fx_tcbit3 usage to generate
> > R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX,
> > R_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTPC32_TLSDESC and
> > R_X86_64_CODE_6_GOTTPOFF.
> >
> > ---
> > For
> >
> >         add     %reg1, name@gottpoff(%rip), %reg2
> >         add     name@gottpoff(%rip), %reg1, %reg2
> >
> > add
> >
> >  #define R_X86_64_CODE_6_GOTTPOFF               50
> >
> > if the instruction starts at 6 bytes before the relocation offset.
> > They are similar to R_X86_64_GOTTPOFF.  Linker can covert GOTTPOFF to
> >
> >         add     $name@tpoff, %reg1, %reg2
> >
> > Rewrite fx_tcbit, fx_tcbit2 and fx_tcbit3 usage to generate
> > R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX,
> > R_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTPC32_TLSDESC and
> > R_X86_64_CODE_6_GOTTPOFF.
> >
> > NB: There is no need to check BFD_RELOC_X86_64_CODE_4_GOTTPOFF in
> > md_assemble since there is only BFD_RELOC_X86_64_GOTTPOFF at this
> > stage, which will be converted to BFD_RELOC_X86_64_CODE_4_GOTTPOFF
> > or BFD_RELOC_X86_64_CODE_6_GOTTPOFF in i386_validate_fix.
> >
> > 5 relocations:
> >
> >  #define R_X86_64_CODE_5_GOTPCRELX              46
> >  #define R_X86_64_CODE_5_GOTTPOFF               47
> >  #define R_X86_64_CODE_5_GOTPC32_TLSDESC        48
> >  #define R_X86_64_CODE_6_GOTPCRELX              49
> >  #define R_X86_64_CODE_6_GOTPC32_TLSDESC        51
> >
> > are added for completeness and they are unused.
> >
> > bfd/
> >
> >         * elf64-x86-64.c (x86_64_elf_howto_table): Add
> >         R_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTTPOFF,
> >         R_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPCRELX,
> >         R_X86_64_CODE_6_GOTTPOFF and R_X86_64_CODE_6_GOTPC32_TLSDESC.
> >         (R_X86_64_standard): Updated.
> >         (x86_64_reloc_map): Add R_X86_64_CODE_5_GOTPCRELX,
> >         R_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTPC32_TLSDESC,
> >         R_X86_64_CODE_6_GOTPCRELX, R_X86_64_CODE_6_GOTTPOFF and
> >         R_X86_64_CODE_6_GOTPC32_TLSDESC.
> >         (elf_x86_64_check_tls_transition): Handle
> >         R_X86_64_CODE_6_GOTTPOFF.
> >         (elf_x86_64_tls_transition): Likewise.
> >         (elf_x86_64_scan_relocs): Handle R_X86_64_CODE_6_GOTTPOFF.
> >         Issue an error for R_X86_64_CODE_5_GOTPCRELX,
> >         R_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTPC32_TLSDESC,
> >         R_X86_64_CODE_6_GOTPCRELX and R_X86_64_CODE_6_GOTPC32_TLSDESC.
> >         (elf_x86_64_relocate_section): Handle R_X86_64_CODE_6_GOTTPOFF.
> >         * reloc.c (bfd_reloc_code_real): Add
> >         BFD_RELOC_X86_64_CODE_5_GOTPCRELX,
> >         BFD_RELOC_X86_64_CODE_5_GOTTPOFF,
> >         BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC,
> >         BFD_RELOC_X86_64_CODE_6_GOTPCRELX,
> >         BFD_RELOC_X86_64_CODE_6_GOTTPOFF and
> >         BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC.
> >         * bfd-in2.h: Regenerated.
> >         * libbfd.h: Likewise.
> >
> > elfcpp/
> >
> >         * x86_64.h (R_X86_64_CODE_5_GOTPCRELX): New.
> >         (R_X86_64_CODE_5_GOTTPOFF): Likewise.
> >         (R_X86_64_CODE_5_GOTPC32_TLSDESC): Likewise.
> >         (R_X86_64_CODE_6_GOTPCRELX): Likewise.
> >         (R_X86_64_CODE_6_GOTTPOFF): Likewise.
> >         (R_X86_64_CODE_6_GOTPC32_TLSDESC): Likewise.
> >
> > gas/
> >
> >         * config/tc-i386.c (tc_i386_fix_adjustable): Handle
> >         BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
> >         (md_assemble): Don't check BFD_RELOC_X86_64_CODE_4_GOTTPOFF.
> >         Allow "add %reg1, foo@gottpoff(%rip), %reg2".
> >         (output_disp): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.  Rewrite
> >         setting fx_tcbitX bits for BFD_RELOC_X86_64_GOTTPOFF,
> >         BFD_RELOC_X86_64_GOTPC32_TLSDESC and BFD_RELOC_32_PCREL.
> >         (md_apply_fix): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
> >         (i386_validate_fix): Rewrite fx_tcbitX bit checking for
> >         BFD_RELOC_X86_64_GOTTPOFF, BFD_RELOC_X86_64_GOTPC32_TLSDESC and
> >         BFD_RELOC_32_PCREL.
> >         (tc_gen_reloc): Handle BFD_RELOC_X86_64_CODE_6_GOTTPOFF.
> >         * testsuite/gas/i386/x86-64-gottpoff.d: Updated.
> >         * testsuite/gas/i386/x86-64-gottpoff.s: Add tests for
> >         "add %reg1, foo@gottpoff(%rip), %reg2" and
> >         "add foo@gottpoff(%rip), %reg, %reg2".
> >
> > gold/
> >
> >         * x86_64.cc (Target_x86_64::optimize_tls_reloc): Handle
> >         R_X86_64_CODE_6_GOTTPOFF.
> >         (Target_x86_64::Scan::get_reference_flags): Likewise.
> >         (Target_x86_64::Scan::local): Likewise.
> >         (Target_x86_64::Scan::global): Likewise.
> >         (Target_x86_64::Relocate::relocate): Likewise.
> >         (Target_x86_64::Relocate::relocate_tls): Likewise.
> >         (Target_x86_64::Relocate::tls_ie_to_le): Handle.
> >         R_X86_64_CODE_6_GOTTPOFF.
> >         * testsuite/x86_64_ie_to_le.s: Add tests for
> >         "add %reg1, foo@gottpoff(%rip), %reg2" and
> >         "add foo@gottpoff(%rip), %reg, %reg2".
> >         * testsuite/x86_64_ie_to_le.sh: Updated.
> >
> > include/
> >
> >         * elf/x86-64.h (elf_x86_64_reloc_type): Add
> >         R_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTTPOFF,
> >         R_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPCRELX,
> >         R_X86_64_CODE_6_GOTTPOFF and R_X86_64_CODE_6_GOTPC32_TLSDESC.
> >
> > ld/
> >
> >         * testsuite/ld-x86-64/tlsbindesc.s: Add R_X86_64_CODE_6_GOTTPOFF
> >         tests.
> >         * testsuite/ld-x86-64/tlsbindesc.d: Updated.
> >         * testsuite/ld-x86-64/tlsbindesc.rd: Likewise.
> > ---
> >  bfd/bfd-in2.h                            |   6 ++
> >  bfd/elf64-x86-64.c                       | 113 ++++++++++++++++++++++-
> >  bfd/libbfd.h                             |   6 ++
> >  bfd/reloc.c                              |  12 +++
> >  elfcpp/x86_64.h                          |  24 +++++
> >  gas/config/tc-i386.c                     | 102 +++++++++++++++-----
> >  gas/testsuite/gas/i386/x86-64-gottpoff.d |   4 +
> >  gas/testsuite/gas/i386/x86-64-gottpoff.s |  10 ++
> >  gold/testsuite/x86_64_ie_to_le.s         |   2 +
> >  gold/testsuite/x86_64_ie_to_le.sh        |   2 +
> >  gold/x86_64.cc                           |  47 +++++++++-
> >  include/elf/x86-64.h                     |  20 ++++
> >  ld/testsuite/ld-x86-64/tlsbindesc.dd     |  24 +++++
> >  ld/testsuite/ld-x86-64/tlsbindesc.rd     |  36 ++++----
> >  ld/testsuite/ld-x86-64/tlsbindesc.s      |   8 ++
> >  15 files changed, 371 insertions(+), 45 deletions(-)
> >
> > diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> > index 581d8fe0b3e..dbafcf8da36 100644
> > --- a/bfd/bfd-in2.h
> > +++ b/bfd/bfd-in2.h
> > @@ -3894,6 +3894,12 @@ enum bfd_reloc_code_real
> >    BFD_RELOC_X86_64_CODE_4_GOTPCRELX,
> >    BFD_RELOC_X86_64_CODE_4_GOTTPOFF,
> >    BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC,
> > +  BFD_RELOC_X86_64_CODE_5_GOTPCRELX,
> > +  BFD_RELOC_X86_64_CODE_5_GOTTPOFF,
> > +  BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC,
> > +  BFD_RELOC_X86_64_CODE_6_GOTPCRELX,
> > +  BFD_RELOC_X86_64_CODE_6_GOTTPOFF,
> > +  BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC,
> >
> >    /* ns32k relocations.  */
> >    BFD_RELOC_NS32K_IMM_8,
> > diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
> > index f1253751bbd..2ed120af780 100644
> > --- a/bfd/elf64-x86-64.c
> > +++ b/bfd/elf64-x86-64.c
> > @@ -179,12 +179,30 @@ static reloc_howto_type x86_64_elf_howto_table[] =
> >    HOWTO(R_X86_64_CODE_4_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
> >         complain_overflow_bitfield, bfd_elf_generic_reloc,
> >         "R_X86_64_CODE_4_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
> > +  HOWTO(R_X86_64_CODE_5_GOTPCRELX, 0, 4, 32, true, 0,
> > +       complain_overflow_signed, bfd_elf_generic_reloc,
> > +       "R_X86_64_CODE_5_GOTPCRELX", false, 0, 0xffffffff, true),
> > +  HOWTO(R_X86_64_CODE_5_GOTTPOFF, 0, 4, 32, true, 0,
> > +       complain_overflow_signed, bfd_elf_generic_reloc,
> > +       "R_X86_64_CODE_5_GOTTPOFF", false, 0, 0xffffffff, true),
> > +  HOWTO(R_X86_64_CODE_5_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
> > +       complain_overflow_bitfield, bfd_elf_generic_reloc,
> > +       "R_X86_64_CODE_5_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
> > +  HOWTO(R_X86_64_CODE_6_GOTPCRELX, 0, 4, 32, true, 0,
> > +       complain_overflow_signed, bfd_elf_generic_reloc,
> > +       "R_X86_64_CODE_6_GOTPCRELX", false, 0, 0xffffffff, true),
> > +  HOWTO(R_X86_64_CODE_6_GOTTPOFF, 0, 4, 32, true, 0,
> > +       complain_overflow_signed, bfd_elf_generic_reloc,
> > +       "R_X86_64_CODE_6_GOTTPOFF", false, 0, 0xffffffff, true),
> > +  HOWTO(R_X86_64_CODE_6_GOTPC32_TLSDESC, 0, 4, 32, true, 0,
> > +       complain_overflow_bitfield, bfd_elf_generic_reloc,
> > +       "R_X86_64_CODE_6_GOTPC32_TLSDESC", false, 0, 0xffffffff, true),
> >
> >    /* We have a gap in the reloc numbers here.
> >       R_X86_64_standard counts the number up to this point, and
> >       R_X86_64_vt_offset is the value to subtract from a reloc type of
> >       R_X86_64_GNU_VT* to form an index into this table.  */
> > -#define R_X86_64_standard (R_X86_64_CODE_4_GOTPC32_TLSDESC + 1)
> > +#define R_X86_64_standard (R_X86_64_CODE_6_GOTPC32_TLSDESC + 1)
> >  #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
> >
> >  /* GNU extension to record C++ vtable hierarchy.  */
> > @@ -256,6 +274,12 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
> >    { BFD_RELOC_X86_64_CODE_4_GOTPCRELX, R_X86_64_CODE_4_GOTPCRELX, },
> >    { BFD_RELOC_X86_64_CODE_4_GOTTPOFF, R_X86_64_CODE_4_GOTTPOFF, },
> >    { BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC, R_X86_64_CODE_4_GOTPC32_TLSDESC, },
> > +  { BFD_RELOC_X86_64_CODE_5_GOTPCRELX, R_X86_64_CODE_5_GOTPCRELX, },
> > +  { BFD_RELOC_X86_64_CODE_5_GOTTPOFF, R_X86_64_CODE_5_GOTTPOFF, },
> > +  { BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC, R_X86_64_CODE_5_GOTPC32_TLSDESC, },
> > +  { BFD_RELOC_X86_64_CODE_6_GOTPCRELX, R_X86_64_CODE_6_GOTPCRELX, },
> > +  { BFD_RELOC_X86_64_CODE_6_GOTTPOFF, R_X86_64_CODE_6_GOTTPOFF, },
> > +  { BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC, R_X86_64_CODE_6_GOTPC32_TLSDESC, },
> >    { BFD_RELOC_VTABLE_INHERIT,  R_X86_64_GNU_VTINHERIT, },
> >    { BFD_RELOC_VTABLE_ENTRY,    R_X86_64_GNU_VTENTRY, },
> >  };
> > @@ -1283,6 +1307,23 @@ elf_x86_64_check_tls_transition (bfd *abfd,
> >
> >        goto check_gottpoff;
> >
> > +    case R_X86_64_CODE_6_GOTTPOFF:
> > +      /* Check transition from IE access model:
> > +               add %reg1, foo@gottpoff(%rip), %reg2
> > +               where reg1/reg2 are one of r16 to r31.  */
> > +
> > +      if (offset < 6
> > +         || (offset + 4) > sec->size
> > +         || contents[offset - 6] != 0x62)
> > +       return false;
> > +
> > +      val = bfd_get_8 (abfd, contents + offset - 2);
> > +      if (val != 0x01 && val != 0x03)
> > +       return false;
> > +
> > +      val = bfd_get_8 (abfd, contents + offset - 1);
> > +      return (val & 0xc7) == 5;
> > +
> >      case R_X86_64_GOTTPOFF:
> >        /* Check transition from IE access model:
> >                 mov foo@gottpoff(%rip), %reg
> > @@ -1417,6 +1458,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
> >      case R_X86_64_TLSDESC_CALL:
> >      case R_X86_64_GOTTPOFF:
> >      case R_X86_64_CODE_4_GOTTPOFF:
> > +    case R_X86_64_CODE_6_GOTTPOFF:
> >        if (bfd_link_executable (info))
> >         {
> >           if (h == NULL)
> > @@ -1464,6 +1506,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
> >    /* Return TRUE if there is no transition.  */
> >    if (from_type == to_type
> >        || (from_type == R_X86_64_CODE_4_GOTTPOFF
> > +         && to_type == R_X86_64_GOTTPOFF)
> > +      || (from_type == R_X86_64_CODE_6_GOTTPOFF
> >           && to_type == R_X86_64_GOTTPOFF))
> >      return true;
> >
> > @@ -2177,6 +2221,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
> >
> >         case R_X86_64_GOTTPOFF:
> >         case R_X86_64_CODE_4_GOTTPOFF:
> > +       case R_X86_64_CODE_6_GOTTPOFF:
> >           if (!bfd_link_executable (info))
> >             info->flags |= DF_STATIC_TLS;
> >           /* Fall through */
> > @@ -2214,6 +2259,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
> >                 break;
> >               case R_X86_64_GOTTPOFF:
> >               case R_X86_64_CODE_4_GOTTPOFF:
> > +             case R_X86_64_CODE_6_GOTTPOFF:
> >                 tls_type = GOT_TLS_IE;
> >                 break;
> >               case R_X86_64_GOTPC32_TLSDESC:
> > @@ -2503,6 +2549,26 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
> >             }
> >           break;
> >
> > +       case R_X86_64_CODE_5_GOTPCRELX:
> > +       case R_X86_64_CODE_5_GOTTPOFF:
> > +       case R_X86_64_CODE_5_GOTPC32_TLSDESC:
> > +       case R_X86_64_CODE_6_GOTPCRELX:
> > +       case R_X86_64_CODE_6_GOTPC32_TLSDESC:
> > +           {
> > +             /* These relocations are added only for completeness and
> > +                aren't be used.  */
> > +             if (h)
> > +               name = h->root.root.string;
> > +             else
> > +               name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
> > +                                        NULL);
> > +             _bfd_error_handler
> > +               /* xgettext:c-format */
> > +               (_("%pB: unsupported relocation %s against symbol `%s'"),
> > +                abfd, x86_64_elf_howto_table[r_type].name, name);
> > +           }
> > +         break;
> > +
> >           /* This relocation describes the C++ object vtable hierarchy.
> >              Reconstruct it for later use during GC.  */
> >         case R_X86_64_GNU_VTINHERIT:
> > @@ -3570,6 +3636,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
> >         case R_X86_64_TLSDESC_CALL:
> >         case R_X86_64_GOTTPOFF:
> >         case R_X86_64_CODE_4_GOTTPOFF:
> > +       case R_X86_64_CODE_6_GOTTPOFF:
> >           tls_type = GOT_UNKNOWN;
> >           if (h == NULL && local_got_offsets)
> >             tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
> > @@ -3920,6 +3987,50 @@ elf_x86_64_relocate_section (bfd *output_bfd,
> >                               contents + roff);
> >                   continue;
> >                 }
> > +             else if (r_type == R_X86_64_CODE_6_GOTTPOFF)
> > +               {
> > +                 /* IE->LE transition:
> > +                    Originally it is
> > +                    add %reg1, foo@gottpoff(%rip), %reg2
> > +                    or
> > +                    add foo@gottpoff(%rip), %reg1, %reg2
> > +                    We change it into:
> > +                    add $foo@tpoff, %reg1, %reg2
> > +                  */
> > +                 unsigned int reg, byte1;
> > +                 unsigned int updated_byte1;
> > +
> > +                 if (roff < 6)
> > +                   goto corrupt_input;
> > +
> > +                 /* Move the R bits to the B bits in EVEX payload
> > +                    byte 1.  */
> > +                 byte1 = bfd_get_8 (input_bfd, contents + roff - 5);
> > +                 updated_byte1 = byte1;
> > +
> > +                 /* Set the R bits since they is inverted.  */
> > +                 updated_byte1 |= 1 << 7 | 1 << 4;
> > +
> > +                 /* Update the B bits from the R bits.  */
> > +                 if ((byte1 & (1 << 7)) == 0)
> > +                   updated_byte1 &= ~(1 << 5);
> > +                 if ((byte1 & (1 << 4)) == 0)
> > +                   updated_byte1 |= 1 << 3;
> > +
> > +                 reg = bfd_get_8 (input_bfd, contents + roff - 1);
> > +                 reg >>= 3;
> > +
> > +                 bfd_put_8 (output_bfd, updated_byte1,
> > +                            contents + roff - 5);
> > +                 bfd_put_8 (output_bfd, 0x81,
> > +                            contents + roff - 2);
> > +                 bfd_put_8 (output_bfd, 0xc0 | reg,
> > +                            contents + roff - 1);
> > +                 bfd_put_32 (output_bfd,
> > +                             elf_x86_64_tpoff (info, relocation),
> > +                             contents + roff);
> > +                 continue;
> > +               }
> >               else
> >                 BFD_ASSERT (false);
> >             }
> > diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> > index ebd4f24149b..40bbe6a3886 100644
> > --- a/bfd/libbfd.h
> > +++ b/bfd/libbfd.h
> > @@ -1463,6 +1463,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
> >    "BFD_RELOC_X86_64_CODE_4_GOTPCRELX",
> >    "BFD_RELOC_X86_64_CODE_4_GOTTPOFF",
> >    "BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC",
> > +  "BFD_RELOC_X86_64_CODE_5_GOTPCRELX",
> > +  "BFD_RELOC_X86_64_CODE_5_GOTTPOFF",
> > +  "BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC",
> > +  "BFD_RELOC_X86_64_CODE_6_GOTPCRELX",
> > +  "BFD_RELOC_X86_64_CODE_6_GOTTPOFF",
> > +  "BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC",
> >    "BFD_RELOC_NS32K_IMM_8",
> >    "BFD_RELOC_NS32K_IMM_16",
> >    "BFD_RELOC_NS32K_IMM_32",
> > diff --git a/bfd/reloc.c b/bfd/reloc.c
> > index e74cbd75e96..7583b7fd552 100644
> > --- a/bfd/reloc.c
> > +++ b/bfd/reloc.c
> > @@ -2481,6 +2481,18 @@ ENUMX
> >    BFD_RELOC_X86_64_CODE_4_GOTTPOFF
> >  ENUMX
> >    BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC
> > +ENUMX
> > +  BFD_RELOC_X86_64_CODE_5_GOTPCRELX
> > +ENUMX
> > +  BFD_RELOC_X86_64_CODE_5_GOTTPOFF
> > +ENUMX
> > +  BFD_RELOC_X86_64_CODE_5_GOTPC32_TLSDESC
> > +ENUMX
> > +  BFD_RELOC_X86_64_CODE_6_GOTPCRELX
> > +ENUMX
> > +  BFD_RELOC_X86_64_CODE_6_GOTTPOFF
> > +ENUMX
> > +  BFD_RELOC_X86_64_CODE_6_GOTPC32_TLSDESC
> >  ENUMDOC
> >    x86-64/elf relocations.
> >
> > diff --git a/elfcpp/x86_64.h b/elfcpp/x86_64.h
> > index 135f339fccf..5d254ce483b 100644
> > --- a/elfcpp/x86_64.h
> > +++ b/elfcpp/x86_64.h
> > @@ -110,6 +110,30 @@ enum
> >                                         // descriptor in GOT if the
> >                                         // instruction starts at 4 bytes
> >                                         // before the relocation offset.
> > +  R_X86_64_CODE_5_GOTPCRELX = 46, // 32 bit signed PC relative offset to
> > +                                 // GOT if the instruction starts at 5
> > +                                 // bytes before the relocation offset,
> > +                                 // relaxable.
> > +  R_X86_64_CODE_5_GOTTPOFF = 47,  // 32 bit signed PC relative offset to
> > +                                 // GOT entry for IE symbol if the
> > +                                 // instruction starts at 5 bytes before
> > +                                 // the relocation offset.
> > +  R_X86_64_CODE_5_GOTPC32_TLSDESC = 48, // 32-bit PC relative to TLS
> > +                                       // descriptor in GOT if the
> > +                                       // instruction starts at 5 bytes
> > +                                       // before the relocation offset.
> > +  R_X86_64_CODE_6_GOTPCRELX = 49, // 32 bit signed PC relative offset to
> > +                                 // GOT if the instruction starts at 6
> > +                                 // bytes before the relocation offset,
> > +                                 // relaxable.
> > +  R_X86_64_CODE_6_GOTTPOFF = 50,  // 32 bit signed PC relative offset to
> > +                                 // GOT entry for IE symbol if the
> > +                                 // instruction starts at 6 bytes before
> > +                                 // the relocation offset.
> > +  R_X86_64_CODE_6_GOTPC32_TLSDESC = 51, // 32-bit PC relative to TLS
> > +                                       // descriptor in GOT if the
> > +                                       // instruction starts at 6 bytes
> > +                                       // before the relocation offset.
> >    // GNU vtable garbage collection extensions.
> >    R_X86_64_GNU_VTINHERIT = 250,
> >    R_X86_64_GNU_VTENTRY = 251
> > diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
> > index 50d890c4481..9e7bb1dd4d6 100644
> > --- a/gas/config/tc-i386.c
> > +++ b/gas/config/tc-i386.c
> > @@ -3648,6 +3648,7 @@ tc_i386_fix_adjustable (fixS *fixP)
> >        || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64
> >        || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF
> >        || fixP->fx_r_type == BFD_RELOC_X86_64_CODE_4_GOTTPOFF
> > +      || fixP->fx_r_type == BFD_RELOC_X86_64_CODE_6_GOTTPOFF
> >        || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
> >        || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64
> >        || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64
> > @@ -6795,10 +6796,19 @@ md_assemble (char *line)
> >        for (j = i.imm_operands; j < i.operands; ++j)
> >         switch (i.reloc[j])
> >           {
> > +         case BFD_RELOC_X86_64_GOTTPOFF:
> > +           if (i.tm.mnem_off == MN_add
> > +               && i.tm.opcode_space == SPACE_EVEXMAP4
> > +               && i.mem_operands == 1
> > +               && i.base_reg
> > +               && i.base_reg->reg_num == RegIP
> > +               && i.tm.operand_types[0].bitfield.class == Reg
> > +               && i.tm.operand_types[2].bitfield.class == Reg)
> > +             /* Allow APX: add %reg1, foo@gottpoff(%rip), %reg2.  */
> > +             break;
> > +           /* Fall through.  */
> >           case BFD_RELOC_386_TLS_GOTIE:
> >           case BFD_RELOC_386_TLS_LE_32:
> > -         case BFD_RELOC_X86_64_GOTTPOFF:
> > -         case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> >           case BFD_RELOC_X86_64_TLSLD:
> >             as_bad (_("TLS relocation cannot be used with `%s'"), insn_name (&i.tm));
> >             return;
> > @@ -12040,6 +12050,7 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
> >                     case BFD_RELOC_X86_64_TLSLD:
> >                     case BFD_RELOC_X86_64_GOTTPOFF:
> >                     case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> > +                   case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
> >                     case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
> >                     case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
> >                     case BFD_RELOC_X86_64_TLSDESC_CALL:
> > @@ -12056,9 +12067,30 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
> >                   && !i.prefix[ADDR_PREFIX])
> >                 fixP->fx_signed = 1;
> >
> > -             /* Set fx_tcbit3 for REX2 prefix.  */
> > -             if (is_apx_rex2_encoding ())
> > -               fixP->fx_tcbit3 = 1;
> > +             if (reloc_type == BFD_RELOC_X86_64_GOTTPOFF
> > +                 && i.tm.opcode_space == SPACE_EVEXMAP4)
> > +               {
> > +                 /* Only "add %reg1, foo@gottpoff(%rip), %reg2" is
> > +                    allowed in md_assemble.  Set fx_tcbit2 for EVEX
> > +                    prefix.  */
> > +                 fixP->fx_tcbit2 = 1;
> > +                 continue;
> > +               }
> > +
> > +             if (i.base_reg && i.base_reg->reg_num == RegIP)
> > +               {
> > +                 if (reloc_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC)
> > +                   {
> > +                     /* Set fx_tcbit for REX2 prefix.  */
> > +                     if (is_apx_rex2_encoding ())
> > +                       fixP->fx_tcbit = 1;
> > +                     continue;
> > +                   }
> > +               }
> > +             /* In 64-bit, i386_validate_fix updates only (%rip)
> > +                relocations.  */
> > +             else if (object_64bit)
> > +               continue;
> >
> >               /* Check for "call/jmp *mem", "mov mem, %reg",
> >                  "test %reg, mem" and "binop mem, %reg" where binop
> > @@ -12083,10 +12115,22 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
> >                 {
> >                   if (object_64bit)
> >                     {
> > -                     fixP->fx_tcbit = i.rex != 0;
> > -                     if (i.base_reg
> > -                         && (i.base_reg->reg_num == RegIP))
> > -                     fixP->fx_tcbit2 = 1;
> > +                     if (reloc_type == BFD_RELOC_X86_64_GOTTPOFF)
> > +                       {
> > +                         /* Set fx_tcbit for REX2 prefix.  */
> > +                         if (is_apx_rex2_encoding ())
> > +                           fixP->fx_tcbit = 1;
> > +                       }
> > +                     else
> > +                       {
> > +                         /* Set fx_tcbit3 for REX2 prefix.  */
> > +                         if (is_apx_rex2_encoding ())
> > +                           fixP->fx_tcbit3 = 1;
> > +                         else if (i.rex)
> > +                           fixP->fx_tcbit2 = 1;
> > +                         else
> > +                           fixP->fx_tcbit = 1;
> > +                       }
> >                     }
> >                   else
> >                     fixP->fx_tcbit2 = 1;
> > @@ -15563,6 +15607,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
> >        case BFD_RELOC_X86_64_TLSLD:
> >        case BFD_RELOC_X86_64_GOTTPOFF:
> >        case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> > +      case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
> >        case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
> >        case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
> >         value = 0; /* Fully resolved at runtime.  No addend.  */
> > @@ -17144,13 +17189,27 @@ i386_validate_fix (fixS *fixp)
> >            && (!S_IS_DEFINED (fixp->fx_addsy)
> >                || S_IS_EXTERNAL (fixp->fx_addsy));
> >
> > -  if (fixp->fx_tcbit3)
> > +  /* BFD_RELOC_X86_64_GOTTPOFF:
> > +      1. fx_tcbit -> BFD_RELOC_X86_64_CODE_4_GOTTPOFF
> > +      2. fx_tcbit2 -> BFD_RELOC_X86_64_CODE_6_GOTTPOFF
> > +    BFD_RELOC_X86_64_GOTPC32_TLSDESC:
> > +      1. fx_tcbit -> BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC
> > +    BFD_RELOC_32_PCREL:
> > +      1. fx_tcbit -> BFD_RELOC_X86_64_GOTPCRELX
> > +      2. fx_tcbit2 -> BFD_RELOC_X86_64_REX_GOTPCRELX
> > +      3. fx_tcbit3 -> BFD_RELOC_X86_64_CODE_4_GOTPCRELX
> > +      4. else -> BFD_RELOC_X86_64_GOTPCREL
> > +   */
> > +  if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF)
> >      {
> > -      if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF)
> > +      if (fixp->fx_tcbit)
> >         fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTTPOFF;
> > -      else if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC)
> > -       fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC;
> > +      else if (fixp->fx_tcbit2)
> > +       fixp->fx_r_type = BFD_RELOC_X86_64_CODE_6_GOTTPOFF;
> >      }
> > +  else if (fixp->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC
> > +          && fixp->fx_tcbit)
> > +    fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC;
> >  #endif
> >
> >    if (fixp->fx_subsy)
> > @@ -17162,15 +17221,12 @@ i386_validate_fix (fixS *fixp)
> >               if (!object_64bit)
> >                 abort ();
> >  #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
> > -             if (fixp->fx_tcbit2)
> > -               {
> > -                 if (fixp->fx_tcbit3)
> > -                   fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPCRELX;
> > -                 else
> > -                   fixp->fx_r_type = (fixp->fx_tcbit
> > -                                      ? BFD_RELOC_X86_64_REX_GOTPCRELX
> > -                                      : BFD_RELOC_X86_64_GOTPCRELX);
> > -               }
> > +             if (fixp->fx_tcbit)
> > +               fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCRELX;
> > +             else if (fixp->fx_tcbit2)
> > +               fixp->fx_r_type = BFD_RELOC_X86_64_REX_GOTPCRELX;
> > +             else if (fixp->fx_tcbit3)
> > +               fixp->fx_r_type = BFD_RELOC_X86_64_CODE_4_GOTPCRELX;
> >               else
> >  #endif
> >                 fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
> > @@ -17296,6 +17352,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
> >      case BFD_RELOC_X86_64_DTPOFF64:
> >      case BFD_RELOC_X86_64_GOTTPOFF:
> >      case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> > +    case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
> >      case BFD_RELOC_X86_64_TPOFF32:
> >      case BFD_RELOC_X86_64_TPOFF64:
> >      case BFD_RELOC_X86_64_GOTOFF64:
> > @@ -17440,6 +17497,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
> >           case BFD_RELOC_X86_64_TLSLD:
> >           case BFD_RELOC_X86_64_GOTTPOFF:
> >           case BFD_RELOC_X86_64_CODE_4_GOTTPOFF:
> > +         case BFD_RELOC_X86_64_CODE_6_GOTTPOFF:
> >           case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
> >           case BFD_RELOC_X86_64_CODE_4_GOTPC32_TLSDESC:
> >           case BFD_RELOC_X86_64_TLSDESC_CALL:
> > diff --git a/gas/testsuite/gas/i386/x86-64-gottpoff.d b/gas/testsuite/gas/i386/x86-64-gottpoff.d
> > index d42abccc6d9..f2c039abe72 100644
> > --- a/gas/testsuite/gas/i386/x86-64-gottpoff.d
> > +++ b/gas/testsuite/gas/i386/x86-64-gottpoff.d
> > @@ -16,4 +16,8 @@ Disassembly of section .text:
> >   +[a-f0-9]+:   48 8b 05 00 00 00 00    mov    0x0\(%rip\),%rax        # 2c <_start\+0x2c>      28: R_X86_64_GOTTPOFF   foo-0x4
> >   +[a-f0-9]+:   d5 48 03 05 00 00 00 00         add    0x0\(%rip\),%r16        # 34 <_start\+0x34>      30: R_X86_64_CODE_4_GOTTPOFF    foo-0x4
> >   +[a-f0-9]+:   d5 48 8b 25 00 00 00 00         mov    0x0\(%rip\),%r20        # 3c <_start\+0x3c>      38: R_X86_64_CODE_4_GOTTPOFF    foo-0x4
> > + +[a-f0-9]+:   62 74 fc 10 01 05 00 00 00 00   add    %r8,0x0\(%rip\),%r16        # 46 <_start\+0x46>  42: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> > + +[a-f0-9]+:   62 f4 9c 18 03 05 00 00 00 00   add    0x0\(%rip\),%rax,%r12        # 50 <_start\+0x50> 4c: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> > + +[a-f0-9]+:   62 74 fc 10 01 05 00 00 00 00   add    %r8,0x0\(%rip\),%r16        # 5a <_start\+0x5a>  56: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> > + +[a-f0-9]+:   62 f4 9c 18 03 05 00 00 00 00   add    0x0\(%rip\),%rax,%r12        # 64 <_start\+0x64> 60: R_X86_64_CODE_6_GOTTPOFF    foo-0x4
> >  #pass
> > diff --git a/gas/testsuite/gas/i386/x86-64-gottpoff.s b/gas/testsuite/gas/i386/x86-64-gottpoff.s
> > index 6f8f9d1480c..0335ec5debf 100644
> > --- a/gas/testsuite/gas/i386/x86-64-gottpoff.s
> > +++ b/gas/testsuite/gas/i386/x86-64-gottpoff.s
> > @@ -13,3 +13,13 @@ _start:
> >
> >         addq    r16, QWORD PTR [rip + foo@GOTTPOFF]
> >         movq    r20, QWORD PTR [rip + foo@GOTTPOFF]
> > +
> > +       .att_syntax prefix
> > +
> > +       addq    %r8, foo@GOTTPOFF(%rip), %r16
> > +       addq    foo@GOTTPOFF(%rip), %rax, %r12
> > +
> > +       .intel_syntax noprefix
> > +
> > +       addq    r16, QWORD PTR [rip + foo@GOTTPOFF], r8
> > +       addq    r12, rax, QWORD PTR [rip + foo@GOTTPOFF]
> > diff --git a/gold/testsuite/x86_64_ie_to_le.s b/gold/testsuite/x86_64_ie_to_le.s
> > index c5752068866..bd0643dc87f 100644
> > --- a/gold/testsuite/x86_64_ie_to_le.s
> > +++ b/gold/testsuite/x86_64_ie_to_le.s
> > @@ -7,6 +7,8 @@ _start:
> >         movq    foo@gottpoff(%rip), %rax
> >         addq    foo@gottpoff(%rip), %r16
> >         movq    foo@gottpoff(%rip), %r20
> > +       addq    %r30, foo@gottpoff(%rip), %r8
> > +       addq    foo@gottpoff(%rip), %rax, %r20
> >         .size   _start, .-_start
> >         .section        .tdata,"awT",@progbits
> >         .align 4
> > diff --git a/gold/testsuite/x86_64_ie_to_le.sh b/gold/testsuite/x86_64_ie_to_le.sh
> > index 9d2e082f3e0..5308712ddbd 100755
> > --- a/gold/testsuite/x86_64_ie_to_le.sh
> > +++ b/gold/testsuite/x86_64_ie_to_le.sh
> > @@ -27,3 +27,5 @@ grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r12" x86_64_ie_to_le.stdout
> >  grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%rax" x86_64_ie_to_le.stdout
> >  grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r16" x86_64_ie_to_le.stdout
> >  grep -q "mov[ \t]\+\$0x[a-f0-9]\+,%r20" x86_64_ie_to_le.stdout
> > +grep -q "add[ \t]\+\$0x[a-f0-9]\+,%r30,%r8" x86_64_ie_to_le.stdout
> > +grep -q "add[ \t]\+\$0x[a-f0-9]\+,%rax,%r20" x86_64_ie_to_le.stdout
> > diff --git a/gold/x86_64.cc b/gold/x86_64.cc
> > index 58e191a055a..f77430bfb3d 100644
> > --- a/gold/x86_64.cc
> > +++ b/gold/x86_64.cc
> > @@ -2920,6 +2920,11 @@ Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type,
> >        // Another Local-Dynamic reloc.
> >        return tls::TLSOPT_TO_LE;
> >
> > +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> > +      if (r_offset <= 6 || *(reloc_view - 6) != 0x62)
> > +       return tls::TLSOPT_NONE;
> > +      goto handle_gottpoff;
> > +
> >      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> >        if (r_offset <= 4 || *(reloc_view - 4) != 0xd5)
> >         return tls::TLSOPT_NONE;
> > @@ -2929,6 +2934,7 @@ Target_x86_64<size>::optimize_tls_reloc(bool is_final, int r_type,
> >        // from the GOT.  If we know that we are linking against the
> >        // local symbol, we can switch to Local-Exec, which links the
> >        // thread offset into the instruction.
> > +handle_gottpoff:
> >        if (is_final)
> >         return tls::TLSOPT_TO_LE;
> >        return tls::TLSOPT_NONE;
> > @@ -2997,6 +3003,7 @@ Target_x86_64<size>::Scan::get_reference_flags(unsigned int r_type)
> >      case elfcpp::R_X86_64_DTPOFF64:
> >      case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
> >      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> > +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> >      case elfcpp::R_X86_64_TPOFF32:          // Local-exec
> >        return Symbol::TLS_REF;
> >
> > @@ -3362,6 +3369,7 @@ need_got:
> >        // These are initial tls relocs, which are expected when linking
> >      case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
> >      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> > +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> >        {
> >         section_size_type stype;
> >         reloc_view = object->section_contents(data_shndx, &stype, true);
> > @@ -3464,6 +3472,7 @@ need_got:
> >
> >           case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
> >           case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> > +         case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> >             layout->set_has_static_tls();
> >             if (optimized_type == tls::TLSOPT_NONE)
> >               {
> > @@ -3902,6 +3911,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
> >        // These are initial tls relocs, which are expected for global()
> >      case elfcpp::R_X86_64_CODE_4_GOTPC32_TLSDESC:
> >      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> > +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> >        {
> >         section_size_type stype;
> >         reloc_view = object->section_contents(data_shndx, &stype, true);
> > @@ -3920,7 +3930,8 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
> >         // when building an executable.
> >         const bool is_final = (gsym->final_value_is_known() ||
> >                                ((r_type == elfcpp::R_X86_64_GOTTPOFF ||
> > -                                r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF) &&
> > +                                r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF||
> > +                                r_type == elfcpp::R_X86_64_CODE_6_GOTTPOFF) &&
> >                                 gsym->is_undefined() &&
> >                                 parameters->options().output_is_executable()));
> >         size_t r_offset = reloc.get_r_offset();
> > @@ -4006,6 +4017,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
> >
> >           case elfcpp::R_X86_64_GOTTPOFF:    // Initial-exec
> >           case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> > +         case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> >             layout->set_has_static_tls();
> >             if (optimized_type == tls::TLSOPT_NONE)
> >               {
> > @@ -4608,6 +4620,7 @@ Target_x86_64<size>::Relocate::relocate(
> >      case elfcpp::R_X86_64_DTPOFF64:
> >      case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
> >      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> > +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> >      case elfcpp::R_X86_64_TPOFF32:          // Local-exec
> >        this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval,
> >                          view, address, view_size);
> > @@ -4894,6 +4907,7 @@ Target_x86_64<size>::Relocate::relocate_tls(
> >
> >      case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
> >      case elfcpp::R_X86_64_CODE_4_GOTTPOFF:
> > +    case elfcpp::R_X86_64_CODE_6_GOTTPOFF:
> >        if (gsym != NULL
> >           && gsym->is_undefined()
> >           && parameters->options().output_is_executable())
> > @@ -5308,11 +5322,19 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
> >
> >    // movq foo@gottpoff(%rip),%reg  ==>  movq $YY,%reg
> >    // addq foo@gottpoff(%rip),%reg  ==>  addq $YY,%reg
> > +  // addq %reg1,foo@gottpoff(%rip),%reg2  ==>  addq $YY,%reg1,%reg2
> > +  // addq foo@gottpoff(%rip),%reg1,%reg2  ==>  addq $YY,%reg1,%reg2
> >
> > -  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
> > +  int off1;
> > +  if (r_type == elfcpp::R_X86_64_CODE_6_GOTTPOFF)
> > +    off1 = -5;
> > +  else
> > +    off1 = -3;
> > +
> > +  tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, off1);
> >    tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
> >
> > -  unsigned char op1 = view[-3];
> > +  unsigned char op1 = view[off1];
> >    unsigned char op2 = view[-2];
> >    unsigned char op3 = view[-1];
> >    unsigned char reg = op3 >> 3;
> > @@ -5350,7 +5372,7 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
> >           view[-1] = 0x80 | reg | (reg << 3);
> >         }
> >      }
> > -  else
> > +  else if (r_type == elfcpp::R_X86_64_CODE_4_GOTTPOFF)
> >      {
> >        if (op2 == 0x8b)
> >         op2 = 0xc7;
> > @@ -5362,6 +5384,23 @@ Target_x86_64<size>::Relocate::tls_ie_to_le(
> >        view[-2] = op2;
> >        view[-1] = 0xc0 | reg;
> >      }
> > +  else
> > +    {
> > +      unsigned char updated_op1 = op1;
> > +
> > +      // Set the R bits since they is inverted.
> > +      updated_op1 |= 1 << 7 | 1 << 4;
> > +
> > +      // Update the B bits from the R bits.
> > +      if ((op1 & (1 << 7)) == 0)
> > +       updated_op1 &= ~(1 << 5);
> > +      if ((op1 & (1 << 4)) == 0)
> > +       updated_op1 |= 1 << 3;
> > +
> > +      view[-5] = updated_op1;
> > +      view[-2] = 0x81;
> > +      view[-1] = 0xc0 | reg;
> > +    }
> >
> >    if (tls_segment != NULL)
> >      value -= tls_segment->memsz();
> > diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h
> > index 33a824620a6..ea5036a8bbf 100644
> > --- a/include/elf/x86-64.h
> > +++ b/include/elf/x86-64.h
> > @@ -92,6 +92,26 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_type)
> >       /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
> >         instruction starts at 4 bytes before the relocation offset.  */
> >       RELOC_NUMBER (R_X86_64_CODE_4_GOTPC32_TLSDESC, 45)
> > +     /* Load from 32 bit signed pc relative offset to GOT entry if the
> > +       instruction starts at 5 bytes before the relocation offset,
> > +       relaxable.  */
> > +     RELOC_NUMBER (R_X86_64_CODE_5_GOTPCRELX, 46)
> > +     /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
> > +       instruction starts at 5 bytes before the relocation offset.  */
> > +     RELOC_NUMBER (R_X86_64_CODE_5_GOTPC32_TLSDESC, 47)
> > +    /* PC relative offset to IE GOT entry if the instruction starts at
> > +       5 bytes before the relocation offset.  */
> > +     RELOC_NUMBER (R_X86_64_CODE_5_GOTTPOFF, 48)
> > +     /* Load from 32 bit signed pc relative offset to GOT entry if the
> > +       instruction starts at 6 bytes before the relocation offset,
> > +       relaxable.  */
> > +     RELOC_NUMBER (R_X86_64_CODE_6_GOTPCRELX, 49)
> > +    /* PC relative offset to IE GOT entry if the instruction starts at
> > +       6 bytes before the relocation offset.  */
> > +     RELOC_NUMBER (R_X86_64_CODE_6_GOTTPOFF, 50)
> > +     /* 32 bit signed pc relative offset to TLS descriptor in the GOT if
> > +       instruction starts at 6 bytes before the relocation offset.  */
> > +     RELOC_NUMBER (R_X86_64_CODE_6_GOTPC32_TLSDESC, 51)
> >       RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250)       /* GNU C++ hack  */
> >       RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251)         /* GNU C++ hack  */
> >  END_RELOC_NUMBERS (R_X86_64_max)
> > diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.dd b/ld/testsuite/ld-x86-64/tlsbindesc.dd
> > index 4587cc751b4..be89f38199d 100644
> > --- a/ld/testsuite/ld-x86-64/tlsbindesc.dd
> > +++ b/ld/testsuite/ld-x86-64/tlsbindesc.dd
> > @@ -169,18 +169,42 @@ Disassembly of section .text:
> >   +[0-9a-f]+:   d5 48 03 05 ([0-9a-f]{2} ){3}[  ]+add    0x[0-9a-f]+\(%rip\),%r16 +# [0-9a-f]+ <sG2>
> >  #                              -> R_X86_64_TPOFF64     sG2
> >   +[0-9a-f]+:   00 *
> > + +[0-9a-f]+:   62 f4 fc 10 01 ([0-9a-f]{2} ){2}[       ]+add    %rax,0x[0-9a-f]+\(%rip\),%r16 +# [0-9a-f]+ <sG2>
> > +#                              -> R_X86_64_TPOFF64     sG2
> > + +[0-9a-f]+:   ([0-9a-f]{2} ){3} *
> > + +[0-9a-f]+:   62 f4 fc 10 03 ([0-9a-f]{2} ){2}[       ]+add    0x[0-9a-f]+\(%rip\),%rax,%r16 +# [0-9a-f]+ <sG2>
> > +#                              -> R_X86_64_TPOFF64     sG2
> > + +[0-9a-f]+:   ([0-9a-f]{2} ){3} *
> >  #  IE -> LE against global var defined in exec
> >   +[0-9a-f]+:   d5 18 81 c1 60 ff ff[   ]+add    \$0xf+60,%r17
> >  #                                                      sg1
> >   +[0-9a-f]+:   ff *
> > + +[0-9a-f]+:   62 d4 f4 10 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r8,%r17
> > +#                                                      sg1
> > + +[0-9a-f]+:   ff ff ff *
> > + +[0-9a-f]+:   62 d4 f4 10 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r8,%r17
> > +#                                                      sg1
> > + +[0-9a-f]+:   ff ff ff *
> >  #  IE -> LE against local var
> >   +[0-9a-f]+:   d5 18 81 c2 80 ff ff[   ]+add    \$0xf+80,%r18
> >  #                                                      sl1
> >   +[0-9a-f]+:   ff *
> > + +[0-9a-f]+:   62 d4 fc 18 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r8,%rax
> > +#                                                      sl1
> > + +[0-9a-f]+:   ff ff ff *
> > + +[0-9a-f]+:   62 d4 fc 18 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r8,%rax
> > +#                                                      sl1
> > + +[0-9a-f]+:   ff ff ff *
> >  #  IE -> LE against hidden var
> >   +[0-9a-f]+:   d5 18 81 c3 a0 ff ff[   ]+add    \$0xf+a0,%r19
> >  #                                                      sh1
> >   +[0-9a-f]+:   ff *
> > + +[0-9a-f]+:   62 fc bc 18 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r19,%r8
> > +#                                                      sh1
> > + +[0-9a-f]+:   ff ff ff *
> > + +[0-9a-f]+:   62 fc bc 18 81 ([0-9a-f]{2} ){2}[       ]+add    \$0x[0-9a-f]+,%r19,%r8
> > +#                                                      sh1
> > + +[0-9a-f]+:   ff ff ff *
> >  #  Direct access through %fs
> >  #  IE against global var
> >   +[0-9a-f]+:   d5 48 8b 25 ([0-9a-f]{2} ){3}[  ]+mov    0x[0-9a-f]+\(%rip\),%r20 +# [0-9a-f]+ <sG5>
> > diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.rd b/ld/testsuite/ld-x86-64/tlsbindesc.rd
> > index daaea7a5371..59325b04e19 100644
> > --- a/ld/testsuite/ld-x86-64/tlsbindesc.rd
> > +++ b/ld/testsuite/ld-x86-64/tlsbindesc.rd
> > @@ -15,12 +15,12 @@ Section Headers:
> >   +\[[ 0-9]+\] .dynsym +.*
> >   +\[[ 0-9]+\] .dynstr +.*
> >   +\[[ 0-9]+\] .rela.dyn +.*
> > - +\[[ 0-9]+\] .text +PROGBITS +0+401000 0+1000 0+25d 00 +AX +0 +0 +4096
> > - +\[[ 0-9]+\] .tdata +PROGBITS +0+60125d 0+125d 0+60 00 WAT +0 +0 +1
> > - +\[[ 0-9]+\] .tbss +NOBITS +0+6012bd 0+12bd 0+40 00 WAT +0 +0 +1
> > - +\[[ 0-9]+\] .dynamic +DYNAMIC +0+6012c0 0+12c0 0+100 10 +WA +4 +0 +8
> > - +\[[ 0-9]+\] .got +PROGBITS +0+6013c0 0+13c0 0+20 08 +WA +0 +0 +8
> > - +\[[ 0-9]+\] .got.plt +PROGBITS +0+6013e0 0+13e0 0+18 08 +WA +0 +0 +8
> > + +\[[ 0-9]+\] .text +PROGBITS +0+401000 0+1000 0+2ad 00 +AX +0 +0 +4096
> > + +\[[ 0-9]+\] .tdata +PROGBITS +0+6012ad 0+12ad 0+60 00 WAT +0 +0 +1
> > + +\[[ 0-9]+\] .tbss +NOBITS +0+60130d 0+130d 0+40 00 WAT +0 +0 +1
> > + +\[[ 0-9]+\] .dynamic +DYNAMIC +0+601310 0+1310 0+100 10 +WA +4 +0 +8
> > + +\[[ 0-9]+\] .got +PROGBITS +0+601410 0+1410 0+20 08 +WA +0 +0 +8
> > + +\[[ 0-9]+\] .got.plt +PROGBITS +0+601430 0+1430 0+18 08 +WA +0 +0 +8
> >   +\[[ 0-9]+\] .symtab +.*
> >   +\[[ 0-9]+\] .strtab +.*
> >   +\[[ 0-9]+\] .shstrtab +.*
> > @@ -28,7 +28,7 @@ Key to Flags:
> >  #...
> >
> >  Elf file type is EXEC \(Executable file\)
> > -Entry point 0x401165
> > +Entry point 0x4011b5
> >  There are [0-9]+ program headers, starting at offset [0-9]+
> >
> >  Program Headers:
> > @@ -36,10 +36,10 @@ Program Headers:
> >   +PHDR.*
> >   +INTERP.*
> >  .*Requesting program interpreter.*
> > - +LOAD +0x0+ 0x0+400000 0x0+400000 0x0+125d 0x0+125d R E 0x200000
> > - +LOAD +0x0+125d 0x0+60125d 0x0+60125d 0x0+19b 0x0+19b RW +0x200000
> > - +DYNAMIC +0x0+12c0 0x0+6012c0 0x0+6012c0 0x0+100 0x0+100 RW +0x8
> > - +TLS +0x0+125d 0x0+60125d 0x0+60125d 0x0+60 0x0+a0 R +0x1
> > + +LOAD +0x0+ 0x0+400000 0x0+400000 0x0+12ad 0x0+12ad R E 0x200000
> > + +LOAD +0x0+12ad 0x0+6012ad 0x0+6012ad 0x0+19b 0x0+19b RW +0x200000
> > + +DYNAMIC +0x0+1310 0x0+601310 0x0+601310 0x0+100 0x0+100 RW +0x8
> > + +TLS +0x0+12ad 0x0+6012ad 0x0+6012ad 0x0+60 0x0+a0 R +0x1
> >
> >   Section to Segment mapping:
> >   +Segment Sections...
> > @@ -52,10 +52,10 @@ Program Headers:
> >
> >  Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 4 entries:
> >   +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
> > -0+6013c0 +0+100000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
> > -0+6013c8 +0+200000012 R_X86_64_TPOFF64 +0+ sG2 \+ 0
> > -0+6013d0 +0+300000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
> > -0+6013d8 +0+400000012 R_X86_64_TPOFF64 +0+ sG1 \+ 0
> > +0+601410 +0+100000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
> > +0+601418 +0+200000012 R_X86_64_TPOFF64 +0+ sG2 \+ 0
> > +0+601420 +0+300000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
> > +0+601428 +0+400000012 R_X86_64_TPOFF64 +0+ sG1 \+ 0
> >
> >  Symbol table '\.dynsym' contains [0-9]+ entries:
> >   +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
> > @@ -88,8 +88,8 @@ Symbol table '\.symtab' contains [0-9]+ entries:
> >   +[0-9]+: 0+9c +0 +TLS +LOCAL +DEFAULT +8 bl8
> >  .* FILE +LOCAL +DEFAULT +ABS
> >   +[0-9]+: 0+a0 +0 +TLS +LOCAL +DEFAULT +7 _TLS_MODULE_BASE_
> > - +[0-9]+: 0+6012c0 +0 +OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
> > - +[0-9]+: 0+6013e0 +0 +OBJECT +LOCAL +DEFAULT +11 _GLOBAL_OFFSET_TABLE_
> > + +[0-9]+: 0+601310 +0 +OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
> > + +[0-9]+: 0+601430 +0 +OBJECT +LOCAL +DEFAULT +11 _GLOBAL_OFFSET_TABLE_
> >   +[0-9]+: 0+1c +0 +TLS +GLOBAL +DEFAULT +7 sg8
> >   +[0-9]+: 0+7c +0 +TLS +GLOBAL +DEFAULT +8 bg8
> >   +[0-9]+: 0+74 +0 +TLS +GLOBAL +DEFAULT +8 bg6
> > @@ -104,7 +104,7 @@ Symbol table '\.symtab' contains [0-9]+ entries:
> >   +[0-9]+: 0+58 +0 +TLS +GLOBAL +HIDDEN +7 sh7
> >   +[0-9]+: 0+5c +0 +TLS +GLOBAL +HIDDEN +7 sh8
> >   +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +7 sg1
> > - +[0-9]+: 0+401165 +0 +FUNC +GLOBAL +DEFAULT +6 _start
> > + +[0-9]+: 0+4011b5 +0 +FUNC +GLOBAL +DEFAULT +6 _start
> >   +[0-9]+: 0+4c +0 +TLS +GLOBAL +HIDDEN +7 sh4
> >   +[0-9]+: 0+78 +0 +TLS +GLOBAL +DEFAULT +8 bg7
> >   +[0-9]+: 0+50 +0 +TLS +GLOBAL +HIDDEN +7 sh5
> > diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.s b/ld/testsuite/ld-x86-64/tlsbindesc.s
> > index b80e5f192c0..4747fc1bc30 100644
> > --- a/ld/testsuite/ld-x86-64/tlsbindesc.s
> > +++ b/ld/testsuite/ld-x86-64/tlsbindesc.s
> > @@ -129,15 +129,23 @@ fn2:
> >
> >         /* IE against global var  */
> >         addq    sG2@gottpoff(%rip), %r16
> > +       addq    %rax, sG2@gottpoff(%rip), %r16
> > +       addq    sG2@gottpoff(%rip), %rax, %r16
> >
> >         /* IE -> LE against global var defined in exec */
> >         addq    sg1@gottpoff(%rip), %r17
> > +       addq    %r8, sg1@gottpoff(%rip), %r17
> > +       addq    sg1@gottpoff(%rip), %r8, %r17
> >
> >         /* IE -> LE against local var */
> >         addq    sl1@gottpoff(%rip), %r18
> > +       addq    %r8, sl1@gottpoff(%rip), %rax
> > +       addq    sl1@gottpoff(%rip), %r8, %rax
> >
> >         /* IE -> LE against hidden var */
> >         addq    sh1@gottpoff(%rip), %r19
> > +       addq    %r19, sh1@gottpoff(%rip), %r8
> > +       addq    sh1@gottpoff(%rip), %r19, %r8
> >
> >         /* Direct access through %fs  */
> >
> > --
> > 2.43.0
> >
>
> I am checking it in.
>
> --
> H.J.

I am backporting it to 2.42 branch.

-- 
H.J.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-02-10 16:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-07 12:42 [PATCH v2] x86-64: Add R_X86_64_CODE_6_GOTTPOFF H.J. Lu
2024-02-08 11:41 ` H.J. Lu
2024-02-10 16:22   ` H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).