[committed] MIPS/BFD: Fix RELA handling of borrow in the generic linker

Maciej W. Rozycki macro@orcam.me.uk
Sun Jul 6 18:25:13 GMT 2025


Fix an issue with `_bfd_mips_elf_generic_reloc' not taking into account 
any borrow from the lower part in the handling of relocations of the 
HI/LO kind and resulting in incorrect calculations made for RELA targets 
in the generic used for non-ELF output such as S-records.  This doesn't 
trigger for REL targets because they call `_bfd_mips_elf_generic_reloc' 
indirectly from `_bfd_mips_elf_lo16_reloc' so as to obtain a complete 
32-bit addend from relocation pairs and in calculating the addend the 
latter function uses a hack to work around the lack of borrow handling 
in the former function.

The MIPS/ELF linker is unaffected as it uses its own calculations.

Correct the calculation of the relevant partial relocations made in 
`_bfd_mips_elf_generic_reloc' then to take the borrow into account and 
remove the hack from `_bfd_mips_elf_lo16_reloc' as no longer needed.

Add generic linker test cases accordingly expecting the same disassembly 
from srec output produced as from ELF output produced by the MIPS/ELF 
linker.
---
 bfd/elfxx-mips.c                                   |   33 +++++++++++++++++----
 ld/testsuite/ld-mips-elf/micromips-hilo-n64.d      |    4 +-
 ld/testsuite/ld-mips-elf/micromips-hilo-srec-n32.d |    8 +++++
 ld/testsuite/ld-mips-elf/micromips-hilo-srec-n64.d |    8 +++++
 ld/testsuite/ld-mips-elf/micromips-hilo-srec.d     |    8 +++++
 ld/testsuite/ld-mips-elf/micromips-hilo.d          |    4 +-
 ld/testsuite/ld-mips-elf/mips-elf.exp              |   27 +++++++++++++++++
 ld/testsuite/ld-mips-elf/mips-hilo-n64.d           |    4 +-
 ld/testsuite/ld-mips-elf/mips-hilo-srec-n32.d      |    6 +++
 ld/testsuite/ld-mips-elf/mips-hilo-srec-n64.d      |    6 +++
 ld/testsuite/ld-mips-elf/mips-hilo-srec.d          |    6 +++
 ld/testsuite/ld-mips-elf/mips-hilo.d               |    4 +-
 ld/testsuite/ld-mips-elf/mips16-hilo-srec-n32.d    |    7 ++++
 ld/testsuite/ld-mips-elf/mips16-hilo-srec.d        |    7 ++++
 ld/testsuite/ld-mips-elf/mips16-hilo.d             |    4 +-
 ld/testsuite/ld-mips-elf/mips16e2-hilo-srec-n32.d  |    8 +++++
 ld/testsuite/ld-mips-elf/mips16e2-hilo-srec.d      |    8 +++++
 ld/testsuite/ld-mips-elf/mips16e2-hilo.d           |    4 +-
 18 files changed, 138 insertions(+), 18 deletions(-)

binutils-mips-reloc-hipart-borrow.diff
Index: binutils-gdb/bfd/elfxx-mips.c
===================================================================
--- binutils-gdb.orig/bfd/elfxx-mips.c
+++ binutils-gdb/bfd/elfxx-mips.c
@@ -2599,15 +2599,13 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, are
      addend is adjusted for the fact that the low part is sign
      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 (a)
+     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 (b) (symbol + addend + 0x8000) >> 16 to the
+     and we want to apply (symbol + addend + 0x8000) >> 16 to the
      high insn (the +0x8000 adjusting for when the applied low part is
-     negative).  Substituting (a) into (b) and recognising that
-     (hi & 0xffff) is already in the high insn gives a high part
-     addend adjustment of (lo & 0xffff) ^ 0x8000.  */
-  vallo = (bfd_get_32 (abfd, location) & 0xffff) ^ 0x8000;
+     negative).  */
+  vallo = ((bfd_get_32 (abfd, location) & 0xffff) ^ 0x8000) - 0x8000;
   _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, false,
 			       location);
 
@@ -2707,6 +2705,29 @@ _bfd_mips_elf_generic_reloc (bfd *abfd A
       /* Add in the separate addend, if any.  */
       val += reloc_entry->addend;
 
+      /* The high 16 bits of the addend are stored in the high insn, the
+	 low 16 bits in the low insn, but there is a catch:  You can't
+	 just concatenate the high and low parts.  The high part of the
+	 addend is adjusted for the fact that the low part is sign
+	 extended.  For example, an addend of 0x38000 would have 0x0004 in
+	 the high part and 0x8000 (=0xff..f8000) in the low part.
+	 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).  Analogously for the higher parts of a 64-bit addend.  */
+      if (reloc_entry->howto->bitsize == 16
+	  && reloc_entry->howto->rightshift % 16 == 0)
+#ifdef BFD64
+	val += 0x800080008000ULL >> (48 - reloc_entry->howto->rightshift);
+#else
+	{
+	  if (reloc_entry->howto->rightshift <= 16)
+	    val += 0x8000 >> (16 - reloc_entry->howto->rightshift);
+	  else
+	    abort ();
+	}
+#endif
+
       /* Add VAL to the relocation field.  */
       _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
 				     location);
Index: binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo-n64.d
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-mips-elf/micromips-hilo-n64.d
+++ binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo-n64.d
@@ -6,9 +6,9 @@
 #ld: -Tmips-hilo.ld -e 0x500000 -N
 #notarget: mips*el-ps2-elf*
 
-.*:     file format elf.*mips.*
+.*:     file format (:?elf.*mips.*|srec)
 
-Disassembly of section \.text:
+Disassembly of section \.(:?text|sec1):
 
 0*500000 <[^>]*>:
  *500000:	41a1 0000 	lui	at,0x0
Index: binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo-srec-n32.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo-srec-n32.d
@@ -0,0 +1,8 @@
+#name: R_MICROMIPS_HI16 and R_MICROMIPS_LO16 relocs srec n32
+#source: ../../../gas/testsuite/gas/mips/mips-hilo.s
+#source: mips-hilo.s
+#as: -mmicromips -march=mips64r2
+#objdump: -m mips:micromips -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#notarget: mips*el-ps2-elf*
+#dump: micromips-hilo.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo-srec-n64.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo-srec-n64.d
@@ -0,0 +1,8 @@
+#name: R_MICROMIPS_HI16 and R_MICROMIPS_LO16 relocs srec n64
+#source: ../../../gas/testsuite/gas/mips/mips-hilo-n64.s
+#source: mips-hilo.s
+#as: -mmicromips -march=mips64r2
+#objdump: -m mips:micromips -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#notarget: mips*el-ps2-elf*
+#dump: micromips-hilo-n64.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo-srec.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo-srec.d
@@ -0,0 +1,8 @@
+#name: R_MICROMIPS_HI16 and R_MICROMIPS_LO16 relocs srec
+#source: ../../../gas/testsuite/gas/mips/mips-hilo.s
+#source: mips-hilo.s
+#as: -mmicromips -march=mips32r2
+#objdump: -m mips:micromips -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#notarget: mips*el-ps2-elf*
+#dump: micromips-hilo.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo.d
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-mips-elf/micromips-hilo.d
+++ binutils-gdb/ld/testsuite/ld-mips-elf/micromips-hilo.d
@@ -6,9 +6,9 @@
 #ld: -Tmips-hilo.ld -e 0x500000 -N
 #notarget: mips*el-ps2-elf*
 
-.*:     file format elf.*mips.*
+.*:     file format (:?elf.*mips.*|srec)
 
-Disassembly of section \.text:
+Disassembly of section \.(:?text|sec1):
 
 0*500000 <[^>]*>:
  *500000:	41a4 0000 	lui	a0,0x0
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-mips-elf/mips-elf.exp
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips-elf.exp
@@ -816,14 +816,41 @@ run_dump_test "mode-change-error-1"
 
 run_dump_test_o32 "mips16-hilo" noarch
 run_dump_test_n32 "mips16-hilo-n32" noarch
+run_dump_test_o32 "mips16-hilo-srec" \
+	[list noarch \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_n32 "mips16-hilo-srec-n32" \
+	[list noarch \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
 run_dump_test_o32 "mips16e2-hilo" noarch
 run_dump_test_n32 "mips16e2-hilo-n32" noarch
+run_dump_test_o32 "mips16e2-hilo-srec" \
+	[list noarch \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_n32 "mips16e2-hilo-srec-n32" \
+	[list noarch \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
 run_dump_test_o32 "mips-hilo"
 run_dump_test_n32 "mips-hilo-n32"
 run_dump_test_n64 "mips-hilo-n64"
+run_dump_test_o32 "mips-hilo-srec" \
+	[list [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_n32 "mips-hilo-srec-n32" \
+	[list [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_n64 "mips-hilo-srec-n64" \
+	[list [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
 run_dump_test_o32 "micromips-hilo" noarch
 run_dump_test_n32 "micromips-hilo-n32" noarch
 run_dump_test_n64 "micromips-hilo-n64" noarch
+run_dump_test_o32 "micromips-hilo-srec" \
+	[list noarch \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_n32 "micromips-hilo-srec-n32" \
+	[list noarch \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
+run_dump_test_n64 "micromips-hilo-srec-n64" \
+	[list noarch \
+	      [list objdump [expr { [istarget *el-*-*] ? "-EL" : "-EB" }]]]
 
 if { $linux_gnu } {
     run_dump_test_n32 "textrel-1"
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo-n64.d
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-mips-elf/mips-hilo-n64.d
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo-n64.d
@@ -4,9 +4,9 @@
 #objdump: -d
 #ld: -Tmips-hilo.ld -e 0x500000 -N
 
-.*:     file format elf.*mips.*
+.*:     file format (:?elf.*mips.*|srec)
 
-Disassembly of section \.text:
+Disassembly of section \.(:?text|sec1):
 
 0*500000 <[^>]*>:
  *500000:	3c010000 	lui	at,0x0
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo-srec-n32.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo-srec-n32.d
@@ -0,0 +1,6 @@
+#name: R_MIPS_HI16 and R_MIPS_LO16 relocs srec n32
+#source: ../../../gas/testsuite/gas/mips/mips-hilo.s
+#source: mips-hilo.s
+#objdump: -m mips:4000 -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#dump: mips-hilo.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo-srec-n64.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo-srec-n64.d
@@ -0,0 +1,6 @@
+#name: R_MIPS_HI16 and R_MIPS_LO16 relocs srec n64
+#source: ../../../gas/testsuite/gas/mips/mips-hilo-n64.s
+#source: mips-hilo.s
+#objdump: -m mips:4000 -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#dump: mips-hilo-n64.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo-srec.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo-srec.d
@@ -0,0 +1,6 @@
+#name: R_MIPS_HI16 and R_MIPS_LO16 relocs srec
+#source: ../../../gas/testsuite/gas/mips/mips-hilo.s
+#source: mips-hilo.s
+#objdump: -m mips:3000 -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#dump: mips-hilo.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo.d
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-mips-elf/mips-hilo.d
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips-hilo.d
@@ -4,9 +4,9 @@
 #objdump: -d
 #ld: -Tmips-hilo.ld -e 0x500000 -N
 
-.*:     file format elf.*mips.*
+.*:     file format (:?elf.*mips.*|srec)
 
-Disassembly of section \.text:
+Disassembly of section \.(:?text|sec1):
 
 0*500000 <[^>]*>:
  *500000:	3c040000 	lui	a0,0x0
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips16-hilo-srec-n32.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips16-hilo-srec-n32.d
@@ -0,0 +1,7 @@
+#name: R_MIPS16_HI16 and R_MIPS16_LO16 relocs srec n32
+#source: ../../../gas/testsuite/gas/mips/mips16-hilo.s
+#source: mips-hilo.s
+#as: -march=mips3
+#objdump: -mmips:16 -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#dump: mips16-hilo.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips16-hilo-srec.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips16-hilo-srec.d
@@ -0,0 +1,7 @@
+#name: R_MIPS16_HI16 and R_MIPS16_LO16 relocs srec
+#source: ../../../gas/testsuite/gas/mips/mips16-hilo.s
+#source: mips-hilo.s
+#as: -march=mips1
+#objdump: -mmips:16 -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#dump: mips16-hilo.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips16-hilo.d
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-mips-elf/mips16-hilo.d
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips16-hilo.d
@@ -5,9 +5,9 @@
 #objdump: -mmips:16 -dr
 #ld: -Tmips-hilo.ld -e 0x500000 -N
 
-.*:     file format elf.*mips.*
+.*:     file format (:?elf.*mips.*|srec)
 
-Disassembly of section .text:
+Disassembly of section \.(:?text|sec1):
 
 0*500000 <[^>]*>:
  *500000:	6c00      	li	a0,0
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips16e2-hilo-srec-n32.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips16e2-hilo-srec-n32.d
@@ -0,0 +1,8 @@
+#name: MIPS16e2 R_MIPS16_HI16 and R_MIPS16_LO16 relocs srec n32
+#source: ../../../gas/testsuite/gas/mips/mips-hilo.s
+#source: mips-hilo.s
+#as: -mips16 -mmips16e2 -march=mips64r2
+#objdump: -mmips:16 -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#notarget: mips*el-ps2-elf*
+#dump: mips16e2-hilo.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips16e2-hilo-srec.d
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips16e2-hilo-srec.d
@@ -0,0 +1,8 @@
+#name: MIPS16e2 R_MIPS16_HI16 and R_MIPS16_LO16 relocs srec
+#source: ../../../gas/testsuite/gas/mips/mips-hilo.s
+#source: mips-hilo.s
+#as: -mips16 -mmips16e2 -march=mips32r2
+#objdump: -mmips:16 -j .sec1 -D
+#ld: --oformat=srec -Tmips-hilo.ld -e 0x500000 -N
+#notarget: mips*el-ps2-elf*
+#dump: mips16e2-hilo.d
Index: binutils-gdb/ld/testsuite/ld-mips-elf/mips16e2-hilo.d
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-mips-elf/mips16e2-hilo.d
+++ binutils-gdb/ld/testsuite/ld-mips-elf/mips16e2-hilo.d
@@ -6,9 +6,9 @@
 #ld: -Tmips-hilo.ld -e 0x500000 -N
 #notarget: mips*el-ps2-elf*
 
-.*:     file format elf.*mips.*
+.*:     file format (:?elf.*mips.*|srec)
 
-Disassembly of section \.text:
+Disassembly of section \.(:?text|sec1):
 
 0*500000 <[^>]*>:
  *500000:	f000 6c20 	lui	a0,0x0


More information about the Binutils mailing list