[binutils-gdb] PR 19977: MIPS: Add missing pairing for REL PCHI/PCLO relocations

Maciej W. Rozycki macro@sourceware.org
Sat Jul 12 00:34:24 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=68f5cb38c27699e9b4840f22596ede96762c4796

commit 68f5cb38c27699e9b4840f22596ede96762c4796
Author: Maciej W. Rozycki <macro@orcam.me.uk>
Date:   Sat Jul 12 01:25:53 2025 +0100

    PR 19977: MIPS: Add missing pairing for REL PCHI/PCLO relocations
    
    Just as with all HI/LO 16-bit partial relocations the newly-introduced
    MIPSr6 PC-relative R_MIPS_PCHI16 and R_MIPS_PCLO16 relocations require
    pairing for correct borrow propagation from the low part to the high
    part with REL targets, another case for PR 19977.
    
    Unlike with absolute relocation, there is a complication here in that
    both parts represent a calculation that is relative to the PC at the
    individual relocation's location rather than both referring to the
    location of the R_MIPS_PCHI16 relocation, normally applied to an AUIPC
    instruction, the location of which is used for the run-time calculation
    executed by hardware.
    
    To take this semantics into account, the addend of the R_MIPS_PCLO16
    relocation matching a given R_MIPS_PCHI16 relocation is expected to be
    adjusted in the source assembly file for the distance between the two
    relocations in a single pair, so that once both relocations have been
    calculated by the linker, the expression calculated at run time is such
    as if the combined 32-bit immediate was added at the location of the
    AUIPC instruction.
    
    So for matching R_MIPS_PCHI16 and R_MIPS_PCLO16 relocations into pairs
    GAS needs to check for the distance between the two relocations to be
    equal to the difference between the addends supplied, and then the
    linker has to subtract the low part of the distance between the two
    relocations from the low part in calculating the high part, so as to
    factor in any borrow.
    
    A further complication is that `_bfd_mips_elf_lo16_reloc' handler is
    supplied with the addend differently depending on whether it has been
    called by GAS via `bfd_install_relocation', or by the generic linker via
    `bfd_perform_relocation'.  In the former case the addend is supplied
    with the relocation itself while in the latter one it comes from the
    field being relocated.
    
    We currently ignore the addend supplied with the relocation and it works
    for calculating absolute high-part relocations, because the same addend
    has been previously supplied with them when `_bfd_mips_elf_hi16_reloc'
    was called, however this approach does not work for the PC-relative case
    because as noted above the low-part addend is different and we need to
    consistently apply the distance adjustment both with GAS and LD.
    
    Since the supplied addend and one retrieved from field being relocated
    won't ever be both nonzero, just use the sum of the two values.
    
    The low-part addend in `mips_elf_add_lo16_rel_addend' always comes from
    the field being relocated, so there's no complication there, we just
    need to apply the same adjustment.
    
    New linker test cases verify that the same ultimate machine code is
    produced both for ELF and S-record output formats, ensuring that the
    both the MIPS/ELF linker and the generic linker behave in the correct
    way, consistent with each other.

Diff:
---
 bfd/elf32-mips.c                           |  4 +-
 bfd/elf64-mips.c                           |  4 +-
 bfd/elfn32-mips.c                          |  4 +-
 bfd/elfxx-mips.c                           | 30 ++++++++---
 gas/config/tc-mips.c                       | 45 +++++++++++++----
 gas/testsuite/gas/mips/mips.exp            |  7 +++
 gas/testsuite/gas/mips/pcrel-hilo-64.d     | 79 +++++++++++++++++++++++++++++
 gas/testsuite/gas/mips/pcrel-hilo-addend.d | 63 +++++++++++++++++++++++
 gas/testsuite/gas/mips/pcrel-hilo-match.d  | 28 +++++++++++
 gas/testsuite/gas/mips/pcrel-hilo-match.s  | 81 ++++++++++++++++++++++++++++++
 gas/testsuite/gas/mips/pcrel-hilo-n32.d    | 31 ++++++++++++
 gas/testsuite/gas/mips/pcrel-hilo.d        | 30 +++++++++++
 gas/testsuite/gas/mips/pcrel-hilo.s        | 48 ++++++++++++++++++
 ld/testsuite/ld-mips-elf/mips-elf.exp      | 11 ++++
 ld/testsuite/ld-mips-elf/pcrel-hilo-srec.d |  6 +++
 ld/testsuite/ld-mips-elf/pcrel-hilo.d      | 42 ++++++++++++++++
 ld/testsuite/ld-mips-elf/pcrel-hilo.ld     | 14 ++++++
 17 files changed, 505 insertions(+), 22 deletions(-)

diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index 6fe93a893e8..45856b14af0 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -789,7 +789,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
 	 true,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_signed, /* complain_on_overflow */
-	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 _bfd_mips_elf_hi16_reloc, /* special_function */
 	 "R_MIPS_PCHI16",	/* name */
 	 true,			/* partial_inplace */
 	 0x0000ffff,		/* src_mask */
@@ -803,7 +803,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
 	 true,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont, /* complain_on_overflow */
-	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 _bfd_mips_elf_lo16_reloc, /* special_function */
 	 "R_MIPS_PCLO16",	/* name */
 	 true,			/* partial_inplace */
 	 0x0000ffff,		/* src_mask */
diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
index 5b5521079e1..29dcadd3230 100644
--- a/bfd/elf64-mips.c
+++ b/bfd/elf64-mips.c
@@ -868,7 +868,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
 	 true,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_signed, /* complain_on_overflow */
-	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 _bfd_mips_elf_hi16_reloc, /* special_function */
 	 "R_MIPS_PCHI16",	/* name */
 	 true,			/* partial_inplace */
 	 0x0000ffff,		/* src_mask */
@@ -882,7 +882,7 @@ static reloc_howto_type mips_elf64_howto_table_rel[] =
 	 true,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont, /* complain_on_overflow */
-	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 _bfd_mips_elf_lo16_reloc, /* special_function */
 	 "R_MIPS_PCLO16",	/* name */
 	 true,			/* partial_inplace */
 	 0x0000ffff,		/* src_mask */
diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c
index e457bfc9849..d72e2f5236a 100644
--- a/bfd/elfn32-mips.c
+++ b/bfd/elfn32-mips.c
@@ -847,7 +847,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
 	 true,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_signed, /* complain_on_overflow */
-	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 _bfd_mips_elf_hi16_reloc, /* special_function */
 	 "R_MIPS_PCHI16",	/* name */
 	 true,			/* partial_inplace */
 	 0x0000ffff,		/* src_mask */
@@ -861,7 +861,7 @@ static reloc_howto_type elf_mips_howto_table_rel[] =
 	 true,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont, /* complain_on_overflow */
-	 _bfd_mips_elf_generic_reloc,   /* special_function */
+	 _bfd_mips_elf_lo16_reloc, /* special_function */
 	 "R_MIPS_PCLO16",	/* name */
 	 true,			/* partial_inplace */
 	 0x0000ffff,		/* src_mask */
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 6f323289ad6..7d1dff1d721 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -2600,20 +2600,22 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
      extended.  For example, an addend of 0x38000 would have 0x0004 in
      the high part and 0x8000 (=0xff..f8000) in the low part.
      To extract the actual addend, calculate
-     ((hi & 0xffff) << 16) + ((lo & 0xffff) ^ 0x8000) - 0x8000.
-     We will be applying (symbol + addend) & 0xffff to the low insn,
-     and we want to apply (symbol + addend + 0x8000) >> 16 to the
-     high insn (the +0x8000 adjusting for when the applied low part is
-     negative).  */
+     ((hi & 0xffff) << 16) + ((lo & 0xffff) ^ 0x8000) - 0x8000.  */
   vallo = _bfd_mips_elf_sign_extend (bfd_get_32 (abfd, location) & 0xffff, 16);
   _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, false,
 			       location);
+  /* Add in the separate addend, if any.  Since we are REL here this
+     will have been set and the in-place addend cleared if we have
+     been called from GAS via `bfd_install_relocation'.  */
+  vallo += reloc_entry->addend;
 
   tdata = mips_elf_tdata (abfd);
   while (tdata->mips_hi16_list != NULL)
     {
       bfd_reloc_status_type ret;
       struct mips_hi16 *hi;
+      bfd_vma addhi;
+      bfd_vma addlo;
 
       hi = tdata->mips_hi16_list;
 
@@ -2629,7 +2631,19 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
       else if (hi->rel.howto->type == R_MICROMIPS_GOT16)
 	hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MICROMIPS_HI16, false);
 
