[PATCH v4] MIPS: Support PCREL GOT access

Fangrui Song i@maskray.me
Wed Apr 3 04:04:19 GMT 2024


On Sat, Mar 16, 2024 at 1:51 AM YunQiang Su <syq@gcc.gnu.org> wrote:
>
> 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.

Currently loading a GOT entry requires loading the GOT base address
first, then adding an offset.
Therefore, (elaborate the reason) we need both GOT and XGOT.
MIPSr6 introduced PC-relative instructions like ..., which allow us to
use a pair of .. and .. to materialize the GOT entry address.

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

GCC's mips port names assembler relocation operators
(gas/config/tc-mips.c names them `mips_percent_op`).
Other ports seem to prefer "modifiers" (assembler modifiers,
expression modifiers).

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

typo

>         * 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.
>
> ld/ChangeLog:
>         * testsuite/ld-mips-elf/mips-elf.exp: Add GOTPC testcases.
>         * testsuite/ld-mips-elf/gotpc-callee.s: Likewise.
>         * testsuite/ld-mips-elf/gotpc.ld: Likewise.
>         * testsuite/ld-mips-elf/gotpc-o32.s: Likewise.
>         * testsuite/ld-mips-elf/gotpc-o32.dd: Likewise.
>         * testsuite/ld-mips-elf/gotpc-o32.gd: Likewise.
>         * testsuite/ld-mips-elf/gotpc-n32.s: Likewise.
>         * testsuite/ld-mips-elf/gotpc-n32.dd: Likewise.
>         * testsuite/ld-mips-elf/gotpc-n32.gd: Likewise.
>         * testsuite/ld-mips-elf/gotpc-n64.s: Likewise.
>         * testsuite/ld-mips-elf/gotpc-n64.dd: Likewise.
>         * testsuite/ld-mips-elf/gotpc-n64.gd: Likewise.
> ---
>  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 +-
>  ld/testsuite/ld-mips-elf/gotpc-callee.s   |  41 ++++
>  ld/testsuite/ld-mips-elf/gotpc-n32.dd     |  73 +++++++
>  ld/testsuite/ld-mips-elf/gotpc-n32.gd     |  15 ++
>  ld/testsuite/ld-mips-elf/gotpc-n32.s      |  46 +++++
>  ld/testsuite/ld-mips-elf/gotpc-n64.dd     |  75 +++++++
>  ld/testsuite/ld-mips-elf/gotpc-n64.gd     |  15 ++
>  ld/testsuite/ld-mips-elf/gotpc-n64.s      |  46 +++++
>  ld/testsuite/ld-mips-elf/gotpc-o32.dd     |  71 +++++++
>  ld/testsuite/ld-mips-elf/gotpc-o32.gd     |  15 ++
>  ld/testsuite/ld-mips-elf/gotpc-o32.s      |  45 +++++
>  ld/testsuite/ld-mips-elf/gotpc.ld         |  17 ++
>  ld/testsuite/ld-mips-elf/mips-elf.exp     |  23 +++
>  33 files changed, 1637 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
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-callee.s
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-n32.dd
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-n32.gd
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-n32.s
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-n64.dd
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-n64.gd
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-n64.s
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-o32.dd
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-o32.gd
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc-o32.s
>  create mode 100644 ld/testsuite/ld-mips-elf/gotpc.ld
>
> diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
> index 29602e054da..e8bb1195c27 100644
> --- a/bfd/bfd-in2.h
> +++ b/bfd/bfd-in2.h
> @@ -3658,6 +3658,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..8ebaa859475 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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..f6a6560b4c2 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 */
> +        false,                 /* partial_inplace */
> +        0,                     /* 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 89dd34e798b..c4d6787357e 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
> @@ -5240,6 +5249,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.  */
>
> @@ -5887,6 +5911,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:
> @@ -5904,6 +5932,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
> @@ -5951,6 +5981,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:
> @@ -6412,6 +6450,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 f15b5f27db8..c10ee485abf 100644
> --- a/bfd/libbfd.h
> +++ b/bfd/libbfd.h
> @@ -1273,6 +1273,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 a187afe9b56..b88763c850b 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..79884bd651b 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_AHI16 = 70,
> +  R_MIPS_GOTPC_ALO16 = 71,
> +  R_MIPS_GOTPC_CALL_AHI16 = 72,
> +  R_MIPS_GOTPC_CALL_ALO16 = 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 8f54cb8937a..7ee6c0259fa 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[] =
> @@ -15543,6 +15581,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;
> @@ -15824,6 +15870,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:
> @@ -15967,6 +16021,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:
> @@ -18388,6 +18450,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)
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-callee.s b/ld/testsuite/ld-mips-elf/gotpc-callee.s
> new file mode 100644
> index 00000000000..4689b66f302
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-callee.s
> @@ -0,0 +1,41 @@
> +       .text
> +       .set    nomips16
> +       .set    nomicromips
> +       .globl  c1
> +       .ent    c1
> +       .type   c1, @function
> +c1:
> +       .set    noreorder
> +       .set    nomacro
> +       jr      $31
> +       li      $2,1
> +       .set    reorder
> +       .set    macro
> +       .end    c1
> +       .size   c1, .-c1
> +
> +       .globl  c2
> +       .ent    c2
> +       .type   c2, @function
> +c2:
> +       .set    noreorder
> +       .set    nomacro
> +       jr      $31
> +       li      $2,2
> +       .set    reorder
> +       .set    macro
> +       .end    c2
> +       .size   c2, .-c2
> +
> +       .data
> +       .globl  g1
> +       .type   g1, @object
> +       .size   g1, 4
> +g1:
> +       .word   0x12345678
> +
> +       .globl  g2
> +       .type   g2, @object
> +       .size   g2, 4
> +g2:
> +       .word   0x09abcdef
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-n32.dd b/ld/testsuite/ld-mips-elf/gotpc-n32.dd
> new file mode 100644
> index 00000000000..2c94d04ee27
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-n32.dd
> @@ -0,0 +1,73 @@
> +
> +.*: +file format .*mips.*
> +
> +DYNAMIC SYMBOL TABLE:
> +00000000 g    DF .text 00000074 f1
> +00000090      DF \*UND\*       00000000 c1
> +00000004 g    DO \*ABS\*       00000004 g2
> +00000080      DF \*UND\*       00000000 c2
> +00000000 g    DO \*ABS\*       00000004 g1
> +
> +
> +
> +Disassembly of section .text:
> +
> +00000000 <f1>:
> +   0:  27bdfff0        addiu   sp,sp,-16
> +   4:  ffbf0008        sd      ra,8\(sp\)
> +   8:  ffb00000        sd      s0,0\(sp\)
> +   c:  24100000        li      s0,0
> +
> +00000010 <L0\^A>:
> +  10:  04110001        bal     18 <L0\^A\+0x8>
> +  14:  3c190000        lui     t9,0x0
> +  18:  033fc821        addu    t9,t9,ra
> +  1c:  8f3900a0        lw      t9,160\(t9\)
> +  20:  0320f809        jalr    t9
> +  24:  00000000        nop
> +  28:  02028021        addu    s0,s0,v0
> +  2c:  ef3f0000        aluipc  t9,0x0
> +  30:  8f3900c0        lw      t9,192\(t9\)
> +  34:  0320f809        jalr    t9
> +  38:  00000000        nop
> +  3c:  02028021        addu    s0,s0,v0
> +
> +00000040 <L0\^A>:
> +  40:  04110001        bal     48 <L0\^A\+0x8>
> +  44:  3c020000        lui     v0,0x0
> +  48:  005f1021        addu    v0,v0,ra
> +  4c:  8c42007c        lw      v0,124\(v0\)
> +  50:  00501021        addu    v0,v0,s0
> +  54:  ec7f0000        aluipc  v1,0x0
> +  58:  8c6300bc        lw      v1,188\(v1\)
> +  5c:  00431021        addu    v0,v0,v1
> +  60:  dfb00000        ld      s0,0\(sp\)
> +  64:  dfbf0008        ld      ra,8\(sp\)
> +  68:  24420001        addiu   v0,v0,1
> +  6c:  03e00009        jr      ra
> +  70:  27bd0010        addiu   sp,sp,16
> +       ...
> +
> +Disassembly of section .MIPS.stubs:
> +
> +00000080 <_MIPS_STUBS_>:
> +  80:  8f998010        lw      t9,-32752\(gp\)
> +  84:  03e07825        move    t3,ra
> +  88:  0320f809        jalr    t9
> +  8c:  24180004        li      t8,4
> +  90:  8f998010        lw      t9,-32752\(gp\)
> +  94:  03e07825        move    t3,ra
> +  98:  0320f809        jalr    t9
> +  9c:  24180002        li      t8,2
> +       ...
> +
> +Disassembly of section .got:
> +
> +000000b0 <.got>:
> +  b0:  00000000        nop
> +  b4:  80000000        lb      zero,0\(zero\)
> +  b8:  00000090        .word   0x90
> +  bc:  00000004        sllv    zero,zero,zero
> +  c0:  00000080        sll     zero,zero,0x2
> +  c4:  00000000        nop
> +#...
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-n32.gd b/ld/testsuite/ld-mips-elf/gotpc-n32.gd
> new file mode 100644
> index 00000000000..33c9b40ab77
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-n32.gd
> @@ -0,0 +1,15 @@
> +
> +Primary GOT:
> + Canonical gp value: 000080a0
> +
> + Reserved entries:
> +   Address     Access  Initial Purpose
> +  000000b0 -32752\(gp\) 00000000 Lazy resolver
> +  000000b4 -32748\(gp\) 80000000 Module pointer \(GNU extension\)
> +
> + Global entries:
> +   Address     Access  Initial Sym.Val. Type    Ndx Name
> +  000000b8 -32744\(gp\) 00000090 00000090 FUNC    UND c1
> +  000000bc -32740\(gp\) 00000004 00000004 OBJECT  ABS g2
> +  000000c0 -32736\(gp\) 00000080 00000080 FUNC    UND c2
> +  000000c4 -32732\(gp\) 00000000 00000000 OBJECT  ABS g1
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-n32.s b/ld/testsuite/ld-mips-elf/gotpc-n32.s
> new file mode 100644
> index 00000000000..ce4f4af87f1
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-n32.s
> @@ -0,0 +1,46 @@
> +       .text
> +       .globl  f1
> +       .set    nomips16
> +       .set    nomicromips
> +       .ent    f1
> +       .type   f1, @function
> +f1:
> +       .set    noreorder
> +       .set    nomacro
> +       addiu   $sp,$sp,-16
> +       sd      $31,8($sp)
> +       sd      $16,0($sp)
> +       li      $16,0
> +
> +       bal     . + 8
> +       lui     $25,%gotpc_call_hi(c1)
> +       addu    $25,$25,$31
> +       lw      $25,%gotpc_call_lo(c1)($25)
> +       jalr    $25
> +       nop
> +       addu    $16,$16,$2
> +       aluipc  $25,%gotpc_call_ahi(c2)
> +       lw      $25,%gotpc_call_alo(c2)($25)
> +       jalr    $25
> +       nop
> +       addu    $16,$16,$2
> +
> +       bal     . + 8
> +       lui     $2,%gotpc_hi(g1)
> +       addu    $2,$2,$31
> +       lw      $2,%gotpc_lo(g1)($2)
> +       addu    $2,$2,$16
> +       aluipc  $3,%gotpc_ahi(g2)
> +       lw      $3,%gotpc_alo(g2)($3)
> +       addu    $2,$2,$3
> +
> +       ld      $16,0($sp)
> +       ld      $31,8($sp)
> +       addiu   $2,$2,1
> +       jr      $31
> +       addiu   $sp,$sp,16
> +
> +       .set    macro
> +       .set    reorder
> +       .end    f1
> +       .size   f1, .-f1
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-n64.dd b/ld/testsuite/ld-mips-elf/gotpc-n64.dd
> new file mode 100644
> index 00000000000..08e8e2b48a1
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-n64.dd
> @@ -0,0 +1,75 @@
> +
> +.*: +file format .*mips.*
> +
> +DYNAMIC SYMBOL TABLE:
> +0000000000000000 g    DF .text 0000000000000074 f1
> +0000000000000090      DF \*UND\*       0000000000000000 c1
> +0000000000000004 g    DO \*ABS\*       0000000000000004 g2
> +0000000000000080      DF \*UND\*       0000000000000000 c2
> +0000000000000000 g    DO \*ABS\*       0000000000000004 g1
> +
> +
> +
> +Disassembly of section .text:
> +
> +0000000000000000 <f1>:
> +   0:  67bdfff0        daddiu  sp,sp,-16
> +   4:  ffbf0008        sd      ra,8\(sp\)
> +   8:  ffb00000        sd      s0,0\(sp\)
> +   c:  24100000        li      s0,0
> +
> +0000000000000010 <L0\^A>:
> +  10:  04110001        bal     18 <L0\^A\+0x8>
> +  14:  3c190000        lui     t9,0x0
> +  18:  033fc82d        daddu   t9,t9,ra
> +  1c:  df3900a8        ld      t9,168\(t9\)
> +  20:  0320f809        jalr    t9
> +  24:  00000000        nop
> +  28:  02028021        addu    s0,s0,v0
> +  2c:  ef3f0000        aluipc  t9,0x0
> +  30:  df3900d0        ld      t9,208\(t9\)
> +  34:  0320f809        jalr    t9
> +  38:  00000000        nop
> +  3c:  02028021        addu    s0,s0,v0
> +
> +0000000000000040 <L0\^A>:
> +  40:  04110001        bal     48 <L0\^A\+0x8>
> +  44:  3c020000        lui     v0,0x0
> +  48:  005f102d        daddu   v0,v0,ra
> +  4c:  8c420090        lw      v0,144\(v0\)
> +  50:  00501021        addu    v0,v0,s0
> +  54:  ec7f0000        aluipc  v1,0x0
> +  58:  8c6300c8        lw      v1,200\(v1\)
> +  5c:  00431021        addu    v0,v0,v1
> +  60:  dfb00000        ld      s0,0\(sp\)
> +  64:  dfbf0008        ld      ra,8\(sp\)
> +  68:  24420001        addiu   v0,v0,1
> +  6c:  03e00009        jr      ra
> +  70:  67bd0010        daddiu  sp,sp,16
> +       ...
> +
> +Disassembly of section .MIPS.stubs:
> +
> +0000000000000080 <_MIPS_STUBS_>:
> +  80:  df998010        ld      t9,-32752\(gp\)
> +  84:  03e07825        move    t3,ra
> +  88:  0320f809        jalr    t9
> +  8c:  64180004        daddiu  t8,zero,4
> +  90:  df998010        ld      t9,-32752\(gp\)
> +  94:  03e07825        move    t3,ra
> +  98:  0320f809        jalr    t9
> +  9c:  64180002        daddiu  t8,zero,2
> +       ...
> +
> +Disassembly of section .got:
> +
> +00000000000000b0 <.got>:
> +       ...
> +  bc:  80000000        lb      zero,0\(zero\)
> +  c0:  00000090        .word   0x90
> +  c4:  00000000        nop
> +  c8:  00000004        sllv    zero,zero,zero
> +  cc:  00000000        nop
> +  d0:  00000080        sll     zero,zero,0x2
> +       ...
> +#...
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-n64.gd b/ld/testsuite/ld-mips-elf/gotpc-n64.gd
> new file mode 100644
> index 00000000000..c08cca49ba4
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-n64.gd
> @@ -0,0 +1,15 @@
> +
> +Primary GOT:
> + Canonical gp value: 00000000000080a0
> +
> + Reserved entries:
> +           Address     Access          Initial Purpose
> +  00000000000000b0 -32752\(gp\) 0000000000000000 Lazy resolver
> +  00000000000000b8 -32744\(gp\) 8000000000000000 Module pointer \(GNU extension\)
> +
> + Global entries:
> +           Address     Access          Initial         Sym.Val. Type    Ndx Name
> +  00000000000000c0 -32736\(gp\) 0000000000000090 0000000000000090 FUNC    UND c1
> +  00000000000000c8 -32728\(gp\) 0000000000000004 0000000000000004 OBJECT  ABS g2
> +  00000000000000d0 -32720\(gp\) 0000000000000080 0000000000000080 FUNC    UND c2
> +  00000000000000d8 -32712\(gp\) 0000000000000000 0000000000000000 OBJECT  ABS g1
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-n64.s b/ld/testsuite/ld-mips-elf/gotpc-n64.s
> new file mode 100644
> index 00000000000..47dbd40af2b
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-n64.s
> @@ -0,0 +1,46 @@
> +       .text
> +       .globl  f1
> +       .set    nomips16
> +       .set    nomicromips
> +       .ent    f1
> +       .type   f1, @function
> +f1:
> +       .set    noreorder
> +       .set    nomacro
> +       daddiu  $sp,$sp,-16
> +       sd      $31,8($sp)
> +       sd      $16,0($sp)
> +       li      $16,0
> +
> +       bal     . + 8
> +       lui     $25,%gotpc_call_hi(c1)
> +       daddu   $25,$25,$31
> +       ld      $25,%gotpc_call_lo(c1)($25)
> +       jalr    $25
> +       nop
> +       addu    $16,$16,$2
> +       aluipc  $25,%gotpc_call_ahi(c2)
> +       ld      $25,%gotpc_call_alo(c2)($25)
> +       jalr    $25
> +       nop
> +       addu    $16,$16,$2
> +
> +       bal     . + 8
> +       lui     $2,%gotpc_hi(g1)
> +       daddu   $2,$2,$31
> +       lw      $2,%gotpc_lo(g1)($2)
> +       addu    $2,$2,$16
> +       aluipc  $3,%gotpc_ahi(g2)
> +       lw      $3,%gotpc_alo(g2)($3)
> +       addu    $2,$2,$3
> +
> +       ld      $16,0($sp)
> +       ld      $31,8($sp)
> +       addiu   $2,$2,1
> +       jr      $31
> +       daddiu  $sp,$sp,16
> +
> +       .set    macro
> +       .set    reorder
> +       .end    f1
> +       .size   f1, .-f1
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-o32.dd b/ld/testsuite/ld-mips-elf/gotpc-o32.dd
> new file mode 100644
> index 00000000000..1c77b059ef6
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-o32.dd
> @@ -0,0 +1,71 @@
> +
> +.*: +file format .*mips.*
> +
> +DYNAMIC SYMBOL TABLE:
> +00000000 g    DF .text 00000070 f1
> +00000080      DF \*UND\*       00000000 c1
> +00000004 g    DO \*ABS\*       00000004 g2
> +00000070      DF \*UND\*       00000000 c2
> +00000000 g    DO \*ABS\*       00000004 g1
> +
> +
> +
> +Disassembly of section .text:
> +
> +00000000 <f1>:
> +   0:  27bdffe0        addiu   sp,sp,-32
> +   4:  afbf001c        sw      ra,28\(sp\)
> +   8:  afb00018        sw      s0,24\(sp\)
> +   c:  24100000        li      s0,0
> +
> +00000010 <L0\^A>:
> +  10:  04110001        bal     18 <L0\^A\+0x8>
> +  14:  3c190000        lui     t9,0x0
> +  18:  033fc821        addu    t9,t9,ra
> +  1c:  8f390090        lw      t9,144\(t9\)
> +  20:  0320f809        jalr    t9
> +  24:  00000000        nop
> +  28:  02028021        addu    s0,s0,v0
> +  2c:  ef3f0000        aluipc  t9,0x0
> +  30:  8f3900b0        lw      t9,176\(t9\)
> +  34:  0320f809        jalr    t9
> +  38:  00000000        nop
> +  3c:  02028021        addu    s0,s0,v0
> +
> +00000040 <L0\^A>:
> +  40:  04110001        bal     48 <L0\^A\+0x8>
> +  44:  3c020000        lui     v0,0x0
> +  48:  005f1021        addu    v0,v0,ra
> +  4c:  8c42006c        lw      v0,108\(v0\)
> +  50:  00501021        addu    v0,v0,s0
> +  54:  ec7f0000        aluipc  v1,0x0
> +  58:  8c6300ac        lw      v1,172\(v1\)
> +  5c:  00431021        addu    v0,v0,v1
> +  60:  8fb00018        lw      s0,24\(sp\)
> +  64:  8fbf001c        lw      ra,28\(sp\)
> +  68:  03e00009        jr      ra
> +  6c:  27bd0020        addiu   sp,sp,32
> +
> +Disassembly of section .MIPS.stubs:
> +
> +00000070 <_MIPS_STUBS_>:
> +  70:  8f998010        lw      t9,-32752\(gp\)
> +  74:  03e07825        move    t7,ra
> +  78:  0320f809        jalr    t9
> +  7c:  24180004        li      t8,4
> +  80:  8f998010        lw      t9,-32752\(gp\)
> +  84:  03e07825        move    t7,ra
> +  88:  0320f809        jalr    t9
> +  8c:  24180002        li      t8,2
> +       ...
> +
> +Disassembly of section .got:
> +
> +000000a0 <.got>:
> +  a0:  00000000        nop
> +  a4:  80000000        lb      zero,0\(zero\)
> +  a8:  00000080        sll     zero,zero,0x2
> +  ac:  00000004        sllv    zero,zero,zero
> +  b0:  00000070        tge     zero,zero,0x1
> +  b4:  00000000        nop
> +#...
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-o32.gd b/ld/testsuite/ld-mips-elf/gotpc-o32.gd
> new file mode 100644
> index 00000000000..7a479237a22
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-o32.gd
> @@ -0,0 +1,15 @@
> +
> +Primary GOT:
> + Canonical gp value: 00008090
> +
> + Reserved entries:
> +   Address     Access  Initial Purpose
> +  000000a0 -32752\(gp\) 00000000 Lazy resolver
> +  000000a4 -32748\(gp\) 80000000 Module pointer \(GNU extension\)
> +
> + Global entries:
> +   Address     Access  Initial Sym.Val. Type    Ndx Name
> +  000000a8 -32744\(gp\) 00000080 00000080 FUNC    UND c1
> +  000000ac -32740\(gp\) 00000004 00000004 OBJECT  ABS g2
> +  000000b0 -32736\(gp\) 00000070 00000070 FUNC    UND c2
> +  000000b4 -32732\(gp\) 00000000 00000000 OBJECT  ABS g1
> diff --git a/ld/testsuite/ld-mips-elf/gotpc-o32.s b/ld/testsuite/ld-mips-elf/gotpc-o32.s
> new file mode 100644
> index 00000000000..3ac3b650aa1
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc-o32.s
> @@ -0,0 +1,45 @@
> +       .text
> +       .globl  f1
> +       .set    nomips16
> +       .set    nomicromips
> +       .ent    f1
> +       .type   f1, @function
> +f1:
> +       .set    noreorder
> +       .set    nomacro
> +       addiu   $sp,$sp,-32
> +       sw      $31,28($sp)
> +       sw      $16,24($sp)
> +       li      $16,0
> +
> +       bal     . + 8
> +       lui     $25,%gotpc_call_hi(c1)
> +       addu    $25,$25,$31
> +       lw      $25,%gotpc_call_lo(c1)($25)
> +       jalr    $25
> +       nop
> +       addu    $16,$16,$2
> +       aluipc  $25,%gotpc_call_ahi(c2)
> +       lw      $25,%gotpc_call_alo(c2)($25)
> +       jalr    $25
> +       nop
> +       addu    $16,$16,$2
> +
> +       bal     . + 8
> +       lui     $2,%gotpc_hi(g1)
> +       addu    $2,$2,$31
> +       lw      $2,%gotpc_lo(g1)($2)
> +       addu    $2,$2,$16
> +       aluipc  $3,%gotpc_ahi(g2)
> +       lw      $3,%gotpc_alo(g2)($3)
> +       addu    $2,$2,$3
> +
> +       lw      $16,24($sp)
> +       lw      $31,28($sp)
> +       jr      $31
> +       addiu   $sp,$sp,32
> +
> +       .set    macro
> +       .set    reorder
> +       .end    f1
> +       .size   f1, .-f1
> diff --git a/ld/testsuite/ld-mips-elf/gotpc.ld b/ld/testsuite/ld-mips-elf/gotpc.ld
> new file mode 100644
> index 00000000000..3dadc7e6d4d
> --- /dev/null
> +++ b/ld/testsuite/ld-mips-elf/gotpc.ld
> @@ -0,0 +1,17 @@
> +ENTRY (foo);
> +SECTIONS
> +{
> +  .text : { *(.text) }
> +  .MIPS.stubs : { *(.MIPS.stubs) }
> +  HIDDEN (_gp = ALIGN(16) + 0x7ff0);
> +  .got : { *(.got) }
> +  .dynamic : { *(.dynamic) }
> +  .hash : { *(.hash) }
> +  .dynsym : { *(.dynsym) }
> +  .dynstr : { *(.dynstr) }
> +  .pdr : { *(.pdr) }
> +  .shstrtab : { *(.shstrtab) }
> +  .symtab : { *(.symtab) }
> +  .strtab : { *(.strtab) }
> +  /DISCARD/ : { *(*) }
> +}
> diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp
> index 50af78d1430..550f373efdc 100644
> --- a/ld/testsuite/ld-mips-elf/mips-elf.exp
> +++ b/ld/testsuite/ld-mips-elf/mips-elf.exp
> @@ -719,6 +719,29 @@ if { $linux_gnu } {
>                     "readelf --relocs gp-hidden${suff64}.rd" \
>                     "readelf --syms gp-hidden.sd"] \
>                 "gp-hidden-${abi}"]]
> +
> +       set gotpc_asflags [regsub -- {-march=[^[:blank:]]*} $abi_asflags($abi) {}]
> +       run_ld_link_tests [list \
> +           [list \
> +               "MIPS R_MIPS_GOTPC support (Prepare, $abi)" \
> +               "$abi_ldflags($abi) -shared -T gotpc.ld" \
> +               "" \
> +               "$gotpc_asflags -mips64r6 -KPIC" \
> +               [list gotpc-callee.s] \
> +               "" \
> +               "libgotpc-callee-${abi}.so"]]
> +       run_ld_link_tests [list \
> +           [list \
> +               "MIPS R_MIPS_GOTPC support ($abi)" \
> +               "$abi_ldflags($abi) -shared -T gotpc.ld \
> +               -Ltmpdir -lgotpc-callee-${abi}" \
> +               "" \
> +               "$gotpc_asflags -mips64r6 -KPIC" \
> +               [list gotpc-${abi}.s] \
> +               [list \
> +                   "objdump -DTC gotpc-${abi}.dd" \
> +                   "readelf -A gotpc-${abi}.gd"] \
> +               "gotpc-${abi}.so"]]
>      }
>  }
>
> --
> 2.39.2
>


More information about the Binutils mailing list