public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] MIPS: support PCREL GOT access
@ 2024-01-31  8:32 YunQiang Su
  2024-01-31  9:24 ` Xi Ruoyao
  0 siblings, 1 reply; 12+ messages in thread
From: YunQiang Su @ 2024-01-31  8:32 UTC (permalink / raw)
  To: nickc; +Cc: binutils, macro

Current if we need to access a GOT entry, we use the
got_base + offset. Thus we have GOT and XGOT.
From MIPSr6, we have PCREL instructions like ALUIPC,
so we have no need to use got_base now.

In this patch, we add 4 new relocs:
	R_MIPS_GOTPC_HI16, R_MIPS_GOTPC_LO16,
	R_MIPS_GOTPC_CALL_HI16, R_MIPS_GOTPC_CALL_LO16,
and the asm notes for them:
	%gotpc_hi(sym), %gotpc_lo(sym)
	%gotpc_call_hi(sym), %gotpc_call_lo(sym).

And we add 3 new BFD_RELOCS for function calling:
	BFD_RELOC_LO16_GOTOFF_CALL,
	BFD_RELOC_HI16_GOTOFF_CALL,
	BFD_RELOC_HI16_S_GOTOFF_CALL.

We use BFD_RELOC_ values like:
	BFD_RELOC_HI16_S_GOTOFF -> R_MIPS_GOTPC_HI16
	BFD_RELOC_LO16_GOTOFF -> R_MIPS_GOTPC_LO16
	BFD_RELOC_HI16_S_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_HI16
	BFD_RELOC_LO16_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_LO16.

Note: the relocation is different for r6 and pre-r6.
For r6, we use aluipc, which will unset the lower 16bit of
result.

The ASM examples is like this:
R6:
	aluipc	$2,%gotpc_hi(sym)
	lw	$2,%gotpc_lo(sym)($2)

Pre-R6:
	bal	. + 8
	lui	$2,%gotpc_hi(sym)
	addiu	$2,$2,$ra
	lw	$2,%gotpc_lo(sym)($2)
---
 bfd/bfd-in2.h        |  3 ++
 bfd/elf32-mips.c     | 62 ++++++++++++++++++++++++++++++++++-
 bfd/elf64-mips.c     | 62 ++++++++++++++++++++++++++++++++++-
 bfd/elfn32-mips.c    | 62 ++++++++++++++++++++++++++++++++++-
 bfd/elfxx-mips.c     | 78 ++++++++++++++++++++++++++++++++++++++++++--
 bfd/libbfd.h         |  3 ++
 bfd/reloc.c          |  6 ++++
 elfcpp/mips.h        |  2 ++
 gas/config/tc-mips.c | 29 +++++++++++++++-
 include/elf/mips.h   |  6 +++-
 10 files changed, 305 insertions(+), 8 deletions(-)

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 581d8fe0b3e..a7d24d216f4 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3313,6 +3313,9 @@ enum bfd_reloc_code_real
   BFD_RELOC_HI16_PLTOFF,
   BFD_RELOC_HI16_S_PLTOFF,
   BFD_RELOC_8_PLTOFF,
+  BFD_RELOC_LO16_GOTOFF_CALL,
+  BFD_RELOC_HI16_GOTOFF_CALL,
+  BFD_RELOC_HI16_S_GOTOFF_CALL,
 
   /* Size relocations.  */
   BFD_RELOC_SIZE32,
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index 63d7334dd52..e2187d442a4 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -809,6 +809,62 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
 	 0x0000ffff,		/* src_mask */
 	 0x0000ffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
 };
 
 /* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link.  This
@@ -2030,7 +2086,11 @@ static const struct elf_reloc_map mips_reloc_map[] =
   { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
   { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
   { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
-  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
+  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
+  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
+  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
+  { BFD_RELOC_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
+  { BFD_RELOC_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 }
 };
 
 static const struct elf_reloc_map mips16_reloc_map[] =
diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
index 489a461bb0b..5ab49b22ce5 100644
--- a/bfd/elf64-mips.c
+++ b/bfd/elf64-mips.c
@@ -889,6 +889,62 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
 	 0x0000ffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
 
+  HOWTO (R_MIPS_GOTPC_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
 };
 
 /* The relocation table used for SHT_RELA sections.  */
@@ -3743,7 +3799,11 @@ static const struct elf_reloc_map mips_reloc_map[] =
   { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
   { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
   { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
-  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
+  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
+  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
+  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
+  { BFD_RELOC_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
+  { BFD_RELOC_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 }
 };
 
 static const struct elf_reloc_map mips16_reloc_map[] =
diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c
index 7e672200006..79d5cb2c840 100644
--- a/bfd/elfn32-mips.c
+++ b/bfd/elfn32-mips.c
@@ -868,6 +868,62 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
 	 0x0000ffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
 
+  HOWTO (R_MIPS_GOTPC_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
 };
 
 /* The relocation table used for SHT_RELA sections.  */
@@ -3577,7 +3633,11 @@ static const struct elf_reloc_map mips_reloc_map[] =
   { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
   { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
   { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
-  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
+  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
+  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
+  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
+  { BFD_RELOC_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
+  { BFD_RELOC_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 }
 };
 
 static const struct elf_reloc_map mips16_reloc_map[] =
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 69dd71419ff..0f3279d7b63 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -2267,19 +2267,25 @@ got_page_reloc_p (unsigned int r_type)
 static inline bool
 got_lo16_reloc_p (unsigned int r_type)
 {
-  return r_type == R_MIPS_GOT_LO16 || r_type == R_MICROMIPS_GOT_LO16;
+  return r_type == R_MIPS_GOT_LO16
+	 || r_type == R_MIPS_GOTPC_LO16
+	 || r_type == R_MICROMIPS_GOT_LO16;
 }
 
 static inline bool
 call_hi16_reloc_p (unsigned int r_type)
 {
-  return r_type == R_MIPS_CALL_HI16 || r_type == R_MICROMIPS_CALL_HI16;
+  return r_type == R_MIPS_CALL_HI16
+	 || r_type == R_MIPS_GOTPC_CALL_HI16
+	 || r_type == R_MICROMIPS_CALL_HI16;
 }
 
 static inline bool
 call_lo16_reloc_p (unsigned int r_type)
 {
-  return r_type == R_MIPS_CALL_LO16 || r_type == R_MICROMIPS_CALL_LO16;
+  return r_type == R_MIPS_CALL_LO16
+	 || r_type == R_MIPS_GOTPC_CALL_LO16
+	 || r_type == R_MICROMIPS_CALL_LO16;
 }
 
 static inline bool
@@ -5241,6 +5247,21 @@ mips_elf_highest (bfd_vma value ATTRIBUTE_UNUSED)
   return MINUS_ONE;
 #endif
 }
+
+/**/
+static bfd_vma
+mips_elf_16bit_align(bfd_vma value, bfd_vma p, bool hi)
+{
+  bfd_vma value_lo = (value & 0xffff) + (p & 0xffff);
+  bfd_vma value_hi = (value >> 16) & 0xffff;
+  value_hi += mips_elf_high (value_lo);
+  value_lo &= 0xffff;
+  if (hi)
+    return value_hi;
+  else
+    return value_lo;
+}
+
 \f
 /* Create the .compact_rel section.  */
 
@@ -5888,6 +5909,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MIPS_GOT_DISP:
     case R_MIPS_GOT_LO16:
     case R_MIPS_CALL_LO16:
+    case R_MIPS_GOTPC_LO16:
+    case R_MIPS_GOTPC_CALL_LO16:
     case R_MICROMIPS_CALL16:
     case R_MICROMIPS_GOT16:
     case R_MICROMIPS_GOT_PAGE:
@@ -5905,6 +5928,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       /* Fall through.  */
     case R_MIPS_GOT_HI16:
     case R_MIPS_CALL_HI16:
+    case R_MIPS_GOTPC_HI16:
+    case R_MIPS_GOTPC_CALL_HI16:
     case R_MICROMIPS_GOT_HI16:
     case R_MICROMIPS_CALL_HI16:
       if (resolved_to_zero
@@ -5952,6 +5977,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MIPS_CALL_HI16:
     case R_MIPS_GOT_LO16:
     case R_MIPS_CALL_LO16:
+    case R_MIPS_GOTPC_HI16:
+    case R_MIPS_GOTPC_LO16:
+    case R_MIPS_GOTPC_CALL_HI16:
+    case R_MIPS_GOTPC_CALL_LO16:
     case R_MICROMIPS_CALL16:
     case R_MICROMIPS_GOT16:
     case R_MICROMIPS_GOT_DISP:
@@ -6413,6 +6442,37 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       value &= howto->dst_mask;
       break;
 
+    /* Pre-R6, we use
+	bal	. + 8
+	lui	$2,%gotpc_hi(sym)
+	addu	$2,$2,$ra
+	lw	$2,%gotpc_lo(sym)
+       In this case, the LO should +=4, and HI should -=4.
+
+       For R6+, we use
+	aluipc	$2,%gotpc_hi(sym)
+	lw	$2,%gotpc_lo(sym)($2)
+       In this case, the HI is OK, while LO should +4 and add the page_offet */
+    case R_MIPS_GOTPC_HI16:
+    case R_MIPS_GOTPC_CALL_HI16:
+      if (MIPSR6_P (abfd))
+	value = mips_elf_16bit_align (addend + gp - p + g, p, true);
+      else
+	value = mips_elf_high (addend + gp - p + g - 4);
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_GOTPC_LO16:
+    case R_MIPS_GOTPC_CALL_LO16:
+      if (howto->partial_inplace)
+	addend = _bfd_mips_elf_sign_extend (addend, 16);
+      if (MIPSR6_P (abfd))
+	value = mips_elf_16bit_align (addend + gp - p + g, p, false);
+      else
+	value = addend + gp - p + g + 4;
+      value &= howto->dst_mask;
+      break;
+
     case R_MIPS_PCHI16:
       value = mips_elf_high (symbol + addend - p);
       value &= howto->dst_mask;
@@ -8282,6 +8342,10 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
     lo16_type = R_MIPS16_LO16;
   else if (micromips_reloc_p (r_type))
     lo16_type = R_MICROMIPS_LO16;
+  else if (r_type == R_MIPS_GOTPC_HI16)
+    lo16_type = R_MIPS_GOTPC_LO16;
+  else if (r_type == R_MIPS_GOTPC_CALL_HI16)
+    lo16_type = R_MIPS_GOTPC_CALL_LO16;
   else if (r_type == R_MIPS_PCHI16)
     lo16_type = R_MIPS_PCLO16;
   else
@@ -8742,6 +8806,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_MIPS_CALL16:
 	case R_MIPS_CALL_HI16:
 	case R_MIPS_CALL_LO16:
+	case R_MIPS_GOTPC_CALL_HI16:
+	case R_MIPS_GOTPC_CALL_LO16:
 	case R_MIPS16_CALL16:
 	case R_MICROMIPS_CALL16:
 	case R_MICROMIPS_CALL_HI16:
@@ -8751,6 +8817,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	case R_MIPS_GOT16:
 	case R_MIPS_GOT_LO16:
+	case R_MIPS_GOTPC_LO16:
 	case R_MIPS_GOT_PAGE:
 	case R_MIPS_GOT_DISP:
 	case R_MIPS16_GOT16:
@@ -8788,6 +8855,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	  /* Fall through.  */
 	case R_MIPS_GOT_HI16:
+	case R_MIPS_GOTPC_HI16:
 	case R_MIPS_GOT_OFST:
 	case R_MIPS_TLS_GOTTPREL:
 	case R_MIPS_TLS_GD:
@@ -8958,6 +9026,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	case R_MIPS_CALL_HI16:
 	case R_MIPS_CALL_LO16:
+	case R_MIPS_GOTPC_CALL_HI16:
+	case R_MIPS_GOTPC_CALL_LO16:
 	case R_MICROMIPS_CALL_HI16:
 	case R_MICROMIPS_CALL_LO16:
 	  if (h != NULL)
@@ -8983,6 +9053,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_MIPS_GOT16:
 	case R_MIPS_GOT_HI16:
 	case R_MIPS_GOT_LO16:
+	case R_MIPS_GOTPC_HI16:
+	case R_MIPS_GOTPC_LO16:
 	case R_MICROMIPS_GOT16:
 	case R_MICROMIPS_GOT_HI16:
 	case R_MICROMIPS_GOT_LO16:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index ebd4f24149b..57bcaab2ab4 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1084,6 +1084,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_HI16_PLTOFF",
   "BFD_RELOC_HI16_S_PLTOFF",
   "BFD_RELOC_8_PLTOFF",
+  "BFD_RELOC_LO16_GOTOFF_CALL",
+  "BFD_RELOC_HI16_GOTOFF_CALL",
+  "BFD_RELOC_HI16_S_GOTOFF_CALL",
   "BFD_RELOC_SIZE32",
   "BFD_RELOC_SIZE64",
   "BFD_RELOC_68K_GLOB_DAT",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index e74cbd75e96..6e8f8712b6b 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -1470,6 +1470,12 @@ ENUMX
   BFD_RELOC_HI16_S_PLTOFF
 ENUMX
   BFD_RELOC_8_PLTOFF
+ENUMX
+  BFD_RELOC_LO16_GOTOFF_CALL
+ENUMX
+  BFD_RELOC_HI16_GOTOFF_CALL
+ENUMX
+  BFD_RELOC_HI16_S_GOTOFF_CALL
 ENUMDOC
   For ELF.
 
diff --git a/elfcpp/mips.h b/elfcpp/mips.h
index e8a8e2458e9..d3c2023f3c5 100644
--- a/elfcpp/mips.h
+++ b/elfcpp/mips.h
@@ -104,6 +104,8 @@ enum
   R_MIPS_PC19_S2 = 63,
   R_MIPS_PCHI16 = 64,
   R_MIPS_PCLO16 = 65,
+  R_MIPS_GOTPC_HI16 = 66,
+  R_MIPS_GOTPC_LO16 = 67,
   // These relocs are used for the mips16.
   R_MIPS16_26 = 100,
   R_MIPS16_GPREL = 101,
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 43c12de2c8a..59a037cb4a3 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -4370,7 +4370,11 @@ limited_pcrel_reloc_p (bfd_reloc_code_real_type reloc)
       return true;
 
     case BFD_RELOC_32_PCREL:
+    case BFD_RELOC_HI16_S_GOTOFF:
+    case BFD_RELOC_LO16_GOTOFF:
     case BFD_RELOC_HI16_S_PCREL:
+    case BFD_RELOC_LO16_GOTOFF_CALL:
+    case BFD_RELOC_HI16_S_GOTOFF_CALL:
     case BFD_RELOC_LO16_PCREL:
       return HAVE_64BIT_ADDRESSES;
 
@@ -7432,6 +7436,7 @@ calculate_reloc (bfd_reloc_code_real_type reloc, offsetT operand,
 
     case BFD_RELOC_HI16_S:
     case BFD_RELOC_HI16_S_PCREL:
+    case BFD_RELOC_HI16_S_GOTOFF:
     case BFD_RELOC_MICROMIPS_HI16_S:
     case BFD_RELOC_MIPS16_HI16_S:
       *result = ((operand + 0x8000) >> 16) & 0xffff;
@@ -7445,6 +7450,8 @@ calculate_reloc (bfd_reloc_code_real_type reloc, offsetT operand,
 
     case BFD_RELOC_LO16:
     case BFD_RELOC_LO16_PCREL:
+    case BFD_RELOC_LO16_GOTOFF:
+    case BFD_RELOC_LO16_GOTOFF_CALL:
     case BFD_RELOC_MICROMIPS_LO16:
     case BFD_RELOC_MIPS16_LO16:
       *result = operand & 0xffff;
@@ -14583,7 +14590,11 @@ static const struct percent_op_match mips_percent_op[] =
   {"%gottprel", BFD_RELOC_MIPS_TLS_GOTTPREL},
   {"%hi", BFD_RELOC_HI16_S},
   {"%pcrel_hi", BFD_RELOC_HI16_S_PCREL},
-  {"%pcrel_lo", BFD_RELOC_LO16_PCREL}
+  {"%pcrel_lo", BFD_RELOC_LO16_PCREL},
+  {"%gotpc_hi", BFD_RELOC_HI16_S_GOTOFF},
+  {"%gotpc_lo", BFD_RELOC_LO16_GOTOFF},
+  {"%gotpc_call_hi", BFD_RELOC_HI16_S_GOTOFF_CALL},
+  {"%gotpc_call_lo", BFD_RELOC_LO16_GOTOFF_CALL}
 };
 
 static const struct percent_op_match mips16_percent_op[] =
@@ -15541,7 +15552,11 @@ mips_force_relocation (fixS *fixp)
 	  || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
 	  || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
 	  || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
+	  || fixp->fx_r_type == BFD_RELOC_HI16_S_GOTOFF
+	  || fixp->fx_r_type == BFD_RELOC_LO16_GOTOFF
 	  || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
+	  || fixp->fx_r_type == BFD_RELOC_LO16_GOTOFF_CALL
+	  || fixp->fx_r_type == BFD_RELOC_HI16_S_GOTOFF_CALL
 	  || fixp->fx_r_type == BFD_RELOC_LO16_PCREL))
     return 1;
 
@@ -15822,6 +15837,10 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       case BFD_RELOC_MIPS_19_PCREL_S2:
       case BFD_RELOC_HI16_S_PCREL:
       case BFD_RELOC_LO16_PCREL:
+      case BFD_RELOC_HI16_S_GOTOFF:
+      case BFD_RELOC_LO16_GOTOFF:
+      case BFD_RELOC_HI16_S_GOTOFF_CALL:
+      case BFD_RELOC_LO16_GOTOFF_CALL:
 	break;
 
       case BFD_RELOC_32:
@@ -15965,6 +15984,10 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS_GOT_LO16:
     case BFD_RELOC_MIPS_CALL_HI16:
     case BFD_RELOC_MIPS_CALL_LO16:
+    case BFD_RELOC_HI16_S_GOTOFF:
+    case BFD_RELOC_LO16_GOTOFF:
+    case BFD_RELOC_HI16_S_GOTOFF_CALL:
+    case BFD_RELOC_LO16_GOTOFF_CALL:
     case BFD_RELOC_HI16_S_PCREL:
     case BFD_RELOC_LO16_PCREL:
     case BFD_RELOC_MIPS16_GPREL:
@@ -18386,7 +18409,11 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 		  || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
 		  || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
 		  || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
+		  || fixp->fx_r_type == BFD_RELOC_HI16_S_GOTOFF
+		  || fixp->fx_r_type == BFD_RELOC_LO16_GOTOFF
 		  || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
+		  || fixp->fx_r_type == BFD_RELOC_LO16_GOTOFF_CALL
+		  || fixp->fx_r_type == BFD_RELOC_HI16_S_GOTOFF_CALL
 		  || fixp->fx_r_type == BFD_RELOC_LO16_PCREL);
 
       /* At this point, fx_addnumber is "symbol offset - pcrel address".
diff --git a/include/elf/mips.h b/include/elf/mips.h
index 686d5500e02..d9a9047b09c 100644
--- a/include/elf/mips.h
+++ b/include/elf/mips.h
@@ -98,7 +98,11 @@ START_RELOC_NUMBERS (elf_mips_reloc_type)
   RELOC_NUMBER (R_MIPS_PC19_S2, 63)
   RELOC_NUMBER (R_MIPS_PCHI16, 64)
   RELOC_NUMBER (R_MIPS_PCLO16, 65)
-  FAKE_RELOC (R_MIPS_max, 66)
+  RELOC_NUMBER (R_MIPS_GOTPC_HI16, 66)
+  RELOC_NUMBER (R_MIPS_GOTPC_LO16, 67)
+  RELOC_NUMBER (R_MIPS_GOTPC_CALL_HI16, 68)
+  RELOC_NUMBER (R_MIPS_GOTPC_CALL_LO16, 69)
+  FAKE_RELOC (R_MIPS_max, 70)
   /* These relocs are used for the mips16.  */
   FAKE_RELOC (R_MIPS16_min, 100)
   RELOC_NUMBER (R_MIPS16_26, 100)
-- 
2.39.2


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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-01-31  8:32 [PATCH] MIPS: support PCREL GOT access YunQiang Su
@ 2024-01-31  9:24 ` Xi Ruoyao
  2024-02-02  1:25   ` YunQiang Su
  0 siblings, 1 reply; 12+ messages in thread
From: Xi Ruoyao @ 2024-01-31  9:24 UTC (permalink / raw)
  To: YunQiang Su, nickc; +Cc: binutils, macro

On Wed, 2024-01-31 at 16:32 +0800, YunQiang Su wrote:
> Note: the relocation is different for r6 and pre-r6.
> For r6, we use aluipc, which will unset the lower 16bit of
> result.

Better use two different names for different semantics.

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-01-31  9:24 ` Xi Ruoyao
@ 2024-02-02  1:25   ` YunQiang Su
  2024-02-05 11:48     ` Nick Clifton
  0 siblings, 1 reply; 12+ messages in thread
