Note: I marked this patch as RFC since it implements a rather obscure
ELF feature at a relatively high cost in terms of code complexity.
Therefore, I would like some feedback on whether this approach is
desirable.
Second note: the implemented feature isn't used (afaict) by X86 or
AArch64 so this should in principle be NFC. It is used by RISC-V so this
patch is part of my efforts to bring BOLT support to that platform. The
patch itself doesn't contain any RISC-V-specific code though.
BOLT currently assumes (and asserts) that no two relocations can share
the same offset. Although this is true in most cases, ELF has a feature
called (not sure if this is an official term) composed relocations [1]
where multiple relocations at the same offset are combined to produce a
single value.
For example, to support label subtraction (a - b) on RISC-V, two
relocations are emitted at the same offset:
- R_RISCV_ADD32 a + 0
- R_RISCV_SUB32 b + 0
which, when combined, will produce the value of (a - b).
To support this in BOLT, first, RelocationSetType in BinarySection is
changed to be a multiset in order to allow it to store multiple
relocations at the same offset.
Next, Relocation::emit() is changed to receive an iterator pair of
relocations. In most cases, these will point to a single relocation in
which case its behavior is unaltered by this patch. For composed
relocations, they should point to all relocations at the same offset and
the following happens:
- A new method Relocation::createExpr() is called for every relocation. This method is essentially the same as the original emit() except that it returns the MCExpr without emitting it.
- The MCExprs of relocations i and i+1 are combined using the opcode returned by the new method Relocation::getComposeOpcodeFor().
- After combining all MCExprs, the last one is emitted.
Note that in the current patch, getComposeOpcodeFor() simply calls
llvm_unreachable() since none of the current targets use composed
relocations. This will change once the RISC-V target lands.
Finally, BinarySection::emitAsData() is updated to group relocations by
offset and emit them all at once.
Note that this means composed relocations are only supported in data
sections. Since this is the only place they seem to be used in RISC-V, I
believe it's reasonable to only support them there for now to avoid
further code complexity.
[1]: https://www.sco.com/developers/gabi/latest/ch4.reloc.html