Open v01dXYZ opened 1 week ago
@llvm/issue-subscribers-lld-coff
Author: None (v01dXYZ)
FYI in binutils/bfd
, the important function that implements the overflow check is bfd/reloc.c _bfd_relocate_contents
. Another interesting file is coff-x86_64.c
, especially the howto_table
array where is defined if the overflow is sign/unsigned/bitfield. I've got to find the exact part of the COFF specs which define that.
For comparison sake, I tried to use link.exe
from MSVC toolchain directly (downloaded by following est31
's tutorial: gist.github.comarchive).
link.exe
simply refuses to link when there is a 32-bit absolute ADDR32
relocation with /largeaddressaware
(which is enabled by default on x86_64
). for /largeaddressaware
cf MS's docsarchive.
When /largeaddressaware:no
, only 32-bit base addresses are supported. Furthermore the 32-bit base address should not set the MSB and some LSBs (base_addr & 0x80_00_ff_ff) != 0
.
I wrote down some test cases in assembly to see if overflows are detected by link.exe
(depending on relocation type, base address, symbol address, etc.) . I tested also the case for symbol+offset
: when the address at relocation is not set to 0
in the object code.
After those experiments, I observed that link.exe
ensures:
1 << 31
(even with /largeaddressaware
). Thus, RIP-relative addressing is always valid. largeaddressaware:no
, image maximum extent (base + size) should be lower than 1 << 31
. Thus, relocation symbol+offset
will not sign-overflow if the offset is valid. symbol+offset
with an invalid offset: both unsigned and signed overflows are not reported. Conclusion: The solution to the problem by Windows is to simply put restrictions on its executable format instead of relying on shared conf b/w code generation (code-model=small
) and linker.
Which path should we take to solve the problem ?
binutils
way: interpret which sign a relocation type is and report overflows.windows
way: only accept a user address space smaller than 2GB. Forbid 32-bit absolute addressing if address space not ensured to never cross the 2GB limit.Tested with two versions of linker.exe
:
@MaskRay I've read your posts about relocation overflow for ELF. Could you advise me on which way is best fitted to current lld
? I prefer to ask before writing some code. I'm surprised this issue was not found earlier because default image base address for x86_64
is already beyond 4GB.
@MaskRay I've read your posts about relocation overflow for ELF. Could you advise me on which way is best fitted to current
lld
? I prefer to ask before writing some code. I'm surprised this issue was not found earlier because default image base address forx86_64
is already beyond 4GB.
It'll be nice to have the errors (https://maskray.me/blog/2023-05-14-relocation-overflow-and-code-models). If the compiler does not generate ELF-like medium/large code model code sequences, it's generally not feasible to entirely rely on the linker to fix all limited relocations. Linkers support certain range extension thunks for function symbols, but it cannot alleviate issues for other symbols.
In this related issue (https://github.com/llvm/llvm-project/issues/106319), some object code has been generated with
code-model=small relocation-model=static
and uses 32-bit absolute relocations. As the 64-bit base address is greater than1 << 32
,ldd
produces wrong relocated addresses.When looking at the code, it seems we narrow/truncate then compute instead of doing the way round. For comparison, ELF uses
checkUInt/checkInt/checkIntUInt
after 64-bit address computations.