From: YunQiang Su @ 2024-02-02  1:25 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: nickc, binutils, macro

Xi Ruoyao <xry111@xry111.site> 于2024年1月31日周三 17:24写道:
>
> On Wed, 2024-01-31 at 16:32 +0800, YunQiang Su wrote:
> > Note: the relocation is different for r6 and pre-r6.
> > For r6, we use aluipc, which will unset the lower 16bit of
> > result.
>
> Better use two different names for different semantics.
>

Thank you. I will update my patch.
Any idea how to write ld testcases?
Normal readelf/objdump can only be sure that it is linked.
I think that we need to execute the out objects to be sure that it has no
problems, such as segfault etc.

> --
> Xi Ruoyao <xry111@xry111.site>
> School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-02-02  1:25   ` YunQiang Su
@ 2024-02-05 11:48     ` Nick Clifton
  2024-02-05 12:59       ` Maciej W. Rozycki
  0 siblings, 1 reply; 12+ messages in thread
From: Nick Clifton @ 2024-02-05 11:48 UTC (permalink / raw)
  To: YunQiang Su, Xi Ruoyao; +Cc: binutils, macro

Hi YunQiang,

> Any idea how to write ld testcases?
> Normal readelf/objdump can only be sure that it is linked.
> I think that we need to execute the out objects to be sure that it has no
> problems, such as segfault etc.

You can use the [isnative] test to check to see if the test
is being run natively and then try executing the linked code.

For example in ld/testsuite/ld-elf/shared.exp there is the
following code to run a linked executable as part of the
mix_pic_and_non_pic procedure:

    if ![isnative] {
	unsupported "Run $exe fun undefined"
	return
     }

     set exec_output [run_host_cmd "tmpdir/$exe" ""]
     if {![string match "PASS" $exec_output]} {
	fail "Run $exe fun undefined"
     } else {
	pass "Run $exe fun undefined"
     }

Cheers
   Nick


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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-02-05 11:48     ` Nick Clifton
@ 2024-02-05 12:59       ` Maciej W. Rozycki
  2024-02-06 16:52         ` YunQiang Su
  0 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2024-02-05 12:59 UTC (permalink / raw)
  To: Nick Clifton; +Cc: YunQiang Su, Xi Ruoyao, binutils

On Mon, 5 Feb 2024, Nick Clifton wrote:

> > Any idea how to write ld testcases?
> > Normal readelf/objdump can only be sure that it is linked.
> > I think that we need to execute the out objects to be sure that it has no
> > problems, such as segfault etc.
> 
> You can use the [isnative] test to check to see if the test
> is being run natively and then try executing the linked code.

 This will limit verification however, especially for such a target as the 
MIPS one, usually found in embedded devices only and therefore typically 
only verified in a cross-environment.  I can't remember when I last run 
verification with the MIPS target natively if ever.  It just takes too 
long for regular use, and it can obviously only cover whatever the subset 
of ISA features is that the native system provides.

 The proper way to handle such verification is to tighten the test cases.  
Relocations have well-defined semantics, so you can prepare sources such 
as to get reproducible output you can then match against.  That means 
verifying exact bit patterns in files produced, and you can arrange for 
boundary cases, such as carry/borrow or overflow, to be verified where 
applicable too.  We have such detailed cases in our testsuite already.

 Relying on run-time tests to crash if a relocation calculation goes wrong 
seems rather fragile to me.  I can imagine errors to cancel each other for 
example.

  Maciej

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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-02-05 12:59       ` Maciej W. Rozycki
@ 2024-02-06 16:52         ` YunQiang Su
  2024-02-06 19:47           ` Maciej W. Rozycki
  0 siblings, 1 reply; 12+ messages in thread
From: YunQiang Su @ 2024-02-06 16:52 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Nick Clifton, Xi Ruoyao, binutils

Maciej W. Rozycki <macro@orcam.me.uk> 于2024年2月5日周一 21:00写道:
>
> On Mon, 5 Feb 2024, Nick Clifton wrote:
>
> > > Any idea how to write ld testcases?
> > > Normal readelf/objdump can only be sure that it is linked.
> > > I think that we need to execute the out objects to be sure that it has no
> > > problems, such as segfault etc.
> >
> > You can use the [isnative] test to check to see if the test
> > is being run natively and then try executing the linked code.
>
>  This will limit verification however, especially for such a target as the
> MIPS one, usually found in embedded devices only and therefore typically
> only verified in a cross-environment.  I can't remember when I last run
> verification with the MIPS target natively if ever.  It just takes too
> long for regular use, and it can obviously only cover whatever the subset
> of ISA features is that the native system provides.
>

Yes. It is a problem, thus I try to use qemu user to run GCC testcase.
In fact not yet for binutils.
https://wiki.debian.org/QemuUserEmulation/GccCheckWithQemuUser

>  The proper way to handle such verification is to tighten the test cases.
> Relocations have well-defined semantics, so you can prepare sources such
> as to get reproducible output you can then match against.  That means
> verifying exact bit patterns in files produced, and you can arrange for
> boundary cases, such as carry/borrow or overflow, to be verified where
> applicable too.  We have such detailed cases in our testsuite already.
>

In fact I am worried that we use the wrong GOT slot, and the ldso
set the GOT incorrectly for use., which is not easy to test statically.
Bit by bit comparison is not easy, due to that the final executables
contains something from libc, which may have quite different versions.

>  Relying on run-time tests to crash if a relocation calculation goes wrong
> seems rather fragile to me.  I can imagine errors to cancel each other for
> example.
>

Yes. We should check statically as possible as we can.

>   Maciej

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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-02-06 16:52         ` YunQiang Su
@ 2024-02-06 19:47           ` Maciej W. Rozycki
  2024-02-25 16:00             ` YunQiang Su
  0 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2024-02-06 19:47 UTC (permalink / raw)
  To: YunQiang Su; +Cc: Nick Clifton, Xi Ruoyao, binutils

On Wed, 7 Feb 2024, YunQiang Su wrote:

> >  The proper way to handle such verification is to tighten the test cases.
> > Relocations have well-defined semantics, so you can prepare sources such
> > as to get reproducible output you can then match against.  That means
> > verifying exact bit patterns in files produced, and you can arrange for
> > boundary cases, such as carry/borrow or overflow, to be verified where
> > applicable too.  We have such detailed cases in our testsuite already.
> >
> 
> In fact I am worried that we use the wrong GOT slot, and the ldso
> set the GOT incorrectly for use., which is not easy to test statically.
> Bit by bit comparison is not easy, due to that the final executables
> contains something from libc, which may have quite different versions.

 You don't have to use libc at link time and using components from outside 
binutils is what makes compiled tests so problematic in our testsuite.  We 
avoid using external components where feasible.

 We can try and do our best to produce correctly linked executables and 
shared libraries and provide testsuite coverage for what we do, and then 
if you want to verify ld.so, then do it with the testsuite for the 
relevant project: glibc, uClibc, musl, whatever.

  Maciej

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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-02-06 19:47           ` Maciej W. Rozycki
@ 2024-02-25 16:00             ` YunQiang Su
  2024-03-01 17:38               ` Maciej W. Rozycki
  0 siblings, 1 reply; 12+ messages in thread
From: YunQiang Su @ 2024-02-25 16:00 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Nick Clifton, Xi Ruoyao, binutils

Maciej W. Rozycki <macro@orcam.me.uk> 于2024年2月7日周三 03:48写道:
>
> On Wed, 7 Feb 2024, YunQiang Su wrote:
>
> > >  The proper way to handle such verification is to tighten the test cases.
> > > Relocations have well-defined semantics, so you can prepare sources such
> > > as to get reproducible output you can then match against.  That means
> > > verifying exact bit patterns in files produced, and you can arrange for
> > > boundary cases, such as carry/borrow or overflow, to be verified where
> > > applicable too.  We have such detailed cases in our testsuite already.
> > >
> >
> > In fact I am worried that we use the wrong GOT slot, and the ldso
> > set the GOT incorrectly for use., which is not easy to test statically.
> > Bit by bit comparison is not easy, due to that the final executables
> > contains something from libc, which may have quite different versions.
>
>  You don't have to use libc at link time and using components from outside
> binutils is what makes compiled tests so problematic in our testsuite.  We
> avoid using external components where feasible.
>
>  We can try and do our best to produce correctly linked executables and
> shared libraries and provide testsuite coverage for what we do, and then

What my plan is (although I have no idea how to archive it with dejagnu):
   1. f.c
       int f() {return 0;}
       mipsel-linux-gnu-gcc -O2 -mabi=32 f.c -shared -o libf.so
   2. f1.c
       extern int f();
       int f1 () {return f();}
       mipsel-linux-gnu-gcc -O2 f1.c -shared -L. -lf -o libf1.so
   3. Let's inspect libf1.so with `objdump -DTC`
       3.1 We can see the symbol 'f' is in an address, 00000520.
             00000520      DF *UND*  00000000 f
       3.2 We can see a line "00000520 <_MIPS_STUBS_>"
       3.3 We can see the address of .got is "00010570 <__TMC_END__>"
       3.3 We can see " 50c:   8f998040        lw      t9,-32704(gp)"
in <f1>, and
             GOT_ADR   +   GP_MAGIC + LW_OFFSET  = GOT_SLOT_OF_F
             0x00010570 +  0x7ff0           + (-32704)          = 0x105a0
       3.4 The content of address GOT_SLOT_OF_F (0x105a0) is 0x00000520.

@Maciej W. Rozycki Is this correct?

> if you want to verify ld.so, then do it with the testsuite for the
> relevant project: glibc, uClibc, musl, whatever.
>
>   Maciej

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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-02-25 16:00             ` YunQiang Su
@ 2024-03-01 17:38               ` Maciej W. Rozycki
  2024-03-15 13:44                 ` YunQiang Su
  0 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2024-03-01 17:38 UTC (permalink / raw)
  To: YunQiang Su; +Cc: Nick Clifton, Xi Ruoyao, binutils

On Mon, 26 Feb 2024, YunQiang Su wrote:

> >  We can try and do our best to produce correctly linked executables and
> > shared libraries and provide testsuite coverage for what we do, and then
> 
> What my plan is (although I have no idea how to archive it with dejagnu):
>    1. f.c
>        int f() {return 0;}
>        mipsel-linux-gnu-gcc -O2 -mabi=32 f.c -shared -o libf.so
>    2. f1.c
>        extern int f();
>        int f1 () {return f();}
>        mipsel-linux-gnu-gcc -O2 f1.c -shared -L. -lf -o libf1.so

 But why do you want to write this code in C?  It's so trivial you can 
