R_MIPS_16 has size=2 in reloc howto. This would seem to disagree with the mips ABI which says the field is 16 bits. Using the wrong size leads to an asan error when running the ld testsuite for mipstx39-elf Executing on host: sh -c {./ld-new -z norelro -L/home/alan/src/binutils-gdb/ld/testsuite/ld-mips-elf -Tdata 0x10000 -e 0 -o tmpdir/dump tmpdir/reloc-localoverflow.o 2>&1} /dev/null dump.tmp (timeout = 300) spawn [open ...] ================================================================= ==12034==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100001c902 at pc 0x561697b97d27 bp 0x7fffe8f6a220 sp 0x7fffe8f6a210 READ of size 1 at 0x62100001c902 thread T0 #0 0x561697b97d26 in bfd_getb32 /home/alan/src/binutils-gdb/bfd/libbfd.c:631 #1 0x561697c12b46 in mips_elf_read_rel_addend /home/alan/src/binutils-gdb/bfd/elfxx-mips.c:8169 Correcting the size won't affect little-endian mips targets, but it would affect anyone who is currently using R_MIPS_16 on a big-endian target since defining the reloc as it is means on big-endian the field is at offset+2. cat > short.s <<\EOF .data .short forword .short ext .short 0 forword: EOF gas/as-new -o short.o short.s ld/ld-new -o short short.o --defsym ext=123 -Tdata=0x1000 binutils/objdump -s short short: file format elf32-bigmips Contents of section .data: 1000 00001000 007b .....{
Huh, no, on reading the ABI a little more carefully I see the half16 field is in fact in a 32-bit word. So the reloc howto is OK but R_MIPS_16 can't really be used to relocate data on big-endian targets.
See also pr3243, which is probably the same bug but somewhat confused as to where the "R_MIPS_16 _memory_descriptors_size" reloc was applied.
The master branch has been updated by Alan Modra <amodra@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d712f2768ac5e71027657d85b921fc0e85d94bcd commit d712f2768ac5e71027657d85b921fc0e85d94bcd Author: Alan Modra <amodra@gmail.com> Date: Sun Jun 12 16:29:05 2022 +0930 BFD_RELOC_MIPS_16 MIPS should not be using BFD_RELOC_16 for its R_MIPS_16 relocation, since R_MIPS_16 specifies a 16-bit field in a 32-bit word. BFD_RELOC_16, emitted by generic code to handle fixups on 16-bit data directives, expects fixups to operate on the whole of a 16-bit word. This patch corrects the problem by using BFD_RELOC_MIPS_16, a new bfd reloc that is used to generate R_MIPS_16. BFD_RELOC_16 is handled in md_apply_fix for cases where the fixup can be applied at assembly time. Like BFD_RELOC_8, BFD_RELOC_16 now has no corresponding object file relocation, and thus .half, .hword, .short and .dc.w must be resolved at assembly time. BFD_RELOC_MIPS_REL16 is removed by this patch since it isn't used. PR 3243 PR 26542 * reloc.c (BFD_RELOC_MIPS_16): Rename from BFD_RELOC_MIPS_REL16. * elf32-mips.c (mips_reloc_map): Map BFD_RELOC_MIPS_16 to R_MIPS_16. * elf64-mips.c (mips_reloc_map): Likewise, delete BFD_RELOC_MIPS_REL16. * elfn32-mips.c (mips_reloc_map): Likewise. * libbfd.h: Regenerate. * bfd-in2.h: Regenerate. gas/ * config/tc-mips.c (append_insn): Handle BFD_RELOC_MIPS_16. (macro_build): Likewise. (mips_percent_op <%half>): Generate BFD_RELOC_MIPS_16. (md_apply_fix): Handle BFD_RELOC_16 and BFD_RELOC_MIPS_16 when fx_done. ld/ * testsuite/ld-mips-elf/reloc-local-overflow.d, * testsuite/ld-mips-elf/reloc-local-overflow.s: Rewrite.
Fixed.