-      hi->rel.addend += vallo;
+      /* We will be applying (symbol + addend) & 0xffff to the low insn,
+	 and we want to apply (symbol + addend + 0x8000) >> 16 to the
+	 high insn (the +0x8000 adjusting for when the applied low part is
+	 negative).  */
+      addhi = (hi->rel.addend + 0x8000) & ~(bfd_vma) 0xffff;
+      addlo = vallo;
+
+      /* For a PC-relative relocation the PCLO16 part of the addend
+	 is relative to its PC and not ours, so we need to adjust it.  */
+      if (hi->rel.howto->type == R_MIPS_PCHI16)
+	addlo -= reloc_entry->address - hi->rel.address;
+
+      hi->rel.addend = addhi + _bfd_mips_elf_sign_extend (addlo & 0xffff, 16);
 
       ret = _bfd_mips_elf_generic_reloc (abfd, &hi->rel, symbol, hi->data,
 					 hi->input_section, output_bfd,
@@ -8334,6 +8348,10 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
 				contents);
 
   l <<= lo16_howto->rightshift;
+  /* For a PC-relative relocation the PCLO16 part of the addend
+     is relative to its PC and not ours, so we need to adjust it.  */
+  if (r_type == R_MIPS_PCHI16)
+    l = (l - (lo16_relocation->r_offset - rel->r_offset)) & 0xffff;
   l = _bfd_mips_elf_sign_extend (l, 16);
 
   *addend <<= 16;
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 9134cef96be..7d0d8559115 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -4328,14 +4328,16 @@ got16_reloc_p (bfd_reloc_code_real_type reloc)
 static inline bool
 hi16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