produce assembly for all the ABIs you want to cover (you can even start 
with compiler output if you don't want to handcode it from scratch) and 
use that as the test sources.  We'll be able to verify it reliably then, 
without a need for external components.

>    3. Let's inspect libf1.so with `objdump -DTC`
>        3.1 We can see the symbol 'f' is in an address, 00000520.
>              00000520      DF *UND*  00000000 f
>        3.2 We can see a line "00000520 <_MIPS_STUBS_>"
>        3.3 We can see the address of .got is "00010570 <__TMC_END__>"
>        3.3 We can see " 50c:   8f998040        lw      t9,-32704(gp)"
> in <f1>, and
>              GOT_ADR   +   GP_MAGIC + LW_OFFSET  = GOT_SLOT_OF_F
>              0x00010570 +  0x7ff0           + (-32704)          = 0x105a0
>        3.4 The content of address GOT_SLOT_OF_F (0x105a0) is 0x00000520.

 There are existing test cases in ld/testsuite/ld-mips-elf/mips-elf.exp 
that do various kinds of checks, including running multiple dump tools on 
single linker output.  Check the various `run_ld_link_tests' invocations.  
You can examine GOT entries in a cooked way with `readelf -A' BTW.

  Maciej

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

* Re: [PATCH] MIPS: support PCREL GOT access
  2024-03-01 17:38               ` Maciej W. Rozycki
@ 2024-03-15 13:44                 ` YunQiang Su
  0 siblings, 0 replies; 12+ messages in thread
From: YunQiang Su @ 2024-03-15 13:44 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Nick Clifton, Xi Ruoyao, binutils

Maciej W. Rozycki <macro@orcam.me.uk> 于2024年3月2日周六 01:38写道:
>
> On Mon, 26 Feb 2024, YunQiang Su wrote:
>
> > >  We can try and do our best to produce correctly linked executables and
> > > shared libraries and provide testsuite coverage for what we do, and then
> >
> > What my plan is (although I have no idea how to archive it with dejagnu):
> >    1. f.c
> >        int f() {return 0;}
> >        mipsel-linux-gnu-gcc -O2 -mabi=32 f.c -shared -o libf.so
> >    2. f1.c
> >        extern int f();
> >        int f1 () {return f();}
> >        mipsel-linux-gnu-gcc -O2 f1.c -shared -L. -lf -o libf1.so
>
>  But why do you want to write this code in C?  It's so trivial you can
> produce assembly for all the ABIs you want to cover (you can even start
> with compiler output if you don't want to handcode it from scratch) and
> use that as the test sources.  We'll be able to verify it reliably then,
> without a need for external components.
>

Sure, asm code is preferred by binutils testcase.
The above C examples are just to describe what we need to do.
In the real patch, I will use asm code.

> >    3. Let's inspect libf1.so with `objdump -DTC`
> >        3.1 We can see the symbol 'f' is in an address, 00000520.
> >              00000520      DF *UND*  00000000 f
> >        3.2 We can see a line "00000520 <_MIPS_STUBS_>"
> >        3.3 We can see the address of .got is "00010570 <__TMC_END__>"
> >        3.3 We can see " 50c:   8f998040        lw      t9,-32704(gp)"
> > in <f1>, and
> >              GOT_ADR   +   GP_MAGIC + LW_OFFSET  = GOT_SLOT_OF_F
> >              0x00010570 +  0x7ff0           + (-32704)          = 0x105a0
> >        3.4 The content of address GOT_SLOT_OF_F (0x105a0) is 0x00000520.
>
>  There are existing test cases in ld/testsuite/ld-mips-elf/mips-elf.exp
> that do various kinds of checks, including running multiple dump tools on
> single linker output.  Check the various `run_ld_link_tests' invocations.
> You can examine GOT entries in a cooked way with `readelf -A' BTW.
>

Thanks. I will have a try.

>   Maciej

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

* Re: [PATCH] MIPS: Support PCREL GOT access
  2024-02-02  6:39 [PATCH] MIPS: Support " YunQiang Su
@ 2024-02-02  6:42 ` YunQiang Su
  0 siblings, 0 replies; 12+ messages in thread
From: YunQiang Su @ 2024-02-02  6:42 UTC (permalink / raw)
  To: nickc; +Cc: binutils, macro, xry111

YunQiang Su <syq@gcc.gnu.org> 于2024年2月2日周五 14:39写道:
>
> Current if we need to access a GOT entry, we use the
> got_base + offset. Thus we have GOT and XGOT.
> From MIPSr6, we have PCREL instructions like ALUIPC,
> so we have no need to use got_base now.
> For pre-R6, we can use BAL to get the the value of PC.
>
> In this patch, we add 8 new relocs:
>         R_MIPS_GOTPC_HI16, R_MIPS_GOTPC_LO16,
>         R_MIPS_GOTPC_CALL_HI16, R_MIPS_GOTPC_CALL_LO16,
>         R_MIPS_GOTPC_AHI16, R_MIPS_GOTPC_ALO16,
>         R_MIPS_GOTPC_CALL_AHI16, R_MIPS_GOTPC_CALL_ALO16.
> These asm notes can be used for them:
>         %gotpc_hi(sym), %gotpc_lo(sym),
>         %gotpc_call_hi(sym), %gotpc_call_lo(sym),
>         %gotpc_ahi(sym), %gotpc_alo(sym),
>         %gotpc_call_ahi(sym), %gotpc_call_alo(sym).
>
> 3 new BFD_RELOCS are added for ALUIPC style relocs:
>         BFD_RELOC_MIPS_ALO16_GOTOFF,
>         BFD_RELOC_MIPS_AHI16_GOTOFF,
>         BFD_RELOC_MIPS_AHI16_S_GOTOFF.
>
> 6 new BFD_RELOCS are added for function calling:
>         BFD_RELOC_MIPS_LO16_GOTOFF_CALL,
>         BFD_RELOC_MIPS_HI16_GOTOFF_CALL,
>         BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL,
>         BFD_RELOC_MIPS_ALO16_GOTOFF_CALL,
>         BFD_RELOC_MIPS_AHI16_GOTOFF_CALL,
>         BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL,
>
> The mapping between BFD_RELOC_ and R_MIPS_GOTPC are:
>         BFD_RELOC_HI16_S_GOTOFF -> R_MIPS_GOTPC_HI16
>         BFD_RELOC_LO16_GOTOFF -> R_MIPS_GOTPC_LO16
>         BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_HI16
>         BFD_RELOC_MIPS_LO16_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_LO16.
>         BFD_RELOC_MIPS_AHI16_S_GOTOFF -> R_MIPS_GOTPC_AHI16
>         BFD_RELOC_MIPS_ALO16_GOTOFF -> R_MIPS_GOTPC_ALO16
>         BFD_RELOC_MIPS_MIPS_AHI16_S_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_AHI16
>         BFD_RELOC_MIPS_MIPS_ALO16_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_ALO16.
>
> The difference of BAL and ALUIPC is that ALUIPC will unset the lower 16
> bits of result.
>
> For r6, both styles are supported, and of course ALUIPC style is
> recommended. For pre-R6, only BAL style is supported.
>
> Here are the ASM examples:
> ALUIPC:
>         aluipc  $2,%gotpc_ahi(sym)
>         lw      $2,%gotpc_alo(sym)($2)
>
> BAL:
>         bal     . + 8 # Note: $31 is clobbered here.
>         lui     $2,%gotpc_hi(sym)
>         addiu   $2,$2,$31
>         lw      $2,%gotpc_lo(sym)($2)
>
> gas/ChangeLog:
>         * config/tc-mips.c: Add GOTPC relocs support.
>         * testsuite/gas/mips/mips.exp: Add GOTPC testcases.
>         * testsuite/gas/mips/gotpc-aluipc-32.s: Ditto.
>         * testsuite/gas/mips/gotpc-aluipc-64.s: Ditto.
>         * testsuite/gas/mips/gotpc-aluipc-n64.d: Ditto.
>         * testsuite/gas/mips/gotpc-aluipc-n32.d: Ditto.
>         * testsuite/gas/mips/gotpc-aluipc-o32.d: Ditto.
>         * testsuite/gas/mips/gotpc-bal-32.s: Ditto.
>         * testsuite/gas/mips/gotpc-bal-64.s: Ditto.
>         * testsuite/gas/mips/gotpc-bal-n64.d: Ditto.
>         * testsuite/gas/mips/gotpc-bal-n32.d: Ditto.
>         * testsuite/gas/mips/gotpc-bal-o32.d: Ditto.
>
> bfd/ChangeLog:
>         * elfxx-mips.c: Add GOTPC relocs support.
>         * elf32-mips.c: Ditto.
>         * elf64-mips.c: Ditto.
>         * elfn32-mips.c: Ditto.
>         * bfd-in2.h: Add new MIPS GOTPC BFD_RELOC defination.
>         * reclos.c: Ditto.
>         * libbfd.h: Ditto.
>
> elfcpp/ChangeLog:
>         * mips.h: Add new MIPS GOTPC relocs.
>
> include/ChangeLog:
>         * elf/mips.h (elf_mips_reloc_type): Add new MIPS GOTPC relocs.
> ---
>  bfd/bfd-in2.h                             |  12 ++
>  bfd/elf32-mips.c                          | 123 +++++++++++-
>  bfd/elf64-mips.c                          | 234 +++++++++++++++++++++-
>  bfd/elfn32-mips.c                         | 234 +++++++++++++++++++++-
>  bfd/elfxx-mips.c                          | 107 +++++++++-
>  bfd/libbfd.h                              |   9 +
>  bfd/reloc.c                               |  18 ++
>  elfcpp/mips.h                             |   8 +
>  gas/config/tc-mips.c                      |  72 ++++++-
>  gas/testsuite/gas/mips/gotpc-aluipc-32.s  |  51 +++++
>  gas/testsuite/gas/mips/gotpc-aluipc-64.s  |  50 +++++
>  gas/testsuite/gas/mips/gotpc-aluipc-n32.d |  17 ++
>  gas/testsuite/gas/mips/gotpc-aluipc-n64.d |  25 +++
>  gas/testsuite/gas/mips/gotpc-aluipc-o32.d |  17 ++
>  gas/testsuite/gas/mips/gotpc-bal-32.s     |  55 +++++
>  gas/testsuite/gas/mips/gotpc-bal-64.s     |  54 +++++
>  gas/testsuite/gas/mips/gotpc-bal-n32.d    |  17 ++
>  gas/testsuite/gas/mips/gotpc-bal-n64.d    |  25 +++
>  gas/testsuite/gas/mips/gotpc-bal-o32.d    |  17 ++
>  gas/testsuite/gas/mips/mips.exp           |   8 +
>  include/elf/mips.h                        |  10 +-
>  21 files changed, 1155 insertions(+), 8 deletions(-)
>  create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-32.s
>  create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-64.s
>  create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-n32.d
>  create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-n64.d
>  create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-o32.d
>  create mode 100644 gas/testsuite/gas/mips/gotpc-bal-32.s
>  create mode 100644 gas/testsuite/gas/mips/gotpc-bal-64.s
>  create mode 100644 gas/testsuite/gas/mips/gotpc-bal-n32.d
>  create mode 100644 gas/testsuite/gas/mips/gotpc-bal-n64.d
>  create mode 100644 gas/testsuite/gas/mips/gotpc-bal-o32.d
>
> diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> index 581d8fe0b3e..bce2030f9c5 100644
> --- a/bfd/bfd-in2.h
> +++ b/bfd/bfd-in2.h
> @@ -3654,6 +3654,18 @@ enum bfd_reloc_code_real
>    BFD_RELOC_MIPS_18_PCREL_S3,
>    BFD_RELOC_MIPS_19_PCREL_S2,
>
> +  BFD_RELOC_MIPS_LO16_GOTOFF_CALL,
> +  BFD_RELOC_MIPS_HI16_GOTOFF_CALL,
> +  BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL,
> +
> +  BFD_RELOC_MIPS_ALO16_GOTOFF,
> +  BFD_RELOC_MIPS_AHI16_GOTOFF,
> +  BFD_RELOC_MIPS_AHI16_S_GOTOFF,
> +
> +  BFD_RELOC_MIPS_ALO16_GOTOFF_CALL,
> +  BFD_RELOC_MIPS_AHI16_GOTOFF_CALL,
> +  BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL,
> +
>    /* microMIPS versions of generic BFD relocs.  */
>    BFD_RELOC_MICROMIPS_GPREL16,
>    BFD_RELOC_MICROMIPS_HI16,
> diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
> index 63d7334dd52..7edcc30d331 100644
> --- a/bfd/elf32-mips.c
> +++ b/bfd/elf32-mips.c
> @@ -809,6 +809,119 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
>          0x0000ffff,            /* src_mask */
>          0x0000ffff,            /* dst_mask */
>          true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_HI16,    /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_HI16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_LO16,    /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_LO16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_HI16,       /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_HI16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_LO16,       /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_LO16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_AHI16,   /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_AHI16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_ALO16,   /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_ALO16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_AHI16,      /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_AHI16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_ALO16,      /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_ALO16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
>  };
>
>  /* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link.  This
> @@ -2030,7 +2143,15 @@ static const struct elf_reloc_map mips_reloc_map[] =
>    { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
>    { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
>    { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
> -  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
> +  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
> +  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
> +  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
> +  { BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
> +  { BFD_RELOC_MIPS_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 },
> +  { BFD_RELOC_MIPS_AHI16_S_GOTOFF, R_MIPS_GOTPC_AHI16 },
> +  { BFD_RELOC_MIPS_ALO16_GOTOFF, R_MIPS_GOTPC_ALO16 },
> +  { BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_AHI16 },
> +  { BFD_RELOC_MIPS_ALO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_ALO16 }
>  };
>
>  static const struct elf_reloc_map mips16_reloc_map[] =
> diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
> index 489a461bb0b..dc4e56d1f55 100644
> --- a/bfd/elf64-mips.c
> +++ b/bfd/elf64-mips.c
> @@ -889,6 +889,118 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
>          0x0000ffff,            /* dst_mask */
>          true),                 /* pcrel_offset */
>
> +  HOWTO (R_MIPS_GOTPC_HI16,    /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_HI16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_LO16,    /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_LO16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_HI16,       /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_HI16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_LO16,       /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_LO16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_AHI16,   /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_AHI16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_ALO16,   /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_ALO16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_AHI16,      /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_AHI16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_ALO16,      /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_ALO16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
>  };
>
>  /* The relocation table used for SHT_RELA sections.  */
> @@ -1670,6 +1782,118 @@ static reloc_howto_type mips_elf64_howto_table_rela[] =
>          0x0000ffff,            /* dst_mask */
>          true),                 /* pcrel_offset */
>
> +  HOWTO (R_MIPS_GOTPC_HI16,    /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_HI16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_LO16,    /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_LO16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_HI16,       /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_HI16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_LO16,       /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_LO16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_AHI16,   /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_AHI16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_ALO16,   /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_ALO16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_AHI16,      /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_AHI16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_ALO16,      /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_ALO16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
>  };
>
>  static reloc_howto_type mips16_elf64_howto_table_rel[] =
> @@ -3743,7 +3967,15 @@ static const struct elf_reloc_map mips_reloc_map[] =
>    { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
>    { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
>    { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
> -  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
> +  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
> +  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
> +  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
> +  { BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
> +  { BFD_RELOC_MIPS_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 },
> +  { BFD_RELOC_MIPS_AHI16_S_GOTOFF, R_MIPS_GOTPC_AHI16 },
> +  { BFD_RELOC_MIPS_ALO16_GOTOFF, R_MIPS_GOTPC_ALO16 },
> +  { BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_AHI16 },
> +  { BFD_RELOC_MIPS_ALO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_ALO16 }
>  };
>
>  static const struct elf_reloc_map mips16_reloc_map[] =
> diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c
> index 7e672200006..03e17dfda64 100644
> --- a/bfd/elfn32-mips.c
> +++ b/bfd/elfn32-mips.c
> @@ -868,6 +868,118 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
>          0x0000ffff,            /* dst_mask */
>          true),                 /* pcrel_offset */
>
> +  HOWTO (R_MIPS_GOTPC_HI16,    /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_HI16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_LO16,    /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_LO16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_HI16,       /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_HI16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_LO16,       /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_LO16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_AHI16,   /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_AHI16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_ALO16,   /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_ALO16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_AHI16,      /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_AHI16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_ALO16,      /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_ALO16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
>  };
>
>  /* The relocation table used for SHT_RELA sections.  */
> @@ -1650,6 +1762,118 @@ static reloc_howto_type elf_mips_howto_table_rela[] =
>          0x0000ffff,            /* dst_mask */
>          true),                 /* pcrel_offset */
>
> +  HOWTO (R_MIPS_GOTPC_HI16,    /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_HI16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_LO16,    /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_LO16",   /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_HI16,       /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_HI16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_LO16,       /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_LO16",      /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_AHI16,   /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_AHI16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_ALO16,   /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_ALO16",  /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_AHI16,      /* type */
> +        16,                    /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_signed, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_AHI16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
> +  HOWTO (R_MIPS_GOTPC_CALL_ALO16,      /* type */
> +        0,                     /* rightshift */
> +        4,                     /* size */
> +        16,                    /* bitsize */
> +        true,                  /* pc_relative */
> +        0,                     /* bitpos */
> +        complain_overflow_dont, /* complain_on_overflow */
> +        _bfd_mips_elf_generic_reloc,   /* special_function */
> +        "R_MIPS_GOTPC_CALL_ALO16",     /* name */
> +        true,                  /* partial_inplace */
> +        0x0000ffff,            /* src_mask */
> +        0x0000ffff,            /* dst_mask */
> +        true),                 /* pcrel_offset */
> +
>  };
>
>  static reloc_howto_type elf_mips16_howto_table_rel[] =
> @@ -3577,7 +3801,15 @@ static const struct elf_reloc_map mips_reloc_map[] =
>    { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
>    { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
>    { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
> -  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
> +  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
> +  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
> +  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
> +  { BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
> +  { BFD_RELOC_MIPS_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 },
> +  { BFD_RELOC_MIPS_AHI16_S_GOTOFF, R_MIPS_GOTPC_AHI16 },
> +  { BFD_RELOC_MIPS_ALO16_GOTOFF, R_MIPS_GOTPC_ALO16 },
> +  { BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_AHI16 },
> +  { BFD_RELOC_MIPS_ALO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_ALO16 }
>  };
>
>  static const struct elf_reloc_map mips16_reloc_map[] =
> diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
> index 69dd71419ff..c8a9ceb7524 100644
> --- a/bfd/elfxx-mips.c
> +++ b/bfd/elfxx-mips.c
> @@ -2267,19 +2267,28 @@ got_page_reloc_p (unsigned int r_type)
>  static inline bool
>  got_lo16_reloc_p (unsigned int r_type)
>  {
> -  return r_type == R_MIPS_GOT_LO16 || r_type == R_MICROMIPS_GOT_LO16;
> +  return r_type == R_MIPS_GOT_LO16
> +        || r_type == R_MIPS_GOTPC_LO16
> +        || r_type == R_MIPS_GOTPC_ALO16
> +        || r_type == R_MICROMIPS_GOT_LO16;
>  }
>
>  static inline bool
>  call_hi16_reloc_p (unsigned int r_type)
>  {
> -  return r_type == R_MIPS_CALL_HI16 || r_type == R_MICROMIPS_CALL_HI16;
> +  return r_type == R_MIPS_CALL_HI16
> +        || r_type == R_MIPS_GOTPC_CALL_HI16
> +        || r_type == R_MIPS_GOTPC_CALL_AHI16
> +        || r_type == R_MICROMIPS_CALL_HI16;
>  }
>
>  static inline bool
>  call_lo16_reloc_p (unsigned int r_type)
>  {
> -  return r_type == R_MIPS_CALL_LO16 || r_type == R_MICROMIPS_CALL_LO16;
> +  return r_type == R_MIPS_CALL_LO16
> +        || r_type == R_MIPS_GOTPC_CALL_LO16
> +        || r_type == R_MIPS_GOTPC_CALL_ALO16
> +        || r_type == R_MICROMIPS_CALL_LO16;
>  }
>
>  static inline bool
> @@ -5241,6 +5250,21 @@ mips_elf_highest (bfd_vma value ATTRIBUTE_UNUSED)
>    return MINUS_ONE;
>  #endif
>  }
> +
> +/**/
> +static bfd_vma
> +mips_elf_16bit_align (bfd_vma value, bfd_vma p, bool hi)
> +{
> +  bfd_vma value_lo = (value & 0xffff) + (p & 0xffff);
> +  bfd_vma value_hi = (value >> 16) & 0xffff;
> +  value_hi += mips_elf_high (value_lo);
> +  value_lo &= 0xffff;
> +  if (hi)
> +    return value_hi;
> +  else
> +    return value_lo;
> +}
> +
>
>  /* Create the .compact_rel section.  */
>
> @@ -5888,6 +5912,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
>      case R_MIPS_GOT_DISP:
>      case R_MIPS_GOT_LO16:
>      case R_MIPS_CALL_LO16:
> +    case R_MIPS_GOTPC_LO16:
> +    case R_MIPS_GOTPC_CALL_LO16:
> +    case R_MIPS_GOTPC_ALO16:
> +    case R_MIPS_GOTPC_CALL_ALO16:
>      case R_MICROMIPS_CALL16:
>      case R_MICROMIPS_GOT16:
>      case R_MICROMIPS_GOT_PAGE:
> @@ -5905,6 +5933,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
>        /* Fall through.  */
>      case R_MIPS_GOT_HI16:
>      case R_MIPS_CALL_HI16:
> +    case R_MIPS_GOTPC_HI16:
> +    case R_MIPS_GOTPC_CALL_HI16:
>      case R_MICROMIPS_GOT_HI16:
>      case R_MICROMIPS_CALL_HI16:
>        if (resolved_to_zero
> @@ -5952,6 +5982,14 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
>      case R_MIPS_CALL_HI16:
>      case R_MIPS_GOT_LO16:
>      case R_MIPS_CALL_LO16:
> +    case R_MIPS_GOTPC_HI16:
> +    case R_MIPS_GOTPC_LO16:
> +    case R_MIPS_GOTPC_CALL_HI16:
> +    case R_MIPS_GOTPC_CALL_LO16:
> +    case R_MIPS_GOTPC_AHI16:
> +    case R_MIPS_GOTPC_ALO16:
> +    case R_MIPS_GOTPC_CALL_AHI16:
> +    case R_MIPS_GOTPC_CALL_ALO16:
>      case R_MICROMIPS_CALL16:
>      case R_MICROMIPS_GOT16:
>      case R_MICROMIPS_GOT_DISP:
> @@ -6413,6 +6451,45 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
>        value &= howto->dst_mask;
>        break;
>
> +    /* For r6 and pre-r6, we can use:
> +       bal     . + 8
> +       lui     $2,%gotpc_hi(sym) # or %gotpc_call_hi
> +       addu    $2,$2,$ra
> +       lw      $2,%gotpc_lo(sym) # or %gotpc_call_lo
> +       In this case, the LO should +=4, and HI should -=4.
> +
> +       For R6+, we can use
> +       aluipc  $2,%gotpc_ahi(sym) # or %gotpc_call_ahi
> +       lw      $2,%gotpc_alo(sym)($2) or %gotpc_call_alo
> +       In this case, the HI is OK, while LO should +4 and add the page_offet */
> +    case R_MIPS_GOTPC_HI16:
> +    case R_MIPS_GOTPC_CALL_HI16:
> +      value = mips_elf_high (addend + gp - p + g - 4);
> +      value &= howto->dst_mask;
> +      break;
> +
> +    case R_MIPS_GOTPC_LO16:
> +    case R_MIPS_GOTPC_CALL_LO16:
> +      if (howto->partial_inplace)
> +       addend = _bfd_mips_elf_sign_extend (addend, 16);
> +      value = addend + gp - p + g + 4;
> +      value &= howto->dst_mask;
> +      break;
> +
> +    case R_MIPS_GOTPC_AHI16:
> +    case R_MIPS_GOTPC_CALL_AHI16:
> +      value = mips_elf_16bit_align (addend + gp - p + g, p, true);
> +      value &= howto->dst_mask;
> +      break;
> +
> +    case R_MIPS_GOTPC_ALO16:
> +    case R_MIPS_GOTPC_CALL_ALO16:
> +      if (howto->partial_inplace)
> +       addend = _bfd_mips_elf_sign_extend (addend, 16);
> +      value = mips_elf_16bit_align (addend + gp - p + g, p, false);
> +      value &= howto->dst_mask;
> +      break;
> +
>      case R_MIPS_PCHI16:
>        value = mips_elf_high (symbol + addend - p);
>        value &= howto->dst_mask;
> @@ -8282,6 +8359,14 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
>      lo16_type = R_MIPS16_LO16;
>    else if (micromips_reloc_p (r_type))
>      lo16_type = R_MICROMIPS_LO16;
> +  else if (r_type == R_MIPS_GOTPC_HI16)
> +    lo16_type = R_MIPS_GOTPC_LO16;
> +  else if (r_type == R_MIPS_GOTPC_CALL_HI16)
> +    lo16_type = R_MIPS_GOTPC_CALL_LO16;
> +  else if (r_type == R_MIPS_GOTPC_AHI16)
> +    lo16_type = R_MIPS_GOTPC_ALO16;
> +  else if (r_type == R_MIPS_GOTPC_CALL_AHI16)
> +    lo16_type = R_MIPS_GOTPC_CALL_ALO16;
>    else if (r_type == R_MIPS_PCHI16)
>      lo16_type = R_MIPS_PCLO16;
>    else
> @@ -8742,6 +8827,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
>         case R_MIPS_CALL16:
>         case R_MIPS_CALL_HI16:
>         case R_MIPS_CALL_LO16:
> +       case R_MIPS_GOTPC_CALL_HI16:
> +       case R_MIPS_GOTPC_CALL_LO16:
> +       case R_MIPS_GOTPC_CALL_AHI16:
> +       case R_MIPS_GOTPC_CALL_ALO16:
>         case R_MIPS16_CALL16:
>         case R_MICROMIPS_CALL16:
>         case R_MICROMIPS_CALL_HI16:
> @@ -8751,6 +8840,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
>
>         case R_MIPS_GOT16:
>         case R_MIPS_GOT_LO16:
> +       case R_MIPS_GOTPC_LO16:
> +       case R_MIPS_GOTPC_ALO16:
>         case R_MIPS_GOT_PAGE:
>         case R_MIPS_GOT_DISP:
>         case R_MIPS16_GOT16:
> @@ -8788,6 +8879,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
>
>           /* Fall through.  */
>         case R_MIPS_GOT_HI16:
> +       case R_MIPS_GOTPC_HI16:
> +       case R_MIPS_GOTPC_AHI16:
>         case R_MIPS_GOT_OFST:
>         case R_MIPS_TLS_GOTTPREL:
>         case R_MIPS_TLS_GD:
> @@ -8958,6 +9051,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
>
>         case R_MIPS_CALL_HI16:
>         case R_MIPS_CALL_LO16:
> +       case R_MIPS_GOTPC_CALL_HI16:
> +       case R_MIPS_GOTPC_CALL_LO16:
> +       case R_MIPS_GOTPC_CALL_AHI16:
> +       case R_MIPS_GOTPC_CALL_ALO16:
>         case R_MICROMIPS_CALL_HI16:
>         case R_MICROMIPS_CALL_LO16:
>           if (h != NULL)
> @@ -8983,6 +9080,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
>         case R_MIPS_GOT16:
>         case R_MIPS_GOT_HI16:
>         case R_MIPS_GOT_LO16:
> +       case R_MIPS_GOTPC_HI16:
> +       case R_MIPS_GOTPC_LO16:
> +       case R_MIPS_GOTPC_AHI16:
> +       case R_MIPS_GOTPC_ALO16:
>         case R_MICROMIPS_GOT16:
>         case R_MICROMIPS_GOT_HI16:
>         case R_MICROMIPS_GOT_LO16:
> diff --git a/bfd/libbfd.h b/bfd/libbfd.h
> index ebd4f24149b..53604a094f6 100644
> --- a/bfd/libbfd.h
> +++ b/bfd/libbfd.h
> @@ -1272,6 +1272,15 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
>    "BFD_RELOC_MIPS_26_PCREL_S2",
>    "BFD_RELOC_MIPS_18_PCREL_S3",
>    "BFD_RELOC_MIPS_19_PCREL_S2",
> +  "BFD_RELOC_MIPS_LO16_GOTOFF_CALL",
> +  "BFD_RELOC_MIPS_HI16_GOTOFF_CALL",
> +  "BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL",
> +  "BFD_RELOC_MIPS_ALO16_GOTOFF",
> +  "BFD_RELOC_MIPS_AHI16_GOTOFF",
> +  "BFD_RELOC_MIPS_AHI16_S_GOTOFF",
> +  "BFD_RELOC_MIPS_ALO16_GOTOFF_CALL",
> +  "BFD_RELOC_MIPS_AHI16_GOTOFF_CALL",
> +  "BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL",
>    "BFD_RELOC_MICROMIPS_GPREL16",
>    "BFD_RELOC_MICROMIPS_HI16",
>    "BFD_RELOC_MICROMIPS_HI16_S",
> diff --git a/bfd/reloc.c b/bfd/reloc.c
> index e74cbd75e96..85e4081ccd6 100644
> --- a/bfd/reloc.c
> +++ b/bfd/reloc.c
> @@ -2040,6 +2040,24 @@ ENUMX
>    BFD_RELOC_MIPS_18_PCREL_S3
>  ENUMX
>    BFD_RELOC_MIPS_19_PCREL_S2
> +ENUMX
> +  BFD_RELOC_LO16_GOTOFF_CALL
> +ENUMX
> +  BFD_RELOC_HI16_GOTOFF_CALL
> +ENUMX
> +  BFD_RELOC_HI16_S_GOTOFF_CALL
> +ENUMX
> +  BFD_RELOC_ALO16_GOTOFF
> +ENUMX
> +  BFD_RELOC_AHI16_GOTOFF
> +ENUMX
> +  BFD_RELOC_AHI16_S_GOTOFF
> +ENUMX
> +  BFD_RELOC_ALO16_GOTOFF_CALL
> +ENUMX
> +  BFD_RELOC_AHI16_GOTOFF_CALL
> +ENUMX
> +  BFD_RELOC_AHI16_S_GOTOFF_CALL
>  ENUMDOC
>    MIPS PC-relative relocations.
>
> diff --git a/elfcpp/mips.h b/elfcpp/mips.h
> index e8a8e2458e9..33adb67107b 100644
> --- a/elfcpp/mips.h
> +++ b/elfcpp/mips.h
> @@ -104,6 +104,14 @@ enum
>    R_MIPS_PC19_S2 = 63,
>    R_MIPS_PCHI16 = 64,
>    R_MIPS_PCLO16 = 65,
> +  R_MIPS_GOTPC_HI16 = 66,
> +  R_MIPS_GOTPC_LO16 = 67,
> +  R_MIPS_GOTPC_CALL_HI16 = 68,
> +  R_MIPS_GOTPC_CALL_LO16 = 69,
> +  R_MIPS_GOTPC_HI16 = 70,
> +  R_MIPS_GOTPC_LO16 = 71,
> +  R_MIPS_GOTPC_CALL_HI16 = 72,
> +  R_MIPS_GOTPC_CALL_LO16 = 73,
>    // These relocs are used for the mips16.
>    R_MIPS16_26 = 100,
>    R_MIPS16_GPREL = 101,
> diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
> index 43c12de2c8a..1ec2feac072 100644
> --- a/gas/config/tc-mips.c
> +++ b/gas/config/tc-mips.c
> @@ -4372,6 +4372,14 @@ limited_pcrel_reloc_p (bfd_reloc_code_real_type reloc)
>      case BFD_RELOC_32_PCREL:
>      case BFD_RELOC_HI16_S_PCREL:
>      case BFD_RELOC_LO16_PCREL:
> +    case BFD_RELOC_HI16_S_GOTOFF:
> +    case BFD_RELOC_LO16_GOTOFF:
> +    case BFD_RELOC_MIPS_LO16_GOTOFF_CALL:
> +    case BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL:
> +    case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
> +    case BFD_RELOC_MIPS_ALO16_GOTOFF:
> +    case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
> +    case BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL:
>        return HAVE_64BIT_ADDRESSES;
>
>      default:
> @@ -7432,6 +7440,8 @@ calculate_reloc (bfd_reloc_code_real_type reloc, offsetT operand,
>
>      case BFD_RELOC_HI16_S:
>      case BFD_RELOC_HI16_S_PCREL:
> +    case BFD_RELOC_HI16_S_GOTOFF:
> +    case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
>      case BFD_RELOC_MICROMIPS_HI16_S:
>      case BFD_RELOC_MIPS16_HI16_S:
>        *result = ((operand + 0x8000) >> 16) & 0xffff;
> @@ -7445,6 +7455,10 @@ calculate_reloc (bfd_reloc_code_real_type reloc, offsetT operand,
>
>      case BFD_RELOC_LO16:
>      case BFD_RELOC_LO16_PCREL:
> +    case BFD_RELOC_LO16_GOTOFF:
> +    case BFD_RELOC_MIPS_LO16_GOTOFF_CALL:
> +    case BFD_RELOC_MIPS_ALO16_GOTOFF:
> +    case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
>      case BFD_RELOC_MICROMIPS_LO16:
>      case BFD_RELOC_MIPS16_LO16:
>        *result = operand & 0xffff;
> @@ -7507,6 +7521,22 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
>      as_warn (_("wrong size instruction in a %u-bit branch delay slot"),
>              (prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0 ? 16 : 32);
>
> +  if (!ISA_IS_R6 (mips_opts.isa))
> +    switch (*reloc_type)
> +      {
> +       default:
> +         break;
> +
> +       case BFD_RELOC_MIPS_ALO16_GOTOFF:
> +       case BFD_RELOC_MIPS_AHI16_GOTOFF:
> +       case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
> +       case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
> +       case BFD_RELOC_MIPS_AHI16_GOTOFF_CALL:
> +       case BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL:
> +         as_fatal (_("ALUIPC style GOTPC cannot work with pre-R6."));
> +         break;
> +      }
> +
>    if (address_expr == NULL)
>      ip->complete_p = 1;
>    else if (reloc_type[0] <= BFD_RELOC_UNUSED
> @@ -14583,7 +14613,15 @@ static const struct percent_op_match mips_percent_op[] =
>    {"%gottprel", BFD_RELOC_MIPS_TLS_GOTTPREL},
>    {"%hi", BFD_RELOC_HI16_S},
>    {"%pcrel_hi", BFD_RELOC_HI16_S_PCREL},
> -  {"%pcrel_lo", BFD_RELOC_LO16_PCREL}
> +  {"%pcrel_lo", BFD_RELOC_LO16_PCREL},
> +  {"%gotpc_hi", BFD_RELOC_HI16_S_GOTOFF},
> +  {"%gotpc_lo", BFD_RELOC_LO16_GOTOFF},
> +  {"%gotpc_call_hi", BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL},
> +  {"%gotpc_call_lo", BFD_RELOC_MIPS_LO16_GOTOFF_CALL},
> +  {"%gotpc_ahi", BFD_RELOC_MIPS_AHI16_S_GOTOFF},
> +  {"%gotpc_alo", BFD_RELOC_MIPS_ALO16_GOTOFF},
> +  {"%gotpc_call_ahi", BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL},
> +  {"%gotpc_call_alo", BFD_RELOC_MIPS_ALO16_GOTOFF_CALL}
>  };
>
>  static const struct percent_op_match mips16_percent_op[] =
> @@ -15541,6 +15579,14 @@ mips_force_relocation (fixS *fixp)
>           || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
>           || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
>           || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
> +         || fixp->fx_r_type == BFD_RELOC_HI16_S_GOTOFF
> +         || fixp->fx_r_type == BFD_RELOC_LO16_GOTOFF
> +         || fixp->fx_r_type == BFD_RELOC_MIPS_LO16_GOTOFF_CALL
> +         || fixp->fx_r_type == BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL
> +         || fixp->fx_r_type == BFD_RELOC_MIPS_AHI16_S_GOTOFF
> +         || fixp->fx_r_type == BFD_RELOC_MIPS_ALO16_GOTOFF
> +         || fixp->fx_r_type == BFD_RELOC_MIPS_ALO16_GOTOFF_CALL
> +         || fixp->fx_r_type == BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL
>           || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
>           || fixp->fx_r_type == BFD_RELOC_LO16_PCREL))
>      return 1;
> @@ -15822,6 +15868,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
>        case BFD_RELOC_MIPS_19_PCREL_S2:
>        case BFD_RELOC_HI16_S_PCREL:
>        case BFD_RELOC_LO16_PCREL:
> +      case BFD_RELOC_HI16_S_GOTOFF:
> +      case BFD_RELOC_LO16_GOTOFF:
> +      case BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL:
> +      case BFD_RELOC_MIPS_LO16_GOTOFF_CALL:
> +      case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
> +      case BFD_RELOC_MIPS_ALO16_GOTOFF:
> +      case BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL:
> +      case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
>         break;
>
>        case BFD_RELOC_32:
> @@ -15965,6 +16019,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
>      case BFD_RELOC_MIPS_GOT_LO16:
>      case BFD_RELOC_MIPS_CALL_HI16:
>      case BFD_RELOC_MIPS_CALL_LO16:
> +    case BFD_RELOC_HI16_S_GOTOFF:
> +    case BFD_RELOC_LO16_GOTOFF:
> +    case BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL:
> +    case BFD_RELOC_MIPS_LO16_GOTOFF_CALL:
> +    case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
> +    case BFD_RELOC_MIPS_ALO16_GOTOFF:
> +    case BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL:
> +    case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
>      case BFD_RELOC_HI16_S_PCREL:
>      case BFD_RELOC_LO16_PCREL:
>      case BFD_RELOC_MIPS16_GPREL:
> @@ -18386,6 +18448,14 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
>                   || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
>                   || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
>                   || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
> +                 || fixp->fx_r_type == BFD_RELOC_HI16_S_GOTOFF
> +                 || fixp->fx_r_type == BFD_RELOC_LO16_GOTOFF
> +                 || fixp->fx_r_type == BFD_RELOC_MIPS_LO16_GOTOFF_CALL
> +                 || fixp->fx_r_type == BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL
> +                 || fixp->fx_r_type == BFD_RELOC_MIPS_AHI16_S_GOTOFF
> +                 || fixp->fx_r_type == BFD_RELOC_MIPS_ALO16_GOTOFF
> +                 || fixp->fx_r_type == BFD_RELOC_MIPS_ALO16_GOTOFF_CALL
> +                 || fixp->fx_r_type == BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL
>                   || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
>                   || fixp->fx_r_type == BFD_RELOC_LO16_PCREL);
>
> diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-32.s b/gas/testsuite/gas/mips/gotpc-aluipc-32.s
> new file mode 100644
> index 00000000000..877193313a1
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-aluipc-32.s
> @@ -0,0 +1,51 @@
> +       .file   1 "nn.c"
> +       .section .mdebug.abi32
> +       .previous
> +       .nan    2008
> +       .module fp=xx
> +       .module nooddspreg
> +       .module arch=mips32r6
> +       .abicalls
> +       .text
> +       .section        .rodata.str1.4,"aMS",@progbits,1
> +       .align  2
> +$LC0:
> +       .ascii  "XXXX\000"
> +       .section        .text.startup,"ax",@progbits
> +       .align  2
> +       .globl  main
> +       .set    nomips16
> +       .ent    main
> +       .type   main, @function
> +main:
> +       .frame  $sp,32,$31              # vars= 0, regs= 1/0, args= 16, gp= 8
> +       .mask   0x80000000,-4
> +       .fmask  0x00000000,0
> +       .set    noreorder
> +       .cpload $25
> +       .set    nomacro
> +       addiu   $sp,$sp,-32
> +       sw      $31,28($sp)
> +
> +       aluipc  $4,%gotpc_ahi($LC0)
> +       lw      $4,%gotpc_alo($LC0)($4)
> +
> +       aluipc  $25,%gotpc_call_ahi(puts)
> +       lw      $25,%gotpc_call_alo(puts)($25)
> +
> +       .cprestore      16
> +       .reloc  1f,R_MIPS_JALR,puts
> +1:     jalr    $25
> +       nop
> +
> +       lw      $31,28($sp)
> +       move    $2,$0
> +       jr      $31
> +       addiu   $sp,$sp,32
> +
> +       .set    macro
> +       .set    reorder
> +       .end    main
> +       .size   main, .-main
> +       .ident  "GCC: (Debian 12.2.0-14) 12.2.0"
> +       .section        .note.GNU-stack,"",@progbits
> diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-64.s b/gas/testsuite/gas/mips/gotpc-aluipc-64.s
> new file mode 100644
> index 00000000000..234be37b6fe
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-aluipc-64.s
> @@ -0,0 +1,50 @@
> +       .file   1 "nn.c"
> +       .section .mdebug.abi64
> +       .previous
> +       .abicalls
> +       .text
> +       .section        .rodata.str1.8,"aMS",@progbits,1
> +       .align  3
> +.LC0:
> +       .ascii  "XXXX\000"
> +       .section        .text.startup,"ax",@progbits
> +       .align  2
> +       .align  3
> +       .globl  main
> +       .set    nomips16
> +       .ent    main
> +       .type   main, @function
> +main:
> +       .frame  $sp,16,$31              # vars= 0, regs= 2/0, args= 0, gp= 0
> +       .mask   0x90000000,-8
> +       .fmask  0x00000000,0
> +       .set    noreorder
> +       .set    nomacro
> +       daddiu  $sp,$sp,-16
> +       sd      $28,0($sp)
> +       lui     $28,%hi(%neg(%gp_rel(main)))
> +       daddu   $28,$28,$25
> +       sd      $31,8($sp)
> +       daddiu  $28,$28,%lo(%neg(%gp_rel(main)))
> +
> +       aluipc  $4,%gotpc_ahi(.LC0)
> +       ld      $4,%gotpc_alo(.LC0)($4)
> +
> +       aluipc  $25,%gotpc_call_ahi(puts)
> +       ld      $25,%gotpc_call_alo(puts)($25)
> +
> +       .reloc  1f,R_MIPS_JALR,puts
> +1:     jalr    $25
> +       nop
> +
> +       ld      $31,8($sp)
> +       ld      $28,0($sp)
> +       move    $2,$0
> +       jr      $31
> +       daddiu  $sp,$sp,16
> +
> +       .set    macro
> +       .set    reorder
> +       .end    main
> +       .size   main, .-main
> +       .section        .note.GNU-stack,"",@progbits
> diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-n32.d b/gas/testsuite/gas/mips/gotpc-aluipc-n32.d
> new file mode 100644
> index 00000000000..41bc6d474d7
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-aluipc-n32.d
> @@ -0,0 +1,17 @@
> +#objdump: -dr --prefix-addresses --show-raw-insn
> +#name: R_MIPS_GOTPC support (NewABI, ALUIPC, N32)
> +#source: gotpc-aluipc-64.s
> +#as: -n32 -mips64r6
> +
> +.*: +file format .*mips.*
> +
> +Disassembly of section \.text\.startup:
> +#...
> +.*R_MIPS_GOTPC_AHI16   \.rodata\.str1\.8
> +#...
> +.*R_MIPS_GOTPC_ALO16   \.rodata\.str1\.8
> +#...
> +.*R_MIPS_GOTPC_CALL_AHI16      puts
> +#...
> +.*R_MIPS_GOTPC_CALL_ALO16      puts
> +#pass
> diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-n64.d b/gas/testsuite/gas/mips/gotpc-aluipc-n64.d
> new file mode 100644
> index 00000000000..0561040ef09
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-aluipc-n64.d
> @@ -0,0 +1,25 @@
> +#objdump: -dr --prefix-addresses --show-raw-insn
> +#name: R_MIPS_GOTPC support (NewABI, ALUIPC, N64)
> +#source: gotpc-aluipc-64.s
> +#as: -64 -mips64r6
> +
> +.*: +file format .*mips.*
> +
> +Disassembly of section \.text\.startup:
> +#...
> +.*R_MIPS_GOTPC_AHI16   \.LC0
> +.*R_MIPS_NONE.*
> +.*R_MIPS_NONE.*
> +#...
> +.*R_MIPS_GOTPC_ALO16   \.LC0
> +.*R_MIPS_NONE.*
> +.*R_MIPS_NONE.*
> +#...
> +.*R_MIPS_GOTPC_CALL_AHI16      puts
> +.*R_MIPS_NONE.*
> +.*R_MIPS_NONE.*
> +#...
> +.*R_MIPS_GOTPC_CALL_ALO16      puts
> +.*R_MIPS_NONE.*
> +.*R_MIPS_NONE.*
> +#pass
> diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-o32.d b/gas/testsuite/gas/mips/gotpc-aluipc-o32.d
> new file mode 100644
> index 00000000000..4079c8de661
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-aluipc-o32.d
> @@ -0,0 +1,17 @@
> +#objdump: -dr --prefix-addresses --show-raw-insn
> +#name: R_MIPS_GOTPC support (NewABI, ALUIPC, O32)

Sorry a typo, here. V3 will be sent.

> +#source: gotpc-aluipc-32.s
> +#as: -32 -mips32r6
> +
> +.*: +file format .*mips.*
> +
> +Disassembly of section \.text\.startup:
> +#...
> +.*R_MIPS_GOTPC_AHI16   \.rodata\.str1\.4
> +#...
> +.*R_MIPS_GOTPC_ALO16   \.rodata\.str1\.4
> +#...
> +.*R_MIPS_GOTPC_CALL_AHI16      puts
> +#...
> +.*R_MIPS_GOTPC_CALL_ALO16      puts
> +#pass
> diff --git a/gas/testsuite/gas/mips/gotpc-bal-32.s b/gas/testsuite/gas/mips/gotpc-bal-32.s
> new file mode 100644
> index 00000000000..841a13dbf87
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-bal-32.s
> @@ -0,0 +1,55 @@
> +       .file   1 "nn.c"
> +       .section .mdebug.abi32
> +       .previous
> +       .nan    2008
> +       .module fp=xx
> +       .module nooddspreg
> +       .module arch=mips32r6
> +       .abicalls
> +       .text
> +       .section        .rodata.str1.4,"aMS",@progbits,1
> +       .align  2
> +$LC0:
> +       .ascii  "XXXX\000"
> +       .section        .text.startup,"ax",@progbits
> +       .align  2
> +       .globl  main
> +       .set    nomips16
> +       .ent    main
> +       .type   main, @function
> +main:
> +       .frame  $sp,32,$31              # vars= 0, regs= 1/0, args= 16, gp= 8
> +       .mask   0x80000000,-4
> +       .fmask  0x00000000,0
> +       .set    noreorder
> +       .cpload $25
> +       .set    nomacro
> +       addiu   $sp,$sp,-32
> +       sw      $31,28($sp)
> +
> +       bal     . + 8
> +       lui     $4,%gotpc_hi($LC0)
> +       addu    $4,$4,$31
> +       lw      $4,%gotpc_lo($LC0)($4)
> +
> +       bal     . + 8
> +       lui     $25,%gotpc_call_hi(puts)
> +       addu    $25,$25,$31
> +       lw      $25,%gotpc_call_lo(puts)($25)
> +
> +       .cprestore      16
> +       .reloc  1f,R_MIPS_JALR,puts
> +1:     jalr    $25
> +       nop
> +
> +       lw      $31,28($sp)
> +       move    $2,$0
> +       jr      $31
> +       addiu   $sp,$sp,32
> +
> +       .set    macro
> +       .set    reorder
> +       .end    main
> +       .size   main, .-main
> +       .ident  "GCC: (Debian 12.2.0-14) 12.2.0"
> +       .section        .note.GNU-stack,"",@progbits
> diff --git a/gas/testsuite/gas/mips/gotpc-bal-64.s b/gas/testsuite/gas/mips/gotpc-bal-64.s
> new file mode 100644
> index 00000000000..c97e6b87af9
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-bal-64.s
> @@ -0,0 +1,54 @@
> +       .file   1 "nn.c"
> +       .section .mdebug.abi64
> +       .previous
> +       .abicalls
> +       .text
> +       .section        .rodata.str1.8,"aMS",@progbits,1
> +       .align  3
> +.LC0:
> +       .ascii  "XXXX\000"
> +       .section        .text.startup,"ax",@progbits
> +       .align  2
> +       .align  3
> +       .globl  main
> +       .set    nomips16
> +       .ent    main
> +       .type   main, @function
> +main:
> +       .frame  $sp,16,$31              # vars= 0, regs= 2/0, args= 0, gp= 0
> +       .mask   0x90000000,-8
> +       .fmask  0x00000000,0
> +       .set    noreorder
> +       .set    nomacro
> +       daddiu  $sp,$sp,-16
> +       sd      $28,0($sp)
> +       lui     $28,%hi(%neg(%gp_rel(main)))
> +       daddu   $28,$28,$25
> +       sd      $31,8($sp)
> +       daddiu  $28,$28,%lo(%neg(%gp_rel(main)))
> +
> +       bal     . + 8
> +       lui     $4,%gotpc_hi(.LC0)
> +       daddu   $4,$4,$31
> +       ld      $4,%gotpc_lo(.LC0)($4)
> +
> +       bal     . + 8
> +       lui     $25,%gotpc_call_hi(puts)
> +       daddu   $25,$25,$31
> +       ld      $25,%gotpc_call_lo(puts)($25)
> +
> +       .reloc  1f,R_MIPS_JALR,puts
> +1:     jalr    $25
> +       nop
> +
> +       ld      $31,8($sp)
> +       ld      $28,0($sp)
> +       move    $2,$0
> +       jr      $31
> +       daddiu  $sp,$sp,16
> +
> +       .set    macro
> +       .set    reorder
> +       .end    main
> +       .size   main, .-main
> +       .section        .note.GNU-stack,"",@progbits
> diff --git a/gas/testsuite/gas/mips/gotpc-bal-n32.d b/gas/testsuite/gas/mips/gotpc-bal-n32.d
> new file mode 100644
> index 00000000000..ec412020dc7
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-bal-n32.d
> @@ -0,0 +1,17 @@
> +#objdump: -dr --prefix-addresses --show-raw-insn
> +#name: R_MIPS_GOTPC support (NewABI, BAL, N32)
> +#source: gotpc-bal-64.s
> +#as: -n32 -march=from-abi
> +
> +.*: +file format .*mips.*
> +
> +Disassembly of section \.text\.startup:
> +#...
> +.*R_MIPS_GOTPC_HI16    \.rodata\.str1\.8
> +#...
> +.*R_MIPS_GOTPC_LO16    \.rodata\.str1\.8
> +#...
> +.*R_MIPS_GOTPC_CALL_HI16       puts
> +#...
> +.*R_MIPS_GOTPC_CALL_LO16       puts
> +#pass
> diff --git a/gas/testsuite/gas/mips/gotpc-bal-n64.d b/gas/testsuite/gas/mips/gotpc-bal-n64.d
> new file mode 100644
> index 00000000000..60b9f020f50
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-bal-n64.d
> @@ -0,0 +1,25 @@
> +#objdump: -dr --prefix-addresses --show-raw-insn
> +#name: R_MIPS_GOTPC support (NewABI, BAL, N64)
> +#source: gotpc-bal-64.s
> +#as: -64 -march=from-abi
> +
> +.*: +file format .*mips.*
> +
> +Disassembly of section \.text\.startup:
> +#...
> +.*R_MIPS_GOTPC_HI16    \.rodata\.str1\.8
> +.*R_MIPS_NONE.*
> +.*R_MIPS_NONE.*
> +#...
> +.*R_MIPS_GOTPC_LO16    \.rodata\.str1\.8
> +.*R_MIPS_NONE.*
> +.*R_MIPS_NONE.*
> +#...
> +.*R_MIPS_GOTPC_CALL_HI16       puts
> +.*R_MIPS_NONE.*
> +.*R_MIPS_NONE.*
> +#...
> +.*R_MIPS_GOTPC_CALL_LO16       puts
> +.*R_MIPS_NONE.*
> +.*R_MIPS_NONE.*
> +#pass
> diff --git a/gas/testsuite/gas/mips/gotpc-bal-o32.d b/gas/testsuite/gas/mips/gotpc-bal-o32.d
> new file mode 100644
> index 00000000000..b4caff9bbe9
> --- /dev/null
> +++ b/gas/testsuite/gas/mips/gotpc-bal-o32.d
> @@ -0,0 +1,17 @@
> +#objdump: -dr --prefix-addresses --show-raw-insn
> +#name: R_MIPS_GOTPC support (BAL, O32)
> +#source: gotpc-bal-32.s
> +#as: -32 -march=from-abi
> +
> +.*: +file format .*mips.*
> +
> +Disassembly of section \.text\.startup:
> +#...
> +.*R_MIPS_GOTPC_HI16    \.rodata\.str1\.4
> +#...
> +.*R_MIPS_GOTPC_LO16    \.rodata\.str1\.4
> +#...
> +.*R_MIPS_GOTPC_CALL_HI16       puts
> +#...
> +.*R_MIPS_GOTPC_CALL_LO16       puts
> +#pass
> diff --git a/gas/testsuite/gas/mips/mips.exp b/gas/testsuite/gas/mips/mips.exp
> index 2ddbf0c768d..619d04b3bd5 100644
> --- a/gas/testsuite/gas/mips/mips.exp
> +++ b/gas/testsuite/gas/mips/mips.exp
> @@ -1210,7 +1210,15 @@ if { [istarget mips*-*-vxworks*] } {
>         run_dump_test "elf-rel-xgot-n32"
>         run_dump_test "elf-rel-got-n64"
>         run_dump_test "elf-rel-xgot-n64"
> +
> +       run_dump_test "gotpc-bal-n64"
> +       run_dump_test "gotpc-bal-n32"
> +       run_dump_test "gotpc-aluipc-n64"
> +       run_dump_test "gotpc-aluipc-n32"
>      }
> +    run_dump_test "gotpc-bal-o32"
> +    run_dump_test "gotpc-aluipc-o32"
> +
>      run_dump_test "elf-rel17"
>      if $has_newabi {
>         run_dump_test "elf-rel18"
> diff --git a/include/elf/mips.h b/include/elf/mips.h
> index 686d5500e02..23e95fe0c45 100644
> --- a/include/elf/mips.h
> +++ b/include/elf/mips.h
> @@ -98,7 +98,15 @@ START_RELOC_NUMBERS (elf_mips_reloc_type)
>    RELOC_NUMBER (R_MIPS_PC19_S2, 63)
>    RELOC_NUMBER (R_MIPS_PCHI16, 64)
>    RELOC_NUMBER (R_MIPS_PCLO16, 65)
> -  FAKE_RELOC (R_MIPS_max, 66)
> +  RELOC_NUMBER (R_MIPS_GOTPC_HI16, 66)
> +  RELOC_NUMBER (R_MIPS_GOTPC_LO16, 67)
> +  RELOC_NUMBER (R_MIPS_GOTPC_CALL_HI16, 68)
> +  RELOC_NUMBER (R_MIPS_GOTPC_CALL_LO16, 69)
> +  RELOC_NUMBER (R_MIPS_GOTPC_AHI16, 70)
> +  RELOC_NUMBER (R_MIPS_GOTPC_ALO16, 71)
> +  RELOC_NUMBER (R_MIPS_GOTPC_CALL_AHI16, 72)
> +  RELOC_NUMBER (R_MIPS_GOTPC_CALL_ALO16, 73)
> +  FAKE_RELOC (R_MIPS_max, 74)
>    /* These relocs are used for the mips16.  */
>    FAKE_RELOC (R_MIPS16_min, 100)
>    RELOC_NUMBER (R_MIPS16_26, 100)
> --
> 2.39.2
>

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

* [PATCH] MIPS: Support PCREL GOT access
@ 2024-02-02  6:39 YunQiang Su
  2024-02-02  6:42 ` YunQiang Su
  0 siblings, 1 reply; 12+ messages in thread
From: YunQiang Su @ 2024-02-02  6:39 UTC (permalink / raw)
  To: nickc; +Cc: binutils, macro, xry111

Current if we need to access a GOT entry, we use the
got_base + offset. Thus we have GOT and XGOT.
From MIPSr6, we have PCREL instructions like ALUIPC,
so we have no need to use got_base now.
For pre-R6, we can use BAL to get the the value of PC.

In this patch, we add 8 new relocs:
	R_MIPS_GOTPC_HI16, R_MIPS_GOTPC_LO16,
	R_MIPS_GOTPC_CALL_HI16, R_MIPS_GOTPC_CALL_LO16,
	R_MIPS_GOTPC_AHI16, R_MIPS_GOTPC_ALO16,
	R_MIPS_GOTPC_CALL_AHI16, R_MIPS_GOTPC_CALL_ALO16.
These asm notes can be used for them:
	%gotpc_hi(sym), %gotpc_lo(sym),
	%gotpc_call_hi(sym), %gotpc_call_lo(sym),
	%gotpc_ahi(sym), %gotpc_alo(sym),
	%gotpc_call_ahi(sym), %gotpc_call_alo(sym).

3 new BFD_RELOCS are added for ALUIPC style relocs:
	BFD_RELOC_MIPS_ALO16_GOTOFF,
	BFD_RELOC_MIPS_AHI16_GOTOFF,
	BFD_RELOC_MIPS_AHI16_S_GOTOFF.

6 new BFD_RELOCS are added for function calling:
	BFD_RELOC_MIPS_LO16_GOTOFF_CALL,
	BFD_RELOC_MIPS_HI16_GOTOFF_CALL,
	BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL,
	BFD_RELOC_MIPS_ALO16_GOTOFF_CALL,
	BFD_RELOC_MIPS_AHI16_GOTOFF_CALL,
	BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL,

The mapping between BFD_RELOC_ and R_MIPS_GOTPC are:
	BFD_RELOC_HI16_S_GOTOFF -> R_MIPS_GOTPC_HI16
	BFD_RELOC_LO16_GOTOFF -> R_MIPS_GOTPC_LO16
	BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_HI16
	BFD_RELOC_MIPS_LO16_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_LO16.
	BFD_RELOC_MIPS_AHI16_S_GOTOFF -> R_MIPS_GOTPC_AHI16
	BFD_RELOC_MIPS_ALO16_GOTOFF -> R_MIPS_GOTPC_ALO16
	BFD_RELOC_MIPS_MIPS_AHI16_S_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_AHI16
	BFD_RELOC_MIPS_MIPS_ALO16_GOTOFF_CALL -> R_MIPS_GOTPC_CALL_ALO16.

The difference of BAL and ALUIPC is that ALUIPC will unset the lower 16
bits of result.

For r6, both styles are supported, and of course ALUIPC style is
recommended. For pre-R6, only BAL style is supported.

Here are the ASM examples:
ALUIPC:
	aluipc	$2,%gotpc_ahi(sym)
	lw	$2,%gotpc_alo(sym)($2)

BAL:
	bal	. + 8 # Note: $31 is clobbered here.
	lui	$2,%gotpc_hi(sym)
	addiu	$2,$2,$31
	lw	$2,%gotpc_lo(sym)($2)

gas/ChangeLog:
	* config/tc-mips.c: Add GOTPC relocs support.
	* testsuite/gas/mips/mips.exp: Add GOTPC testcases.
	* testsuite/gas/mips/gotpc-aluipc-32.s: Ditto.
	* testsuite/gas/mips/gotpc-aluipc-64.s: Ditto.
	* testsuite/gas/mips/gotpc-aluipc-n64.d: Ditto.
	* testsuite/gas/mips/gotpc-aluipc-n32.d: Ditto.
	* testsuite/gas/mips/gotpc-aluipc-o32.d: Ditto.
	* testsuite/gas/mips/gotpc-bal-32.s: Ditto.
	* testsuite/gas/mips/gotpc-bal-64.s: Ditto.
	* testsuite/gas/mips/gotpc-bal-n64.d: Ditto.
	* testsuite/gas/mips/gotpc-bal-n32.d: Ditto.
	* testsuite/gas/mips/gotpc-bal-o32.d: Ditto.

bfd/ChangeLog:
	* elfxx-mips.c: Add GOTPC relocs support.
	* elf32-mips.c: Ditto.
	* elf64-mips.c: Ditto.
	* elfn32-mips.c: Ditto.
	* bfd-in2.h: Add new MIPS GOTPC BFD_RELOC defination.
	* reclos.c: Ditto.
	* libbfd.h: Ditto.

elfcpp/ChangeLog:
	* mips.h: Add new MIPS GOTPC relocs.

include/ChangeLog:
	* elf/mips.h (elf_mips_reloc_type): Add new MIPS GOTPC relocs.
---
 bfd/bfd-in2.h                             |  12 ++
 bfd/elf32-mips.c                          | 123 +++++++++++-
 bfd/elf64-mips.c                          | 234 +++++++++++++++++++++-
 bfd/elfn32-mips.c                         | 234 +++++++++++++++++++++-
 bfd/elfxx-mips.c                          | 107 +++++++++-
 bfd/libbfd.h                              |   9 +
 bfd/reloc.c                               |  18 ++
 elfcpp/mips.h                             |   8 +
 gas/config/tc-mips.c                      |  72 ++++++-
 gas/testsuite/gas/mips/gotpc-aluipc-32.s  |  51 +++++
 gas/testsuite/gas/mips/gotpc-aluipc-64.s  |  50 +++++
 gas/testsuite/gas/mips/gotpc-aluipc-n32.d |  17 ++
 gas/testsuite/gas/mips/gotpc-aluipc-n64.d |  25 +++
 gas/testsuite/gas/mips/gotpc-aluipc-o32.d |  17 ++
 gas/testsuite/gas/mips/gotpc-bal-32.s     |  55 +++++
 gas/testsuite/gas/mips/gotpc-bal-64.s     |  54 +++++
 gas/testsuite/gas/mips/gotpc-bal-n32.d    |  17 ++
 gas/testsuite/gas/mips/gotpc-bal-n64.d    |  25 +++
 gas/testsuite/gas/mips/gotpc-bal-o32.d    |  17 ++
 gas/testsuite/gas/mips/mips.exp           |   8 +
 include/elf/mips.h                        |  10 +-
 21 files changed, 1155 insertions(+), 8 deletions(-)
 create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-32.s
 create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-64.s
 create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-n32.d
 create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-n64.d
 create mode 100644 gas/testsuite/gas/mips/gotpc-aluipc-o32.d
 create mode 100644 gas/testsuite/gas/mips/gotpc-bal-32.s
 create mode 100644 gas/testsuite/gas/mips/gotpc-bal-64.s
 create mode 100644 gas/testsuite/gas/mips/gotpc-bal-n32.d
 create mode 100644 gas/testsuite/gas/mips/gotpc-bal-n64.d
 create mode 100644 gas/testsuite/gas/mips/gotpc-bal-o32.d

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 581d8fe0b3e..bce2030f9c5 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3654,6 +3654,18 @@ enum bfd_reloc_code_real
   BFD_RELOC_MIPS_18_PCREL_S3,
   BFD_RELOC_MIPS_19_PCREL_S2,
 
+  BFD_RELOC_MIPS_LO16_GOTOFF_CALL,
+  BFD_RELOC_MIPS_HI16_GOTOFF_CALL,
+  BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL,
+
+  BFD_RELOC_MIPS_ALO16_GOTOFF,
+  BFD_RELOC_MIPS_AHI16_GOTOFF,
+  BFD_RELOC_MIPS_AHI16_S_GOTOFF,
+
+  BFD_RELOC_MIPS_ALO16_GOTOFF_CALL,
+  BFD_RELOC_MIPS_AHI16_GOTOFF_CALL,
+  BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL,
+
   /* microMIPS versions of generic BFD relocs.  */
   BFD_RELOC_MICROMIPS_GPREL16,
   BFD_RELOC_MICROMIPS_HI16,
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index 63d7334dd52..7edcc30d331 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -809,6 +809,119 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
 	 0x0000ffff,		/* src_mask */
 	 0x0000ffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
 };
 
 /* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link.  This
@@ -2030,7 +2143,15 @@ static const struct elf_reloc_map mips_reloc_map[] =
   { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
   { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
   { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
-  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
+  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
+  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
+  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
+  { BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
+  { BFD_RELOC_MIPS_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 },
+  { BFD_RELOC_MIPS_AHI16_S_GOTOFF, R_MIPS_GOTPC_AHI16 },
+  { BFD_RELOC_MIPS_ALO16_GOTOFF, R_MIPS_GOTPC_ALO16 },
+  { BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_AHI16 },
+  { BFD_RELOC_MIPS_ALO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_ALO16 }
 };
 
 static const struct elf_reloc_map mips16_reloc_map[] =
diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
index 489a461bb0b..dc4e56d1f55 100644
--- a/bfd/elf64-mips.c
+++ b/bfd/elf64-mips.c
@@ -889,6 +889,118 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
 	 0x0000ffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
 
+  HOWTO (R_MIPS_GOTPC_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
 };
 
 /* The relocation table used for SHT_RELA sections.  */
@@ -1670,6 +1782,118 @@ static reloc_howto_type mips_elf64_howto_table_rela[] =
 	 0x0000ffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
 
+  HOWTO (R_MIPS_GOTPC_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
 };
 
 static reloc_howto_type mips16_elf64_howto_table_rel[] =
@@ -3743,7 +3967,15 @@ static const struct elf_reloc_map mips_reloc_map[] =
   { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
   { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
   { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
-  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
+  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
+  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
+  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
+  { BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
+  { BFD_RELOC_MIPS_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 },
+  { BFD_RELOC_MIPS_AHI16_S_GOTOFF, R_MIPS_GOTPC_AHI16 },
+  { BFD_RELOC_MIPS_ALO16_GOTOFF, R_MIPS_GOTPC_ALO16 },
+  { BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_AHI16 },
+  { BFD_RELOC_MIPS_ALO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_ALO16 }
 };
 
 static const struct elf_reloc_map mips16_reloc_map[] =
diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c
index 7e672200006..03e17dfda64 100644
--- a/bfd/elfn32-mips.c
+++ b/bfd/elfn32-mips.c
@@ -868,6 +868,118 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
 	 0x0000ffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
 
+  HOWTO (R_MIPS_GOTPC_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
 };
 
 /* The relocation table used for SHT_RELA sections.  */
@@ -1650,6 +1762,118 @@ static reloc_howto_type elf_mips_howto_table_rela[] =
 	 0x0000ffff,		/* dst_mask */
 	 true),			/* pcrel_offset */
 
+  HOWTO (R_MIPS_GOTPC_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_HI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_HI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_LO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_LO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_AHI16,	/* type */
+	 16,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_AHI16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
+  HOWTO (R_MIPS_GOTPC_CALL_ALO16,	/* type */
+	 0,			/* rightshift */
+	 4,			/* size */
+	 16,			/* bitsize */
+	 true,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 "R_MIPS_GOTPC_CALL_ALO16",	/* name */
+	 true,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 true),			/* pcrel_offset */
+
 };
 
 static reloc_howto_type elf_mips16_howto_table_rel[] =
@@ -3577,7 +3801,15 @@ static const struct elf_reloc_map mips_reloc_map[] =
   { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 },
   { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 },
   { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 },
-  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 }
+  { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 },
+  { BFD_RELOC_HI16_S_GOTOFF, R_MIPS_GOTPC_HI16 },
+  { BFD_RELOC_LO16_GOTOFF, R_MIPS_GOTPC_LO16 },
+  { BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_HI16 },
+  { BFD_RELOC_MIPS_LO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_LO16 },
+  { BFD_RELOC_MIPS_AHI16_S_GOTOFF, R_MIPS_GOTPC_AHI16 },
+  { BFD_RELOC_MIPS_ALO16_GOTOFF, R_MIPS_GOTPC_ALO16 },
+  { BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL, R_MIPS_GOTPC_CALL_AHI16 },
+  { BFD_RELOC_MIPS_ALO16_GOTOFF_CALL, R_MIPS_GOTPC_CALL_ALO16 }
 };
 
 static const struct elf_reloc_map mips16_reloc_map[] =
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 69dd71419ff..c8a9ceb7524 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -2267,19 +2267,28 @@ got_page_reloc_p (unsigned int r_type)
 static inline bool
 got_lo16_reloc_p (unsigned int r_type)
 {
-  return r_type == R_MIPS_GOT_LO16 || r_type == R_MICROMIPS_GOT_LO16;
+  return r_type == R_MIPS_GOT_LO16
+	 || r_type == R_MIPS_GOTPC_LO16
+	 || r_type == R_MIPS_GOTPC_ALO16
+	 || r_type == R_MICROMIPS_GOT_LO16;
 }
 
 static inline bool
 call_hi16_reloc_p (unsigned int r_type)
 {
-  return r_type == R_MIPS_CALL_HI16 || r_type == R_MICROMIPS_CALL_HI16;
+  return r_type == R_MIPS_CALL_HI16
+	 || r_type == R_MIPS_GOTPC_CALL_HI16
+	 || r_type == R_MIPS_GOTPC_CALL_AHI16
+	 || r_type == R_MICROMIPS_CALL_HI16;
 }
 
 static inline bool
 call_lo16_reloc_p (unsigned int r_type)
 {
-  return r_type == R_MIPS_CALL_LO16 || r_type == R_MICROMIPS_CALL_LO16;
+  return r_type == R_MIPS_CALL_LO16
+	 || r_type == R_MIPS_GOTPC_CALL_LO16
+	 || r_type == R_MIPS_GOTPC_CALL_ALO16
+	 || r_type == R_MICROMIPS_CALL_LO16;
 }
 
 static inline bool
@@ -5241,6 +5250,21 @@ mips_elf_highest (bfd_vma value ATTRIBUTE_UNUSED)
   return MINUS_ONE;
 #endif
 }
