From 36e2d65d26622e83fa4c3af8289f6728376b9e89 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 23 Mar 2022 08:43:13 +0100 Subject: [PATCH] ELF32: don't silently truncate relocation addends At least x86-64's x32 sub-mode and RISC-V's 32-bit mode calculate addends as 64-bit values, but store them in signed 32-bit fields when generating the file without encountering any earlier error. When the relocated field is a 64-bit one, the value resulting after processing the relocation record when linking (or the latest when loading) may thus be wrong due to the truncation. With the code change in place, one x32 testcase actually triggers the new diagnostic. That one case of too large a (negative) addend is being adjusted alongside the addition of a new testcase to actually trigger the new error. (Note that due to internal BFD behavior the relocation in .data doesn't get processed anymore after the errors in .text.) Note that in principle it is possible to express 64-bit relocations in ELF32, but this would require .rel relocations, i.e. with the addend stored in the 64-bit field being relocated. But I guess it would be a lot of effort for little gain to actually support this. --- bfd/elfcode.h | 13 +++++++++++++ gas/testsuite/gas/i386/ilp32/ilp32.exp | 1 + gas/testsuite/gas/i386/ilp32/reloc-2.l | 4 ++++ gas/testsuite/gas/i386/ilp32/reloc-2.s | 7 +++++++ gas/testsuite/gas/i386/ilp32/reloc64.d | 3 ++- gas/testsuite/gas/i386/ilp32/reloc64.l | 14 +++++++------- gas/testsuite/gas/i386/ilp32/reloc64.s | 3 ++- 7 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 gas/testsuite/gas/i386/ilp32/reloc-2.l create mode 100644 gas/testsuite/gas/i386/ilp32/reloc-2.s diff --git a/bfd/elfcode.h b/bfd/elfcode.h index c3ab0536321..4d4cb68164a 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -997,6 +997,19 @@ elf_write_relocs (bfd *abfd, asection *sec, void *data) return; } +#if defined(BFD64) && ARCH_SIZE == 32 + if (rela_hdr->sh_type == SHT_RELA + && ptr->howto->bitsize > 32 + && ptr->addend - INT32_MIN > UINT32_MAX) + { + _bfd_error_handler (_("%pB: %pA+%"BFD_VMA_FMT"x: " + "relocation addend %"BFD_VMA_FMT"x too large"), + abfd, sec, ptr->address, ptr->addend); + *failedp = true; + bfd_set_error (bfd_error_bad_value); + } +#endif + src_rela.r_offset = ptr->address + addr_offset; src_rela.r_info = ELF_R_INFO (n, ptr->howto->type); src_rela.r_addend = ptr->addend; diff --git a/gas/testsuite/gas/i386/ilp32/ilp32.exp b/gas/testsuite/gas/i386/ilp32/ilp32.exp index d1bb96cc1a1..c2ff5e3e919 100644 --- a/gas/testsuite/gas/i386/ilp32/ilp32.exp +++ b/gas/testsuite/gas/i386/ilp32/ilp32.exp @@ -38,6 +38,7 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_x32_check] & } run_list_test "reloc64" "--defsym _bad_=1" + run_list_test "reloc-2" set ASFLAGS "$old_ASFLAGS" } diff --git a/gas/testsuite/gas/i386/ilp32/reloc-2.l b/gas/testsuite/gas/i386/ilp32/reloc-2.l new file mode 100644 index 00000000000..9e89145daef --- /dev/null +++ b/gas/testsuite/gas/i386/ilp32/reloc-2.l @@ -0,0 +1,4 @@ +.*: \.text\+2:.*addend.*too large.* +.*: \.text\+b:.*addend.*too large.* +.*: Assembler messages: +.*: Fatal error: .* diff --git a/gas/testsuite/gas/i386/ilp32/reloc-2.s b/gas/testsuite/gas/i386/ilp32/reloc-2.s new file mode 100644 index 00000000000..f9035a8ef2b --- /dev/null +++ b/gas/testsuite/gas/i386/ilp32/reloc-2.s @@ -0,0 +1,7 @@ + .text +_start: + movabs $x+0x123456789, %rax + movabs x+0x123456789, %eax + + .data + .quad x+0x123456789 diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.d b/gas/testsuite/gas/i386/ilp32/reloc64.d index 78ca3fd9e38..e2c461f24e8 100644 --- a/gas/testsuite/gas/i386/ilp32/reloc64.d +++ b/gas/testsuite/gas/i386/ilp32/reloc64.d @@ -61,7 +61,8 @@ Disassembly of section \.text: .*[ ]+R_X86_64_TPOFF32[ ]+xtrn .*[ ]+R_X86_64_TPOFF32[ ]+xtrn .*[ ]+R_X86_64_TPOFF32[ ]+xtrn -.*[ ]+R_X86_64_64[ ]+xtrn\+0x1 +.*[ ]+R_X86_64_64[ ]+xtrn\+0x7fffffff +.*[ ]+R_X86_64_64[ ]+xtrn\-0x80000000 Disassembly of section \.data: #... .*[ ]+R_X86_64_32[ ]+xtrn diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.l b/gas/testsuite/gas/i386/ilp32/reloc64.l index 9643e677782..aad4c583c7b 100644 --- a/gas/testsuite/gas/i386/ilp32/reloc64.l +++ b/gas/testsuite/gas/i386/ilp32/reloc64.l @@ -51,17 +51,17 @@ .*:175: Error: .* .*:176: Error: .* .*:177: Error: .* -.*:189: Error: .* -.*:192: Error: .* too large for field of 4 bytes at .* +.*:190: Error: .* .*:193: Error: .* too large for field of 4 bytes at .* .*:194: Error: .* too large for field of 4 bytes at .* .*:195: Error: .* too large for field of 4 bytes at .* -.*:196: Error: .* too large for field of 2 bytes at .* -.*:196: Error: .* too large for field of 1 byte at .* +.*:196: Error: .* too large for field of 4 bytes at .* .*:197: Error: .* too large for field of 2 bytes at .* .*:197: Error: .* too large for field of 1 byte at .* -.*:200: Error: .* too large for field of 4 bytes at .* -.*:201: Error: .* too large for field of 2 bytes at .* +.*:198: Error: .* too large for field of 2 bytes at .* +.*:198: Error: .* too large for field of 1 byte at .* +.*:201: Error: .* too large for field of 4 bytes at .* .*:202: Error: .* too large for field of 2 bytes at .* -.*:203: Error: .* too large for field of 1 byte at .* +.*:203: Error: .* too large for field of 2 bytes at .* .*:204: Error: .* too large for field of 1 byte at .* +.*:205: Error: .* too large for field of 1 byte at .* diff --git a/gas/testsuite/gas/i386/ilp32/reloc64.s b/gas/testsuite/gas/i386/ilp32/reloc64.s index 9f5990a300a..db2d2acdf5d 100644 --- a/gas/testsuite/gas/i386/ilp32/reloc64.s +++ b/gas/testsuite/gas/i386/ilp32/reloc64.s @@ -178,7 +178,8 @@ bad .byte xtrn@tpoff .text mov xtrn@tpoff (%rbx), %eax - movabsq $xtrn - 4294967295, %rbp + movabsq $xtrn + 0x7fffffff, %rbx + movabsq $xtrn - 0x80000000, %rbp .data .quad xtrn -- 2.30.2