+  return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_HI16_S_PCREL
+	  || reloc == BFD_RELOC_MIPS16_HI16_S
 	  || reloc == BFD_RELOC_MICROMIPS_HI16_S);
 }
 
 static inline bool
 lo16_reloc_p (bfd_reloc_code_real_type reloc)
 {
-  return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
+  return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_LO16_PCREL
+	  || reloc == BFD_RELOC_MIPS16_LO16
 	  || reloc == BFD_RELOC_MICROMIPS_LO16);
 }
 
@@ -4402,8 +4404,9 @@ static inline bfd_reloc_code_real_type
 matching_lo_reloc (bfd_reloc_code_real_type reloc)
 {
   return (mips16_reloc_p (reloc) ? BFD_RELOC_MIPS16_LO16
-	  : (micromips_reloc_p (reloc) ? BFD_RELOC_MICROMIPS_LO16
-	     : BFD_RELOC_LO16));
+	  : micromips_reloc_p (reloc) ? BFD_RELOC_MICROMIPS_LO16
+	  : reloc == BFD_RELOC_HI16_S_PCREL ? BFD_RELOC_LO16_PCREL
+	  : BFD_RELOC_LO16);
 }
 
 /* Return true if the given fixup is followed by a matching R_MIPS_LO16
@@ -4415,7 +4418,12 @@ fixup_has_matching_lo_p (fixS *fixp)
   return (fixp->fx_next != NULL
 	  && fixp->fx_next->fx_r_type == matching_lo_reloc (fixp->fx_r_type)
 	  && fixp->fx_addsy == fixp->fx_next->fx_addsy
-	  && fixp->fx_offset == fixp->fx_next->fx_offset);
+	  && (fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
+	      ? (fixp->fx_next->fx_offset - fixp->fx_offset
+		 == ((fixp->fx_next->fx_frag->fr_address
+			+ fixp->fx_next->fx_where)
+		     - (fixp->fx_frag->fr_address + fixp->fx_where)))
+	      : fixp->fx_offset == fixp->fx_next->fx_offset));
 }
 
 /* Move all labels in LABELS to the current insertion point.  TEXT_P
@@ -15413,6 +15421,13 @@ mips_frob_file_before_adjust (void)
    if the user knows that adding 2 to "foo" will not induce a carry to
    the high 16 bits.
 
+   A %pcrel_lo() expression matches a %pcrel_hi() expression if:
+
+      (a) it refers to the same symbol; and
+      (b) the offset applied in the %pcrel_lo() expression equals
+	  the offset applied in the %pcrel_hi() expression plus the
+	  distance from the location of %pcrel_hi() to %pcrel_lo().
+
    When several %lo()s match a particular %got() or %hi(), we use the
    following rules to distinguish them:
 
@@ -15484,9 +15499,14 @@ mips_frob_file (void)
 
 	  if ((*pos)->fx_r_type == looking_for_rtype
 	      && symbol_same_p ((*pos)->fx_addsy, l->fixp->fx_addsy)
-	      && (*pos)->fx_offset >= l->fixp->fx_offset
+	      && (l->fixp->fx_r_type == BFD_RELOC_HI16_S_PCREL
+		  ? ((*pos)->fx_offset - l->fixp->fx_offset
+		     == (((*pos)->fx_frag->fr_address + (*pos)->fx_where)
+			 - (l->fixp->fx_frag->fr_address + l->fixp->fx_where)))
+		  : (*pos)->fx_offset >= l->fixp->fx_offset)
 	      && (lo_pos == NULL
-		  || (*pos)->fx_offset < (*lo_pos)->fx_offset
+		  || (l->fixp->fx_r_type != BFD_RELOC_HI16_S_PCREL
+		      && (*pos)->fx_offset < (*lo_pos)->fx_offset)
 		  || (!matched_lo_p
 		      && (*pos)->fx_offset == (*lo_pos)->fx_offset)))
 	    lo_pos = pos;
@@ -15497,15 +15517,20 @@ mips_frob_file (void)
 
       /* If we found a match, remove the high-part relocation from its
 	 current position and insert it before the low-part relocation.
-	 Make the offsets match so that fixup_has_matching_lo_p()
-	 will return true.
+
+	 For absolute relocations make the offsets match so that
+	 fixup_has_matching_lo_p() will return true.  For PC-relative
+	 relocations the distance between the offsets is retained
+	 according to expectations in `fixup_has_matching_lo_p',
+	 `_bfd_mips_elf_lo16_reloc' and `mips_elf_add_lo16_rel_addend'.
 
 	 We don't warn about unmatched high-part relocations since some
 	 versions of gcc have been known to emit dead "lui ...%hi(...)"
 	 instructions.  */
       if (lo_pos != NULL)
 	{
-	  l->fixp->fx_offset = (*lo_pos)->fx_offset;
+	  if (l->fixp->fx_r_type != BFD_RELOC_HI16_S_PCREL)
+	    l->fixp->fx_offset = (*lo_pos)->fx_offset;
 	  if (l->fixp->fx_next != *lo_pos)
 	    {
 	      *hi_pos = l->fixp->fx_next;
diff --git a/gas/testsuite/gas/mips/mips.exp b/gas/testsuite/gas/mips/mips.exp
index 1a766ffc821..73ea41d59c6 100644
--- a/gas/testsuite/gas/mips/mips.exp
+++ b/gas/testsuite/gas/mips/mips.exp
@@ -1724,6 +1724,13 @@ if { [istarget mips*-*-vxworks*] } {
 	run_dump_test "pcrel-4-n32"
 	run_dump_test "pcrel-4-64"
     }
+    run_dump_test "pcrel-hilo-match"
+    run_dump_test "pcrel-hilo-addend"
+    run_dump_test "pcrel-hilo"
+    if $has_newabi {
+	run_dump_test "pcrel-hilo-n32"
+	run_dump_test "pcrel-hilo-64"
+    }
 
     run_dump_test "pcrel-reloc-1"
     run_dump_test "pcrel-reloc-1-r6"
diff --git a/gas/testsuite/gas/mips/pcrel-hilo-64.d b/gas/testsuite/gas/mips/pcrel-hilo-64.d
new file mode 100644
index 00000000000..92c697ffb42
--- /dev/null
+++ b/gas/testsuite/gas/mips/pcrel-hilo-64.d
@@ -0,0 +1,79 @@
+#readelf: -r
+#name: MIPSr6 PCHI16/PCLO16 relocations (n64)
+#as: -mabi=64 -march=mips64r6 -mno-pdr
+#source: pcrel-hilo.s
+
+Relocation section '\.rela\.text' at offset .+ contains 24 entries:
+  Offset          Info           Type           Sym\. Value    Sym\. Name \+ Addend
+000000000000  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ 7fec
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000000004  000900000005 R_MIPS_HI16       0000000000000000 baz \+ 0
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000000008  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ 7ff8
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+00000000000c  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ fff0
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000000010  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 7ffc
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000000014  000900000006 R_MIPS_LO16       0000000000000000 baz \+ 0
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000000018  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 8008
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+00000000001c  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 10000
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000000020  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ 800c
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000000024  000900000005 R_MIPS_HI16       0000000000000000 baz \+ 0
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000000028  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ 8018
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+00000000002c  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ 10010
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030030  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 3801c
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030034  000900000006 R_MIPS_LO16       0000000000000000 baz \+ 0
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030038  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 38028
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+00000003003c  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 40020
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030040  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 3802c
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030044  000900000006 R_MIPS_LO16       0000000000000000 baz \+ 0
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030048  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 38038
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+00000003004c  000800000041 R_MIPS_PCLO16     0000000000000000 bar \+ 40030
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030050  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ 3803c
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030054  000900000005 R_MIPS_HI16       0000000000000000 baz \+ 0
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+000000030058  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ 38048
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
+00000003005c  000800000040 R_MIPS_PCHI16     0000000000000000 bar \+ 40040
+                    Type2: R_MIPS_NONE      
+                    Type3: R_MIPS_NONE      
diff --git a/gas/testsuite/gas/mips/pcrel-hilo-addend.d b/gas/testsuite/gas/mips/pcrel-hilo-addend.d
new file mode 100644
index 00000000000..296101cbd5c
--- /dev/null
+++ b/gas/testsuite/gas/mips/pcrel-hilo-addend.d
@@ -0,0 +1,63 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: MIPSr6 PCHI16/PCLO16 in-place addends (o32)
+#as: -mabi=32 -mno-pdr
+#source: pcrel-hilo.s
+
+.*: +file format .*mips.*
+
+Disassembly of section \.text:
+00000000 <[^>]*> ec9e0000 	auipc	a0,0x0
+			0: R_MIPS_PCHI16	bar
+00000004 <[^>]*> 3c050000 	lui	a1,0x0
+			4: R_MIPS_HI16	baz
+00000008 <[^>]*> ecde0000 	auipc	a2,0x0
+			8: R_MIPS_PCHI16	bar
+0000000c <[^>]*> ecfe0001 	auipc	a3,0x1
+			c: R_MIPS_PCHI16	bar
+00000010 <[^>]*> 24847ffc 	addiu	a0,a0,32764
+			10: R_MIPS_PCLO16	bar
+00000014 <[^>]*> 24a50000 	addiu	a1,a1,0
+			14: R_MIPS_LO16	baz
+00000018 <[^>]*> 24c68008 	addiu	a2,a2,-32760
+			18: R_MIPS_PCLO16	bar
+0000001c <[^>]*> 24e70000 	addiu	a3,a3,0
+			1c: R_MIPS_PCLO16	bar
+00000020 <[^>]*> ec9e0001 	auipc	a0,0x1
+			20: R_MIPS_PCHI16	bar
+00000024 <[^>]*> 3c050000 	lui	a1,0x0
+			24: R_MIPS_HI16	baz
+00000028 <[^>]*> ecde0001 	auipc	a2,0x1
+			28: R_MIPS_PCHI16	bar
+0000002c <[^>]*> ecfe0001 	auipc	a3,0x1
+			2c: R_MIPS_PCHI16	bar
+	\.\.\.
+00030030 <[^>]*> 2484801c 	addiu	a0,a0,-32740
+			30030: R_MIPS_PCLO16	bar
+00030034 <[^>]*> 24a50000 	addiu	a1,a1,0
+			30034: R_MIPS_LO16	baz
+00030038 <[^>]*> 24c68028 	addiu	a2,a2,-32728
+			30038: R_MIPS_PCLO16	bar
+0003003c <[^>]*> 24e70020 	addiu	a3,a3,32
+			3003c: R_MIPS_PCLO16	bar
+00030040 <[^>]*> 2410802c 	li	s0,-32724
+			30040: R_MIPS_PCLO16	bar
+00030044 <[^>]*> 24110000 	li	s1,0
+			30044: R_MIPS_LO16	baz
+00030048 <[^>]*> 24128038 	li	s2,-32712
+			30048: R_MIPS_PCLO16	bar
+0003004c <[^>]*> 24130030 	li	s3,48
+			3004c: R_MIPS_PCLO16	bar
+00030050 <[^>]*> ec9e0004 	auipc	a0,0x4
+			30050: R_MIPS_PCHI16	bar
+00030054 <[^>]*> 3c050000 	lui	a1,0x0
+			30054: R_MIPS_HI16	baz
+00030058 <[^>]*> ecde0004 	auipc	a2,0x4
+			30058: R_MIPS_PCHI16	bar
+0003005c <[^>]*> ecfe0004 	auipc	a3,0x4
+			3005c: R_MIPS_PCHI16	bar
+00030060 <[^>]*> 00902021 	addu	a0,a0,s0
+00030064 <[^>]*> 00b12821 	addu	a1,a1,s1
+00030068 <[^>]*> 00d23021 	addu	a2,a2,s2
+0003006c <[^>]*> 00f33821 	addu	a3,a3,s3
+00030070 <[^>]*> d81f0000 	jrc	ra
+	\.\.\.
diff --git a/gas/testsuite/gas/mips/pcrel-hilo-match.d b/gas/testsuite/gas/mips/pcrel-hilo-match.d
new file mode 100644
index 00000000000..5ff66c255c4
--- /dev/null
+++ b/gas/testsuite/gas/mips/pcrel-hilo-match.d
@@ -0,0 +1,28 @@
+#objdump: -r
+#as: -mabi=32 -mno-pdr
+#name: MIPS pcrel-hilo-match
+
+.*: +file format .*mips.*
+
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET +TYPE +VALUE
+00000010 R_MIPS_PCHI16     var4
+00000018 R_MIPS_PCLO16     var4
+00000008 R_MIPS_PCHI16     __var1
+00000020 R_MIPS_PCLO16     __var1
+0000001c R_MIPS_PCHI16     .sbss
+0000002c R_MIPS_PCLO16     .sbss
+00000028 R_MIPS_PCHI16     __var3
+00000034 R_MIPS_PCLO16     __var3
+00000030 R_MIPS_PCHI16     func4
+00000038 R_MIPS_PCLO16     func4
+00000024 R_MIPS_PCHI16     hilo_match
+0000003c R_MIPS_PCLO16     hilo_match
+00000040 R_MIPS_PCHI16     .bss
+00000048 R_MIPS_PCLO16     .bss
+00000044 R_MIPS_PCHI16     .bss
+0000004c R_MIPS_PCLO16     .bss
+00000050 R_MIPS_PCHI16     hilo_match
+00000058 R_MIPS_PCLO16     hilo_match
+00000054 R_MIPS_PCHI16     func3
+0000005c R_MIPS_PCLO16     func3
diff --git a/gas/testsuite/gas/mips/pcrel-hilo-match.s b/gas/testsuite/gas/mips/pcrel-hilo-match.s
new file mode 100644
index 00000000000..dfc8a80680b
--- /dev/null
+++ b/gas/testsuite/gas/mips/pcrel-hilo-match.s
@@ -0,0 +1,81 @@
+	.module	mips64r6
+
+	.align	2
+	.globl	_pinit
+	.ent	_pinit
+_pinit:
+	lw	$3,8($23)
+	li	$5,1
+10:	auipc	$2,%pcrel_hi(__var1)
+	ori	$3,$3,0x1
+11:	auipc	$4,%pcrel_hi(var4)
+	sw	$3,8($23)
+12:	addiu	$4,$4,%pcrel_lo(var4 + (12b - 11b))
+13:	auipc	$3,%pcrel_hi(var5)
+14:	sw	$5,%pcrel_lo(__var1 + (14b - 10b))($2)
+15:	auipc	$19,%pcrel_hi(hilo_match)
+16:	auipc	$2,%pcrel_hi(__var3)
+17:	sw	$5,%pcrel_lo(var5 + (17b - 13b))($3)
+18:	auipc	$25,%pcrel_hi(func4)
+19:	sw	$5,%pcrel_lo(__var3 + (19b - 16b))($2)
+20:	jialc	$25,%pcrel_lo(func4 + (20b - 18b))
+21:	lw	$17,%pcrel_lo(hilo_match + (21b - 15b))($19)
+22:	auipc	$2,%pcrel_hi(var6)
+23:	auipc	$3,%pcrel_hi(var6+704)
+24:	addiu	$16,$2,%pcrel_lo(var6 + (24b - 22b))
+25:	addiu	$18,$3,%pcrel_lo(var6+704 + (25b - 23b))
+26:	auipc	$19,%pcrel_hi(hilo_match)
+28:	auipc	$25,%pcrel_hi(func3)
+27:	sw	$2,%pcrel_lo(hilo_match + (27b - 26b))($19)
+29:	jialc	$25,%pcrel_lo(func3 + (29b - 28b))
+	.end	_pinit
+	.size	_pinit, .-_pinit
+
+	.align	2
+	.weak	__var3
+	.section	.sbss,"aw",@nobits
+	.align	2
+	.type	__var3, @object
+	.size	__var3, 4
+__var3:
+	.space	4
+	.weak	__var1
+	.align	2
+	.type	__var1, @object
+	.size	__var1, 4
+__var1:
+	.space	4
+	.data
+	.align	2
+	.weak	__hilo_match
+	.align	2
+	.type	__hilo_match, @object
+	.size	__hilo_match, 4
+__hilo_match:
+	.space	4
+	.data
+	.align	2
+	.align	2
+	.type	var2, @object
+	.size	var2, 32
+var2:
+	.word	0
+	.word	-1
+	.word	0
+	.byte	0
+	.byte	0
+	.byte	0
+	.byte	0
+	.word	0
+	.word	0
+	.half	0
+	.space	6
+	.align	2
+	.rdata
+	.align	2
+	.space	8
+	.local	var5
+	.comm	var5,4,4
+	.align	2
+	.local	var6
+	.comm	var6,704,4
diff --git a/gas/testsuite/gas/mips/pcrel-hilo-n32.d b/gas/testsuite/gas/mips/pcrel-hilo-n32.d
new file mode 100644
index 00000000000..aed204a5517
--- /dev/null
+++ b/gas/testsuite/gas/mips/pcrel-hilo-n32.d
@@ -0,0 +1,31 @@
+#readelf: -r
+#name: MIPSr6 PCHI16/PCLO16 relocations (n32)
+#as: -mabi=n32 -march=mips64r6 -mno-pdr
+#source: pcrel-hilo.s
+
+Relocation section '\.rela\.text' at offset .+ contains 24 entries:
+ Offset     Info    Type            Sym\.Value  Sym\. Name \+ Addend
+00000000  00000840 R_MIPS_PCHI16     00000000   bar \+ 7fec
+00000004  00000905 R_MIPS_HI16       00000000   baz \+ 0
+00000008  00000840 R_MIPS_PCHI16     00000000   bar \+ 7ff8
+0000000c  00000840 R_MIPS_PCHI16     00000000   bar \+ fff0
+00000010  00000841 R_MIPS_PCLO16     00000000   bar \+ 7ffc
+00000014  00000906 R_MIPS_LO16       00000000   baz \+ 0
+00000018  00000841 R_MIPS_PCLO16     00000000   bar \+ 8008
+0000001c  00000841 R_MIPS_PCLO16     00000000   bar \+ 10000
+00000020  00000840 R_MIPS_PCHI16     00000000   bar \+ 800c
+00000024  00000905 R_MIPS_HI16       00000000   baz \+ 0
+00000028  00000840 R_MIPS_PCHI16     00000000   bar \+ 8018
+0000002c  00000840 R_MIPS_PCHI16     00000000   bar \+ 10010
+00030030  00000841 R_MIPS_PCLO16     00000000   bar \+ 3801c
+00030034  00000906 R_MIPS_LO16       00000000   baz \+ 0
+00030038  00000841 R_MIPS_PCLO16     00000000   bar \+ 38028
+0003003c  00000841 R_MIPS_PCLO16     00000000   bar \+ 40020
+00030040  00000841 R_MIPS_PCLO16     00000000   bar \+ 3802c
+00030044  00000906 R_MIPS_LO16       00000000   baz \+ 0
+00030048  00000841 R_MIPS_PCLO16     00000000   bar \+ 38038
+0003004c  00000841 R_MIPS_PCLO16     00000000   bar \+ 40030
+00030050  00000840 R_MIPS_PCHI16     00000000   bar \+ 3803c
+00030054  00000905 R_MIPS_HI16       00000000   baz \+ 0
+00030058  00000840 R_MIPS_PCHI16     00000000   bar \+ 38048
+0003005c  00000840 R_MIPS_PCHI16     00000000   bar \+ 40040
diff --git a/gas/testsuite/gas/mips/pcrel-hilo.d b/gas/testsuite/gas/mips/pcrel-hilo.d
new file mode 100644
index 00000000000..a96e4f2375e
--- /dev/null
+++ b/gas/testsuite/gas/mips/pcrel-hilo.d
@@ -0,0 +1,30 @@
+#readelf: -r
+#name: MIPSr6 PCHI16/PCLO16 relocations (o32)
+#as: -mabi=32 -mno-pdr
+
+Relocation section '\.rel\.text' at offset .+ contains 24 entries:
+ Offset     Info    Type            Sym\.Value  Sym\. Name
+00030050  00000840 R_MIPS_PCHI16     00000000   bar
+00000000  00000840 R_MIPS_PCHI16     00000000   bar
+00000010  00000841 R_MIPS_PCLO16     00000000   bar
+00000004  00000905 R_MIPS_HI16       00000000   baz
+00000014  00000906 R_MIPS_LO16       00000000   baz
+00030058  00000840 R_MIPS_PCHI16     00000000   bar
+00000028  00000840 R_MIPS_PCHI16     00000000   bar
+00000008  00000840 R_MIPS_PCHI16     00000000   bar
+00000018  00000841 R_MIPS_PCLO16     00000000   bar
+0003005c  00000840 R_MIPS_PCHI16     00000000   bar
+0000002c  00000840 R_MIPS_PCHI16     00000000   bar
+0000000c  00000840 R_MIPS_PCHI16     00000000   bar
+0000001c  00000841 R_MIPS_PCLO16     00000000   bar
+00000020  00000840 R_MIPS_PCHI16     00000000   bar
+00030030  00000841 R_MIPS_PCLO16     00000000   bar
+00000024  00000905 R_MIPS_HI16       00000000   baz
+00030034  00000906 R_MIPS_LO16       00000000   baz
+00030038  00000841 R_MIPS_PCLO16     00000000   bar
+0003003c  00000841 R_MIPS_PCLO16     00000000   bar
+00030040  00000841 R_MIPS_PCLO16     00000000   bar
+00030054  00000905 R_MIPS_HI16       00000000   baz
+00030044  00000906 R_MIPS_LO16       00000000   baz
+00030048  00000841 R_MIPS_PCLO16     00000000   bar
+0003004c  00000841 R_MIPS_PCLO16     00000000   bar
diff --git a/gas/testsuite/gas/mips/pcrel-hilo.s b/gas/testsuite/gas/mips/pcrel-hilo.s
new file mode 100644
index 00000000000..4a8278f1b24
--- /dev/null
+++ b/gas/testsuite/gas/mips/pcrel-hilo.s
@@ -0,0 +1,48 @@
+	.module	mips64r6
+
+	.text
+	.align	16
+	.globl	foo
+	.ent	foo
+foo:
+0:	auipc	$4, %pcrel_hi(bar + 0x7fec)
+1:	lui	$5, %hi(baz)
+2:	auipc	$6, %pcrel_hi(bar + 0x7ff8)
+3:	auipc	$7, %pcrel_hi(bar + 0xfff0)
+4:	addiu	$4, %pcrel_lo(bar + 0x7fec + (4b - 0b))
+5:	addiu	$5, %lo(baz)
+6:	addiu	$6, %pcrel_lo(bar + 0x7ff8 + (6b - 2b))
+7:	addiu	$7, %pcrel_lo(bar + 0xfff0 + (7b - 3b))
+10:	auipc	$4, %pcrel_hi(bar + 0x800c)
+11:	lui	$5, %hi(baz)
+12:	auipc	$6, %pcrel_hi(bar + 0x8018)
+13:	auipc	$7, %pcrel_hi(bar + 0x10010)
+	.rept	49152
+	nop
+	.endr
+14:	addiu	$4, %pcrel_lo(bar + 0x800c + (14b - 10b))
+15:	addiu	$5, %lo(baz)
+16:	addiu	$6, %pcrel_lo(bar + 0x8018 + (16b - 12b))
+17:	addiu	$7, %pcrel_lo(bar + 0x10010 + (17b - 13b))
+24:	addiu	$16, $0, %pcrel_lo(bar + 0x3803c + (24b - 20f))
+25:	addiu	$17, $0, %lo(baz)
+26:	addiu	$18, $0, %pcrel_lo(bar + 0x38048 + (26b - 22f))
+27:	addiu	$19, $0, %pcrel_lo(bar + 0x40040 + (27b - 23f))
+20:	auipc	$4, %pcrel_hi(bar + 0x3803c)
+21:	lui	$5, %hi(baz)
+22:	auipc	$6, %pcrel_hi(bar + 0x38048)
+23:	auipc	$7, %pcrel_hi(bar + 0x40040)
+	addu	$4, $4, $16
+	addu	$5, $5, $17
+	addu	$6, $6, $18
+	addu	$7, $7, $19
+	jrc	$31
+	.end	foo
+
+	.data
+	.align	16
+	.globl	bar
+	.type	bar, @object
+bar:
+	.space	0x18000
+	.size	bar, . - bar
diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp
index e95f1e739cd..6fc960dfc10 100644
--- a/ld/testsuite/ld-mips-elf/mips-elf.exp
+++ b/ld/testsuite/ld-mips-elf/mips-elf.exp
@@ -855,6 +855,17 @@ run_dump_test_n32 "micromips-hilo-srec" \
 run_dump_test_n64 "micromips-hilo-srec-n64" \
 	[list noarch \
 	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_o32 "pcrel-hilo"
+run_dump_test_n32 "pcrel-hilo" [list [list name (n32)]]
+run_dump_test_n64 "pcrel-hilo" [list [list name (n64)]]
+run_dump_test_o32 "pcrel-hilo-srec" \
+	[list [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_n32 "pcrel-hilo-srec" \
+	[list [list name (n32)] \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_n64 "pcrel-hilo-srec" \
+	[list [list name (n64)] \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
 
 if { $linux_gnu } {
     run_dump_test_n32 "textrel-1"
diff --git a/ld/testsuite/ld-mips-elf/pcrel-hilo-srec.d b/ld/testsuite/ld-mips-elf/pcrel-hilo-srec.d
new file mode 100644
index 00000000000..e9b09567f4a
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/pcrel-hilo-srec.d
@@ -0,0 +1,6 @@
+#name: MIPSr6 PCHI16/PCLO16 relocations srec
+#as: -mno-pdr
+#ld: -e 0 --defsym=baz=0xfedcba98 -T pcrel-hilo.ld --oformat=srec
+#objdump: -m mips:isa64r6 -D -j .sec1
+#source: ../../../gas/testsuite/gas/mips/pcrel-hilo.s
+#dump: pcrel-hilo.d
diff --git a/ld/testsuite/ld-mips-elf/pcrel-hilo.d b/ld/testsuite/ld-mips-elf/pcrel-hilo.d
new file mode 100644
index 00000000000..ae5d0522229
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/pcrel-hilo.d
@@ -0,0 +1,42 @@
+#name: MIPSr6 PCHI16/PCLO16 relocations
+#as: -mno-pdr
+#ld: -e 0 --defsym=baz=0xfedcba98 -T pcrel-hilo.ld
+#objdump: -m mips:isa64r6 -d
+#source: ../../../gas/testsuite/gas/mips/pcrel-hilo.s
+
+.*: +file format (?:.*mips.*|srec)
+
+Disassembly of section \.(?:text|sec1):
+
+0*10000000 <[^>]*>:
+ *10000000:	ec9e2456 	auipc	a0,0x2456
+ *10000004:	3c05fedd 	lui	a1,0xfedd
+ *10000008:	ecde2456 	auipc	a2,0x2456
+ *1000000c:	ecfe2457 	auipc	a3,0x2457
+ *10000010:	24847fec 	addiu	a0,a0,32748
+ *10000014:	24a5ba98 	addiu	a1,a1,-17768
+ *10000018:	24c67ff0 	addiu	a2,a2,32752
+ *1000001c:	24e7ffe4 	addiu	a3,a3,-28
+ *10000020:	ec9e2456 	auipc	a0,0x2456
+ *10000024:	3c05fedd 	lui	a1,0xfedd
+ *10000028:	ecde2456 	auipc	a2,0x2456
+ *1000002c:	ecfe2457 	auipc	a3,0x2457
+	\.\.\.
+ *10030030:	24847fec 	addiu	a0,a0,32748
+ *10030034:	24a5ba98 	addiu	a1,a1,-17768
+ *10030038:	24c67ff0 	addiu	a2,a2,32752
+ *1003003c:	24e7ffe4 	addiu	a3,a3,-28
+ *10030040:	24107fec 	li	s0,32748
+ *10030044:	2411ba98 	li	s1,-17768
+ *10030048:	24127ff0 	li	s2,32752
+ *1003004c:	2413ffe4 	li	s3,-28
+ *10030050:	ec9e2456 	auipc	a0,0x2456
+ *10030054:	3c05fedd 	lui	a1,0xfedd
+ *10030058:	ecde2456 	auipc	a2,0x2456
+ *1003005c:	ecfe2457 	auipc	a3,0x2457
+ *10030060:	00902021 	addu	a0,a0,s0
+ *10030064:	00b12821 	addu	a1,a1,s1
+ *10030068:	00d23021 	addu	a2,a2,s2
+ *1003006c:	00f33821 	addu	a3,a3,s3
+ *10030070:	d81f0000 	jrc	ra
+	\.\.\.
diff --git a/ld/testsuite/ld-mips-elf/pcrel-hilo.ld b/ld/testsuite/ld-mips-elf/pcrel-hilo.ld
new file mode 100644
index 00000000000..77d361d9317
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/pcrel-hilo.ld
@@ -0,0 +1,14 @@
+MEMORY
+{
+  text (rx) : ORIGIN = 0x10000000, LENGTH = 0x40000
+  data (w) : ORIGIN = 0x34560000, LENGTH = 0x40000
+}
+SECTIONS
+{
+  .text : { *(.text) } >text
+  .data : { *(.data) } >data
+  .symtab : { *(.symtab) }
+  .strtab : { *(.strtab) }
+  .shstrtab : { *(.shstrtab) }
+  /DISCARD/ : { *(*) }
+}


More information about the Binutils-cvs mailing list