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

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.
This commit is contained in:
Maciej W. Rozycki
2025-07-06 19:22:49 +01:00
parent ae236b71ea
commit ce08b3bb19
18 changed files with 138 additions and 18 deletions

View File

@@ -2599,15 +2599,13 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
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 ATTRIBUTE_UNUSED, arelent *reloc_entry,
/* 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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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