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.
This commit is contained in:
Jan Beulich
2022-03-23 08:43:13 +01:00
parent b3446f947b
commit 36e2d65d26
7 changed files with 36 additions and 9 deletions

View File

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

View File

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

View File

@ -0,0 +1,4 @@
.*: \.text\+2:.*addend.*too large.*
.*: \.text\+b:.*addend.*too large.*
.*: Assembler messages:
.*: Fatal error: .*

View File

@ -0,0 +1,7 @@
.text
_start:
movabs $x+0x123456789, %rax
movabs x+0x123456789, %eax
.data
.quad x+0x123456789

View File

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

View File

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

View File

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