From: Maciej W. Rozycki Date: Sun, 6 Jul 2025 18:22:49 +0000 (+0100) Subject: MIPS/BFD: Fix RELA handling of borrow in the generic linker X-Git-Tag: binutils-2_45~161 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ce08b3bb19b3;p=thirdparty%2Fbinutils-gdb.git 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. --- diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index ace1d4b1e07..530e8d63ddc 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -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); diff --git a/ld/testsuite/ld-mips-elf/micromips-hilo-n64.d b/ld/testsuite/ld-mips-elf/micromips-hilo-n64.d index e093336358b..1243e91a73c 100644 --- a/ld/testsuite/ld-mips-elf/micromips-hilo-n64.d +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/micromips-hilo-srec-n32.d b/ld/testsuite/ld-mips-elf/micromips-hilo-srec-n32.d new file mode 100644 index 00000000000..1ea7daa3036 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/micromips-hilo-srec-n64.d b/ld/testsuite/ld-mips-elf/micromips-hilo-srec-n64.d new file mode 100644 index 00000000000..c25fbe803d4 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/micromips-hilo-srec.d b/ld/testsuite/ld-mips-elf/micromips-hilo-srec.d new file mode 100644 index 00000000000..e6b84592c83 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/micromips-hilo.d b/ld/testsuite/ld-mips-elf/micromips-hilo.d index 050d42c56d5..d518dfb9560 100644 --- a/ld/testsuite/ld-mips-elf/micromips-hilo.d +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp index 576721b3d0c..d0919ea665f 100644 --- a/ld/testsuite/ld-mips-elf/mips-elf.exp +++ b/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" diff --git a/ld/testsuite/ld-mips-elf/mips-hilo-n64.d b/ld/testsuite/ld-mips-elf/mips-hilo-n64.d index ec0c120af72..5a3f9198f64 100644 --- a/ld/testsuite/ld-mips-elf/mips-hilo-n64.d +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips-hilo-srec-n32.d b/ld/testsuite/ld-mips-elf/mips-hilo-srec-n32.d new file mode 100644 index 00000000000..ccd0195bdda --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips-hilo-srec-n64.d b/ld/testsuite/ld-mips-elf/mips-hilo-srec-n64.d new file mode 100644 index 00000000000..b02983e2f30 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips-hilo-srec.d b/ld/testsuite/ld-mips-elf/mips-hilo-srec.d new file mode 100644 index 00000000000..59e5717a9a8 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips-hilo.d b/ld/testsuite/ld-mips-elf/mips-hilo.d index 2d81173f60f..ae19f501c79 100644 --- a/ld/testsuite/ld-mips-elf/mips-hilo.d +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips16-hilo-srec-n32.d b/ld/testsuite/ld-mips-elf/mips16-hilo-srec-n32.d new file mode 100644 index 00000000000..724adcbae99 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips16-hilo-srec.d b/ld/testsuite/ld-mips-elf/mips16-hilo-srec.d new file mode 100644 index 00000000000..9c41d9a3ae9 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips16-hilo.d b/ld/testsuite/ld-mips-elf/mips16-hilo.d index 22eb28022a0..1f01ca23491 100644 --- a/ld/testsuite/ld-mips-elf/mips16-hilo.d +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips16e2-hilo-srec-n32.d b/ld/testsuite/ld-mips-elf/mips16e2-hilo-srec-n32.d new file mode 100644 index 00000000000..0132fa82e17 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips16e2-hilo-srec.d b/ld/testsuite/ld-mips-elf/mips16e2-hilo-srec.d new file mode 100644 index 00000000000..e46708bc432 --- /dev/null +++ b/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 diff --git a/ld/testsuite/ld-mips-elf/mips16e2-hilo.d b/ld/testsuite/ld-mips-elf/mips16e2-hilo.d index 97b56cadd02..eb93873bf6b 100644 --- a/ld/testsuite/ld-mips-elf/mips16e2-hilo.d +++ b/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