This patch fully implements linker relaxation for RISC-V including relaxation for R_RISCV_CALL, R_RISCV_HI20/LO12, R_RISCV_PCREL_HI20/LO12 and handling for R_RISCV_ALIGN. Just for reference/link, there were some previous efforts/discussion to implementation linker relaxation in D77694 and D79105.
As linker relaxation is highly specific to RISC-V at the moment, most of the work are done in the Target::finalizeContents() function and isolated from generic code. For now I'm avoiding trying to come up with a common relaxation framework for multiple targets as their needs may be greatly different.
The relaxation process is split into several passes:
- For each executable input section, search its relocation vector for R_RISCV_RELAX and determine how to relax the previous relocation.
- If the relocation is R_RISCV_CALL (auipc+jalr pair), try to relax to jal or c.jal if the jump target is in range. This assumes that the PC-relative offset can only become smaller during the relaxation process.
- If the relocation is R_RISCV_HI20/LO12 (absolute addressing) and the target symbol can be addressed from __global_pointer$ (defaulted to .sdata+0x800), delete the lui and rewrite the lo part to use gp as source register.
- If the relocation is R_RISCV_PCREL_HI20/LO12, this requires two-pass to relax as PCREL_LO12 links to its PCREL_HI20 for address calculation and they may appear in arbitrary order in an input section. To preserve the look up from PCREL_LO12 the first pass relaxes/deletes`PCREL_LO12` and the second pass handles PCREL_HI20. The implementation is simpler than that in bfd because lld doesn't allow addends in PCREL_LO12 (https://github.com/riscv/riscv-elf-psabi-doc/issues/184), and so both parts can be relaxed independently.
- The range of bytes are deleted after processing relaxation for a whole input section. This requires adjusting section content, symbol addresses/sizes and relocation offsets, which is handled in InputSectionBase::deleteRanges. Compared to other approaches we use a algorithm that is not quadratic by sorting symbols, relocations and bytes to be deleted by offset.
- After relaxation, handle alignment as symbols addresses are now fixed modulo section alignment. This is always enabled regardless of the --relax option as this is required for correctness.
There are still some issues to solve:
- --emit-relocs will be broken on relaxed section as currently it just copies the corresponding .rela section verbatim from input. It needs to be fixed to build relocation entries from the section's relocation vector.
The patch adds two additional RelExpr (R_RISCV_GPREL and R_RELAX_HINT) which unfortunately makes it unable to fit into a 64-bit mask, so it is now changed back to sequential checking. I think it should be somehow split into target-independent (R_ABS, R_PC, ...) exprs and target-dependent (R_RISCV_..., R_MIPS_...) exprs which can overlap in numeric range, but it is probably out of the scope of this patch.