R_PPC_ADDR32 and R_PPC64_ADDR64 may be emitted at misaligned r_offset.
This does not conform to the ABIs.
32-bit psABI says:
word32
Specifies a 32-bit bit-field taking up 4 bytes maintaining 4-byte alignment unless otherwise indicated.
ELFv2 ABI says:
doubleword64 specifies a 64-bit field occupying 8 bytes, the alignment of which is 8 bytes unless otherwise specified.
R_PPC_UADDR32 and R_PPC64_UADDR64 belong to the word32 and doubleword64 classes, respectively.
This patch fixes the problem by teaching ELFWriter::writeRelocations to
emit UADDR if an ADDR has a misaligned r_offset. This cannot be done in
the derived MCELFObjectTargetWriter::getRelocType because r_offset is
not known there.
When objects are linked into executable/DSO:
- If sh_addralign >= 8, an R_PPC64_ADDR64 whose r_offset%8!=0 is guaranteed to have a misaligned address.
- Otherwise, it may have an aligned address if the relocated section is combined with other sections, e.g.
.section .data,"aw",@progbits,unique,0; .align 8; .byte 0 .section .data,"aw",@progbits,unique,1; .space 7; .long a
UADDR are rare: they are caused by initialized data at misaligned
addresses (e.g. attribute((packed))). So we don't necessarily
optimize for them.
This change also simplifies the linker design. Since R_PPC64_ADDR64 will
be guaranteed to be aligned, we can safely emit dynamic R_PPC64_RELATIVE
for R_PPC64_ADDR64 to a non-preemptable symbol in a writable location.
(Currently lld ppc{32,64} and ld.bfd ppc32 can emit misaligned
R_PPC{,64}_RELATIVE. This is not a big problem - kernels (verified with Linux
and FreeBSD) trap handlers will fix misaligned accesses).)