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)
+#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)
