public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3] MIPS: Support PCREL GOT access
@ 2024-02-02  6:42 YunQiang Su
  0 siblings, 0 replies; only message in thread
From: YunQiang Su @ 2024-02-02  6:42 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..1832061a34e
--- /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 (OldABI, 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..57cb891042a
--- /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 (OldABI, 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] only message in thread

only message in thread, other threads:[~2024-02-02  6:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-02  6:42 [PATCH v3] MIPS: Support PCREL GOT access 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).