+
+/**/
+static bfd_vma
+mips_elf_16bit_align (bfd_vma value, bfd_vma p, bool hi)
+{
+  bfd_vma value_lo = (value & 0xffff) + (p & 0xffff);
+  bfd_vma value_hi = (value >> 16) & 0xffff;
+  value_hi += mips_elf_high (value_lo);
+  value_lo &= 0xffff;
+  if (hi)
+    return value_hi;
+  else
+    return value_lo;
+}
+
 \f
 /* Create the .compact_rel section.  */
 
@@ -5888,6 +5912,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MIPS_GOT_DISP:
     case R_MIPS_GOT_LO16:
     case R_MIPS_CALL_LO16:
+    case R_MIPS_GOTPC_LO16:
+    case R_MIPS_GOTPC_CALL_LO16:
+    case R_MIPS_GOTPC_ALO16:
+    case R_MIPS_GOTPC_CALL_ALO16:
     case R_MICROMIPS_CALL16:
     case R_MICROMIPS_GOT16:
     case R_MICROMIPS_GOT_PAGE:
@@ -5905,6 +5933,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       /* Fall through.  */
     case R_MIPS_GOT_HI16:
     case R_MIPS_CALL_HI16:
+    case R_MIPS_GOTPC_HI16:
+    case R_MIPS_GOTPC_CALL_HI16:
     case R_MICROMIPS_GOT_HI16:
     case R_MICROMIPS_CALL_HI16:
       if (resolved_to_zero
@@ -5952,6 +5982,14 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
     case R_MIPS_CALL_HI16:
     case R_MIPS_GOT_LO16:
     case R_MIPS_CALL_LO16:
+    case R_MIPS_GOTPC_HI16:
+    case R_MIPS_GOTPC_LO16:
+    case R_MIPS_GOTPC_CALL_HI16:
+    case R_MIPS_GOTPC_CALL_LO16:
+    case R_MIPS_GOTPC_AHI16:
+    case R_MIPS_GOTPC_ALO16:
+    case R_MIPS_GOTPC_CALL_AHI16:
+    case R_MIPS_GOTPC_CALL_ALO16:
     case R_MICROMIPS_CALL16:
     case R_MICROMIPS_GOT16:
     case R_MICROMIPS_GOT_DISP:
@@ -6413,6 +6451,45 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
       value &= howto->dst_mask;
       break;
 
+    /* For r6 and pre-r6, we can use:
+	bal	. + 8
+	lui	$2,%gotpc_hi(sym) # or %gotpc_call_hi
+	addu	$2,$2,$ra
+	lw	$2,%gotpc_lo(sym) # or %gotpc_call_lo
+       In this case, the LO should +=4, and HI should -=4.
+
+       For R6+, we can use
+	aluipc	$2,%gotpc_ahi(sym) # or %gotpc_call_ahi
+	lw	$2,%gotpc_alo(sym)($2) or %gotpc_call_alo
+       In this case, the HI is OK, while LO should +4 and add the page_offet */
+    case R_MIPS_GOTPC_HI16:
+    case R_MIPS_GOTPC_CALL_HI16:
+      value = mips_elf_high (addend + gp - p + g - 4);
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_GOTPC_LO16:
+    case R_MIPS_GOTPC_CALL_LO16:
+      if (howto->partial_inplace)
+	addend = _bfd_mips_elf_sign_extend (addend, 16);
+      value = addend + gp - p + g + 4;
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_GOTPC_AHI16:
+    case R_MIPS_GOTPC_CALL_AHI16:
+      value = mips_elf_16bit_align (addend + gp - p + g, p, true);
+      value &= howto->dst_mask;
+      break;
+
+    case R_MIPS_GOTPC_ALO16:
+    case R_MIPS_GOTPC_CALL_ALO16:
+      if (howto->partial_inplace)
+	addend = _bfd_mips_elf_sign_extend (addend, 16);
+      value = mips_elf_16bit_align (addend + gp - p + g, p, false);
+      value &= howto->dst_mask;
+      break;
+
     case R_MIPS_PCHI16:
       value = mips_elf_high (symbol + addend - p);
       value &= howto->dst_mask;
@@ -8282,6 +8359,14 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
     lo16_type = R_MIPS16_LO16;
   else if (micromips_reloc_p (r_type))
     lo16_type = R_MICROMIPS_LO16;
+  else if (r_type == R_MIPS_GOTPC_HI16)
+    lo16_type = R_MIPS_GOTPC_LO16;
+  else if (r_type == R_MIPS_GOTPC_CALL_HI16)
+    lo16_type = R_MIPS_GOTPC_CALL_LO16;
+  else if (r_type == R_MIPS_GOTPC_AHI16)
+    lo16_type = R_MIPS_GOTPC_ALO16;
+  else if (r_type == R_MIPS_GOTPC_CALL_AHI16)
+    lo16_type = R_MIPS_GOTPC_CALL_ALO16;
   else if (r_type == R_MIPS_PCHI16)
     lo16_type = R_MIPS_PCLO16;
   else
@@ -8742,6 +8827,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_MIPS_CALL16:
 	case R_MIPS_CALL_HI16:
 	case R_MIPS_CALL_LO16:
+	case R_MIPS_GOTPC_CALL_HI16:
+	case R_MIPS_GOTPC_CALL_LO16:
+	case R_MIPS_GOTPC_CALL_AHI16:
+	case R_MIPS_GOTPC_CALL_ALO16:
 	case R_MIPS16_CALL16:
 	case R_MICROMIPS_CALL16:
 	case R_MICROMIPS_CALL_HI16:
@@ -8751,6 +8840,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	case R_MIPS_GOT16:
 	case R_MIPS_GOT_LO16:
+	case R_MIPS_GOTPC_LO16:
+	case R_MIPS_GOTPC_ALO16:
 	case R_MIPS_GOT_PAGE:
 	case R_MIPS_GOT_DISP:
 	case R_MIPS16_GOT16:
@@ -8788,6 +8879,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	  /* Fall through.  */
 	case R_MIPS_GOT_HI16:
+	case R_MIPS_GOTPC_HI16:
+	case R_MIPS_GOTPC_AHI16:
 	case R_MIPS_GOT_OFST:
 	case R_MIPS_TLS_GOTTPREL:
 	case R_MIPS_TLS_GD:
@@ -8958,6 +9051,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	case R_MIPS_CALL_HI16:
 	case R_MIPS_CALL_LO16:
+	case R_MIPS_GOTPC_CALL_HI16:
+	case R_MIPS_GOTPC_CALL_LO16:
+	case R_MIPS_GOTPC_CALL_AHI16:
+	case R_MIPS_GOTPC_CALL_ALO16:
 	case R_MICROMIPS_CALL_HI16:
 	case R_MICROMIPS_CALL_LO16:
 	  if (h != NULL)
@@ -8983,6 +9080,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	case R_MIPS_GOT16:
 	case R_MIPS_GOT_HI16:
 	case R_MIPS_GOT_LO16:
+	case R_MIPS_GOTPC_HI16:
+	case R_MIPS_GOTPC_LO16:
+	case R_MIPS_GOTPC_AHI16:
+	case R_MIPS_GOTPC_ALO16:
 	case R_MICROMIPS_GOT16:
 	case R_MICROMIPS_GOT_HI16:
 	case R_MICROMIPS_GOT_LO16:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index ebd4f24149b..53604a094f6 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1272,6 +1272,15 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_MIPS_26_PCREL_S2",
   "BFD_RELOC_MIPS_18_PCREL_S3",
   "BFD_RELOC_MIPS_19_PCREL_S2",
+  "BFD_RELOC_MIPS_LO16_GOTOFF_CALL",
+  "BFD_RELOC_MIPS_HI16_GOTOFF_CALL",
+  "BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL",
+  "BFD_RELOC_MIPS_ALO16_GOTOFF",
+  "BFD_RELOC_MIPS_AHI16_GOTOFF",
+  "BFD_RELOC_MIPS_AHI16_S_GOTOFF",
+  "BFD_RELOC_MIPS_ALO16_GOTOFF_CALL",
+  "BFD_RELOC_MIPS_AHI16_GOTOFF_CALL",
+  "BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL",
   "BFD_RELOC_MICROMIPS_GPREL16",
   "BFD_RELOC_MICROMIPS_HI16",
   "BFD_RELOC_MICROMIPS_HI16_S",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index e74cbd75e96..85e4081ccd6 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2040,6 +2040,24 @@ ENUMX
   BFD_RELOC_MIPS_18_PCREL_S3
 ENUMX
   BFD_RELOC_MIPS_19_PCREL_S2
+ENUMX
+  BFD_RELOC_LO16_GOTOFF_CALL
+ENUMX
+  BFD_RELOC_HI16_GOTOFF_CALL
+ENUMX
+  BFD_RELOC_HI16_S_GOTOFF_CALL
+ENUMX
+  BFD_RELOC_ALO16_GOTOFF
+ENUMX
+  BFD_RELOC_AHI16_GOTOFF
+ENUMX
+  BFD_RELOC_AHI16_S_GOTOFF
+ENUMX
+  BFD_RELOC_ALO16_GOTOFF_CALL
+ENUMX
+  BFD_RELOC_AHI16_GOTOFF_CALL
+ENUMX
+  BFD_RELOC_AHI16_S_GOTOFF_CALL
 ENUMDOC
   MIPS PC-relative relocations.
 
diff --git a/elfcpp/mips.h b/elfcpp/mips.h
index e8a8e2458e9..33adb67107b 100644
--- a/elfcpp/mips.h
+++ b/elfcpp/mips.h
@@ -104,6 +104,14 @@ enum
   R_MIPS_PC19_S2 = 63,
   R_MIPS_PCHI16 = 64,
   R_MIPS_PCLO16 = 65,
+  R_MIPS_GOTPC_HI16 = 66,
+  R_MIPS_GOTPC_LO16 = 67,
+  R_MIPS_GOTPC_CALL_HI16 = 68,
+  R_MIPS_GOTPC_CALL_LO16 = 69,
+  R_MIPS_GOTPC_HI16 = 70,
+  R_MIPS_GOTPC_LO16 = 71,
+  R_MIPS_GOTPC_CALL_HI16 = 72,
+  R_MIPS_GOTPC_CALL_LO16 = 73,
   // These relocs are used for the mips16.
   R_MIPS16_26 = 100,
   R_MIPS16_GPREL = 101,
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 43c12de2c8a..1ec2feac072 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -4372,6 +4372,14 @@ limited_pcrel_reloc_p (bfd_reloc_code_real_type reloc)
     case BFD_RELOC_32_PCREL:
     case BFD_RELOC_HI16_S_PCREL:
     case BFD_RELOC_LO16_PCREL:
+    case BFD_RELOC_HI16_S_GOTOFF:
+    case BFD_RELOC_LO16_GOTOFF:
+    case BFD_RELOC_MIPS_LO16_GOTOFF_CALL:
+    case BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL:
+    case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
+    case BFD_RELOC_MIPS_ALO16_GOTOFF:
+    case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
+    case BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL:
       return HAVE_64BIT_ADDRESSES;
 
     default:
@@ -7432,6 +7440,8 @@ calculate_reloc (bfd_reloc_code_real_type reloc, offsetT operand,
 
     case BFD_RELOC_HI16_S:
     case BFD_RELOC_HI16_S_PCREL:
+    case BFD_RELOC_HI16_S_GOTOFF:
+    case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
     case BFD_RELOC_MICROMIPS_HI16_S:
     case BFD_RELOC_MIPS16_HI16_S:
       *result = ((operand + 0x8000) >> 16) & 0xffff;
@@ -7445,6 +7455,10 @@ calculate_reloc (bfd_reloc_code_real_type reloc, offsetT operand,
 
     case BFD_RELOC_LO16:
     case BFD_RELOC_LO16_PCREL:
+    case BFD_RELOC_LO16_GOTOFF:
+    case BFD_RELOC_MIPS_LO16_GOTOFF_CALL:
+    case BFD_RELOC_MIPS_ALO16_GOTOFF:
+    case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
     case BFD_RELOC_MICROMIPS_LO16:
     case BFD_RELOC_MIPS16_LO16:
       *result = operand & 0xffff;
@@ -7507,6 +7521,22 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
     as_warn (_("wrong size instruction in a %u-bit branch delay slot"),
 	     (prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0 ? 16 : 32);
 
+  if (!ISA_IS_R6 (mips_opts.isa))
+    switch (*reloc_type)
+      {
+	default:
+	  break;
+
+	case BFD_RELOC_MIPS_ALO16_GOTOFF:
+	case BFD_RELOC_MIPS_AHI16_GOTOFF:
+	case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
+	case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
+	case BFD_RELOC_MIPS_AHI16_GOTOFF_CALL:
+	case BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL:
+	  as_fatal (_("ALUIPC style GOTPC cannot work with pre-R6."));
+	  break;
+      }
+
   if (address_expr == NULL)
     ip->complete_p = 1;
   else if (reloc_type[0] <= BFD_RELOC_UNUSED
@@ -14583,7 +14613,15 @@ static const struct percent_op_match mips_percent_op[] =
   {"%gottprel", BFD_RELOC_MIPS_TLS_GOTTPREL},
   {"%hi", BFD_RELOC_HI16_S},
   {"%pcrel_hi", BFD_RELOC_HI16_S_PCREL},
-  {"%pcrel_lo", BFD_RELOC_LO16_PCREL}
+  {"%pcrel_lo", BFD_RELOC_LO16_PCREL},
+  {"%gotpc_hi", BFD_RELOC_HI16_S_GOTOFF},
+  {"%gotpc_lo", BFD_RELOC_LO16_GOTOFF},
+  {"%gotpc_call_hi", BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL},
+  {"%gotpc_call_lo", BFD_RELOC_MIPS_LO16_GOTOFF_CALL},
+  {"%gotpc_ahi", BFD_RELOC_MIPS_AHI16_S_GOTOFF},
+  {"%gotpc_alo", BFD_RELOC_MIPS_ALO16_GOTOFF},
+  {"%gotpc_call_ahi", BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL},
+  {"%gotpc_call_alo", BFD_RELOC_MIPS_ALO16_GOTOFF_CALL}
 };
 
 static const struct percent_op_match mips16_percent_op[] =
@@ -15541,6 +15579,14 @@ mips_force_relocation (fixS *fixp)
 	  || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
 	  || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
 	  || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
+	  || fixp->fx_r_type == BFD_RELOC_HI16_S_GOTOFF
+	  || fixp->fx_r_type == BFD_RELOC_LO16_GOTOFF
+	  || fixp->fx_r_type == BFD_RELOC_MIPS_LO16_GOTOFF_CALL
+	  || fixp->fx_r_type == BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL
+	  || fixp->fx_r_type == BFD_RELOC_MIPS_AHI16_S_GOTOFF
+	  || fixp->fx_r_type == BFD_RELOC_MIPS_ALO16_GOTOFF
+	  || fixp->fx_r_type == BFD_RELOC_MIPS_ALO16_GOTOFF_CALL
+	  || fixp->fx_r_type == BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL
 	  || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
 	  || fixp->fx_r_type == BFD_RELOC_LO16_PCREL))
     return 1;
@@ -15822,6 +15868,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       case BFD_RELOC_MIPS_19_PCREL_S2:
       case BFD_RELOC_HI16_S_PCREL:
       case BFD_RELOC_LO16_PCREL:
+      case BFD_RELOC_HI16_S_GOTOFF:
+      case BFD_RELOC_LO16_GOTOFF:
+      case BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL:
+      case BFD_RELOC_MIPS_LO16_GOTOFF_CALL:
+      case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
+      case BFD_RELOC_MIPS_ALO16_GOTOFF:
+      case BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL:
+      case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
 	break;
 
       case BFD_RELOC_32:
@@ -15965,6 +16019,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_MIPS_GOT_LO16:
     case BFD_RELOC_MIPS_CALL_HI16:
     case BFD_RELOC_MIPS_CALL_LO16:
+    case BFD_RELOC_HI16_S_GOTOFF:
+    case BFD_RELOC_LO16_GOTOFF:
+    case BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL:
+    case BFD_RELOC_MIPS_LO16_GOTOFF_CALL:
+    case BFD_RELOC_MIPS_AHI16_S_GOTOFF:
+    case BFD_RELOC_MIPS_ALO16_GOTOFF:
+    case BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL:
+    case BFD_RELOC_MIPS_ALO16_GOTOFF_CALL:
     case BFD_RELOC_HI16_S_PCREL:
     case BFD_RELOC_LO16_PCREL:
     case BFD_RELOC_MIPS16_GPREL:
@@ -18386,6 +18448,14 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 		  || fixp->fx_r_type == BFD_RELOC_MIPS_26_PCREL_S2
 		  || fixp->fx_r_type == BFD_RELOC_MIPS_18_PCREL_S3
 		  || fixp->fx_r_type == BFD_RELOC_MIPS_19_PCREL_S2
+		  || fixp->fx_r_type == BFD_RELOC_HI16_S_GOTOFF
+		  || fixp->fx_r_type == BFD_RELOC_LO16_GOTOFF
+		  || fixp->fx_r_type == BFD_RELOC_MIPS_LO16_GOTOFF_CALL
+		  || fixp->fx_r_type == BFD_RELOC_MIPS_HI16_S_GOTOFF_CALL
+		  || fixp->fx_r_type == BFD_RELOC_MIPS_AHI16_S_GOTOFF
+		  || fixp->fx_r_type == BFD_RELOC_MIPS_ALO16_GOTOFF
+		  || fixp->fx_r_type == BFD_RELOC_MIPS_ALO16_GOTOFF_CALL
+		  || fixp->fx_r_type == BFD_RELOC_MIPS_AHI16_S_GOTOFF_CALL
 		  || fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
 		  || fixp->fx_r_type == BFD_RELOC_LO16_PCREL);
 
diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-32.s b/gas/testsuite/gas/mips/gotpc-aluipc-32.s
new file mode 100644
index 00000000000..877193313a1
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-aluipc-32.s
@@ -0,0 +1,51 @@
+	.file	1 "nn.c"
+	.section .mdebug.abi32
+	.previous
+	.nan	2008
+	.module	fp=xx
+	.module	nooddspreg
+	.module	arch=mips32r6
+	.abicalls
+	.text
+	.section	.rodata.str1.4,"aMS",@progbits,1
+	.align	2
+$LC0:
+	.ascii	"XXXX\000"
+	.section	.text.startup,"ax",@progbits
+	.align	2
+	.globl	main
+	.set	nomips16
+	.ent	main
+	.type	main, @function
+main:
+	.frame	$sp,32,$31		# vars= 0, regs= 1/0, args= 16, gp= 8
+	.mask	0x80000000,-4
+	.fmask	0x00000000,0
+	.set	noreorder
+	.cpload	$25
+	.set	nomacro
+	addiu	$sp,$sp,-32
+	sw	$31,28($sp)
+
+	aluipc	$4,%gotpc_ahi($LC0)
+	lw	$4,%gotpc_alo($LC0)($4)
+
+	aluipc	$25,%gotpc_call_ahi(puts)
+	lw	$25,%gotpc_call_alo(puts)($25)
+
+	.cprestore	16
+	.reloc	1f,R_MIPS_JALR,puts
+1:	jalr	$25
+	nop
+
+	lw	$31,28($sp)
+	move	$2,$0
+	jr	$31
+	addiu	$sp,$sp,32
+
+	.set	macro
+	.set	reorder
+	.end	main
+	.size	main, .-main
+	.ident	"GCC: (Debian 12.2.0-14) 12.2.0"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-64.s b/gas/testsuite/gas/mips/gotpc-aluipc-64.s
new file mode 100644
index 00000000000..234be37b6fe
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-aluipc-64.s
@@ -0,0 +1,50 @@
+	.file	1 "nn.c"
+	.section .mdebug.abi64
+	.previous
+	.abicalls
+	.text
+	.section	.rodata.str1.8,"aMS",@progbits,1
+	.align	3
+.LC0:
+	.ascii	"XXXX\000"
+	.section	.text.startup,"ax",@progbits
+	.align	2
+	.align	3
+	.globl	main
+	.set	nomips16
+	.ent	main
+	.type	main, @function
+main:
+	.frame	$sp,16,$31		# vars= 0, regs= 2/0, args= 0, gp= 0
+	.mask	0x90000000,-8
+	.fmask	0x00000000,0
+	.set	noreorder
+	.set	nomacro
+	daddiu	$sp,$sp,-16
+	sd	$28,0($sp)
+	lui	$28,%hi(%neg(%gp_rel(main)))
+	daddu	$28,$28,$25
+	sd	$31,8($sp)
+	daddiu	$28,$28,%lo(%neg(%gp_rel(main)))
+
+	aluipc	$4,%gotpc_ahi(.LC0)
+	ld	$4,%gotpc_alo(.LC0)($4)
+
+	aluipc	$25,%gotpc_call_ahi(puts)
+	ld	$25,%gotpc_call_alo(puts)($25)
+
+	.reloc	1f,R_MIPS_JALR,puts
+1:	jalr	$25
+	nop
+
+	ld	$31,8($sp)
+	ld	$28,0($sp)
+	move	$2,$0
+	jr	$31
+	daddiu	$sp,$sp,16
+
+	.set	macro
+	.set	reorder
+	.end	main
+	.size	main, .-main
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-n32.d b/gas/testsuite/gas/mips/gotpc-aluipc-n32.d
new file mode 100644
index 00000000000..41bc6d474d7
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-aluipc-n32.d
@@ -0,0 +1,17 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: R_MIPS_GOTPC support (NewABI, ALUIPC, N32)
+#source: gotpc-aluipc-64.s
+#as: -n32 -mips64r6
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text\.startup:
+#...
+.*R_MIPS_GOTPC_AHI16	\.rodata\.str1\.8
+#...
+.*R_MIPS_GOTPC_ALO16	\.rodata\.str1\.8
+#...
+.*R_MIPS_GOTPC_CALL_AHI16	puts
+#...
+.*R_MIPS_GOTPC_CALL_ALO16	puts
+#pass
diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-n64.d b/gas/testsuite/gas/mips/gotpc-aluipc-n64.d
new file mode 100644
index 00000000000..0561040ef09
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-aluipc-n64.d
@@ -0,0 +1,25 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: R_MIPS_GOTPC support (NewABI, ALUIPC, N64)
+#source: gotpc-aluipc-64.s
+#as: -64 -mips64r6
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text\.startup:
+#...
+.*R_MIPS_GOTPC_AHI16	\.LC0
+.*R_MIPS_NONE.*
+.*R_MIPS_NONE.*
+#...
+.*R_MIPS_GOTPC_ALO16	\.LC0
+.*R_MIPS_NONE.*
+.*R_MIPS_NONE.*
+#...
+.*R_MIPS_GOTPC_CALL_AHI16	puts
+.*R_MIPS_NONE.*
+.*R_MIPS_NONE.*
+#...
+.*R_MIPS_GOTPC_CALL_ALO16	puts
+.*R_MIPS_NONE.*
+.*R_MIPS_NONE.*
+#pass
diff --git a/gas/testsuite/gas/mips/gotpc-aluipc-o32.d b/gas/testsuite/gas/mips/gotpc-aluipc-o32.d
new file mode 100644
index 00000000000..4079c8de661
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-aluipc-o32.d
@@ -0,0 +1,17 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: R_MIPS_GOTPC support (NewABI, ALUIPC, O32)
+#source: gotpc-aluipc-32.s
+#as: -32 -mips32r6
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text\.startup:
+#...
+.*R_MIPS_GOTPC_AHI16	\.rodata\.str1\.4
+#...
+.*R_MIPS_GOTPC_ALO16	\.rodata\.str1\.4
+#...
+.*R_MIPS_GOTPC_CALL_AHI16	puts
+#...
+.*R_MIPS_GOTPC_CALL_ALO16	puts
+#pass
diff --git a/gas/testsuite/gas/mips/gotpc-bal-32.s b/gas/testsuite/gas/mips/gotpc-bal-32.s
new file mode 100644
index 00000000000..841a13dbf87
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-bal-32.s
@@ -0,0 +1,55 @@
+	.file	1 "nn.c"
+	.section .mdebug.abi32
+	.previous
+	.nan	2008
+	.module	fp=xx
+	.module	nooddspreg
+	.module	arch=mips32r6
+	.abicalls
+	.text
+	.section	.rodata.str1.4,"aMS",@progbits,1
+	.align	2
+$LC0:
+	.ascii	"XXXX\000"
+	.section	.text.startup,"ax",@progbits
+	.align	2
+	.globl	main
+	.set	nomips16
+	.ent	main
+	.type	main, @function
+main:
+	.frame	$sp,32,$31		# vars= 0, regs= 1/0, args= 16, gp= 8
+	.mask	0x80000000,-4
+	.fmask	0x00000000,0
+	.set	noreorder
+	.cpload	$25
+	.set	nomacro
+	addiu	$sp,$sp,-32
+	sw	$31,28($sp)
+
+	bal	. + 8
+	lui	$4,%gotpc_hi($LC0)
+	addu	$4,$4,$31
+	lw	$4,%gotpc_lo($LC0)($4)
+
+	bal	. + 8
+	lui	$25,%gotpc_call_hi(puts)
+	addu	$25,$25,$31
+	lw	$25,%gotpc_call_lo(puts)($25)
+
+	.cprestore	16
+	.reloc	1f,R_MIPS_JALR,puts
+1:	jalr	$25
+	nop
+
+	lw	$31,28($sp)
+	move	$2,$0
+	jr	$31
+	addiu	$sp,$sp,32
+
+	.set	macro
+	.set	reorder
+	.end	main
+	.size	main, .-main
+	.ident	"GCC: (Debian 12.2.0-14) 12.2.0"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gas/testsuite/gas/mips/gotpc-bal-64.s b/gas/testsuite/gas/mips/gotpc-bal-64.s
new file mode 100644
index 00000000000..c97e6b87af9
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-bal-64.s
@@ -0,0 +1,54 @@
+	.file	1 "nn.c"
+	.section .mdebug.abi64
+	.previous
+	.abicalls
+	.text
+	.section	.rodata.str1.8,"aMS",@progbits,1
+	.align	3
+.LC0:
+	.ascii	"XXXX\000"
+	.section	.text.startup,"ax",@progbits
+	.align	2
+	.align	3
+	.globl	main
+	.set	nomips16
+	.ent	main
+	.type	main, @function
+main:
+	.frame	$sp,16,$31		# vars= 0, regs= 2/0, args= 0, gp= 0
+	.mask	0x90000000,-8
+	.fmask	0x00000000,0
+	.set	noreorder
+	.set	nomacro
+	daddiu	$sp,$sp,-16
+	sd	$28,0($sp)
+	lui	$28,%hi(%neg(%gp_rel(main)))
+	daddu	$28,$28,$25
+	sd	$31,8($sp)
+	daddiu	$28,$28,%lo(%neg(%gp_rel(main)))
+
+	bal	. + 8
+	lui	$4,%gotpc_hi(.LC0)
+	daddu	$4,$4,$31
+	ld	$4,%gotpc_lo(.LC0)($4)
+
+	bal	. + 8
+	lui	$25,%gotpc_call_hi(puts)
+	daddu	$25,$25,$31
+	ld	$25,%gotpc_call_lo(puts)($25)
+
+	.reloc	1f,R_MIPS_JALR,puts
+1:	jalr	$25
+	nop
+
+	ld	$31,8($sp)
+	ld	$28,0($sp)
+	move	$2,$0
+	jr	$31
+	daddiu	$sp,$sp,16
+
+	.set	macro
+	.set	reorder
+	.end	main
+	.size	main, .-main
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gas/testsuite/gas/mips/gotpc-bal-n32.d b/gas/testsuite/gas/mips/gotpc-bal-n32.d
new file mode 100644
index 00000000000..ec412020dc7
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-bal-n32.d
@@ -0,0 +1,17 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: R_MIPS_GOTPC support (NewABI, BAL, N32)
+#source: gotpc-bal-64.s
+#as: -n32 -march=from-abi
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text\.startup:
+#...
+.*R_MIPS_GOTPC_HI16	\.rodata\.str1\.8
+#...
+.*R_MIPS_GOTPC_LO16	\.rodata\.str1\.8
+#...
+.*R_MIPS_GOTPC_CALL_HI16	puts
+#...
+.*R_MIPS_GOTPC_CALL_LO16	puts
+#pass
diff --git a/gas/testsuite/gas/mips/gotpc-bal-n64.d b/gas/testsuite/gas/mips/gotpc-bal-n64.d
new file mode 100644
index 00000000000..60b9f020f50
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-bal-n64.d
@@ -0,0 +1,25 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: R_MIPS_GOTPC support (NewABI, BAL, N64)
+#source: gotpc-bal-64.s
+#as: -64 -march=from-abi
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text\.startup:
+#...
+.*R_MIPS_GOTPC_HI16	\.rodata\.str1\.8
+.*R_MIPS_NONE.*
+.*R_MIPS_NONE.*
+#...
+.*R_MIPS_GOTPC_LO16	\.rodata\.str1\.8
+.*R_MIPS_NONE.*
+.*R_MIPS_NONE.*
+#...
+.*R_MIPS_GOTPC_CALL_HI16	puts
+.*R_MIPS_NONE.*
+.*R_MIPS_NONE.*
+#...
+.*R_MIPS_GOTPC_CALL_LO16	puts
+.*R_MIPS_NONE.*
+.*R_MIPS_NONE.*
+#pass
diff --git a/gas/testsuite/gas/mips/gotpc-bal-o32.d b/gas/testsuite/gas/mips/gotpc-bal-o32.d
new file mode 100644
index 00000000000..b4caff9bbe9
--- /dev/null
+++ b/gas/testsuite/gas/mips/gotpc-bal-o32.d
@@ -0,0 +1,17 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: R_MIPS_GOTPC support (BAL, O32)
+#source: gotpc-bal-32.s
+#as: -32 -march=from-abi
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text\.startup:
+#...
+.*R_MIPS_GOTPC_HI16	\.rodata\.str1\.4
+#...
+.*R_MIPS_GOTPC_LO16	\.rodata\.str1\.4
+#...
+.*R_MIPS_GOTPC_CALL_HI16	puts
+#...
+.*R_MIPS_GOTPC_CALL_LO16	puts
+#pass
diff --git a/gas/testsuite/gas/mips/mips.exp b/gas/testsuite/gas/mips/mips.exp
index 2ddbf0c768d..619d04b3bd5 100644
--- a/gas/testsuite/gas/mips/mips.exp
+++ b/gas/testsuite/gas/mips/mips.exp
@@ -1210,7 +1210,15 @@ if { [istarget mips*-*-vxworks*] } {
 	run_dump_test "elf-rel-xgot-n32"
 	run_dump_test "elf-rel-got-n64"
 	run_dump_test "elf-rel-xgot-n64"
+
+	run_dump_test "gotpc-bal-n64"
+	run_dump_test "gotpc-bal-n32"
+	run_dump_test "gotpc-aluipc-n64"
+	run_dump_test "gotpc-aluipc-n32"
     }
+    run_dump_test "gotpc-bal-o32"
+    run_dump_test "gotpc-aluipc-o32"
+
     run_dump_test "elf-rel17"
     if $has_newabi {
 	run_dump_test "elf-rel18"
diff --git a/include/elf/mips.h b/include/elf/mips.h
index 686d5500e02..23e95fe0c45 100644
--- a/include/elf/mips.h
+++ b/include/elf/mips.h
@@ -98,7 +98,15 @@ START_RELOC_NUMBERS (elf_mips_reloc_type)
   RELOC_NUMBER (R_MIPS_PC19_S2, 63)
   RELOC_NUMBER (R_MIPS_PCHI16, 64)
   RELOC_NUMBER (R_MIPS_PCLO16, 65)
-  FAKE_RELOC (R_MIPS_max, 66)
+  RELOC_NUMBER (R_MIPS_GOTPC_HI16, 66)
+  RELOC_NUMBER (R_MIPS_GOTPC_LO16, 67)
+  RELOC_NUMBER (R_MIPS_GOTPC_CALL_HI16, 68)
+  RELOC_NUMBER (R_MIPS_GOTPC_CALL_LO16, 69)
+  RELOC_NUMBER (R_MIPS_GOTPC_AHI16, 70)
+  RELOC_NUMBER (R_MIPS_GOTPC_ALO16, 71)
+  RELOC_NUMBER (R_MIPS_GOTPC_CALL_AHI16, 72)
+  RELOC_NUMBER (R_MIPS_GOTPC_CALL_ALO16, 73)
+  FAKE_RELOC (R_MIPS_max, 74)
   /* These relocs are used for the mips16.  */
   FAKE_RELOC (R_MIPS16_min, 100)
   RELOC_NUMBER (R_MIPS16_26, 100)
-- 
2.39.2


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

end of thread, other threads:[~2024-03-15 13:45 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-31  8:32 [PATCH] MIPS: support PCREL GOT access YunQiang Su
2024-01-31  9:24 ` Xi Ruoyao
2024-02-02  1:25   ` YunQiang Su
2024-02-05 11:48     ` Nick Clifton
2024-02-05 12:59       ` Maciej W. Rozycki
2024-02-06 16:52         ` YunQiang Su
2024-02-06 19:47           ` Maciej W. Rozycki
2024-02-25 16:00             ` YunQiang Su
2024-03-01 17:38               ` Maciej W. Rozycki
2024-03-15 13:44                 ` YunQiang Su
2024-02-02  6:39 [PATCH] MIPS: Support " YunQiang Su
2024-02-02  6:42 ` YunQiang Su

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).