For a label difference A-B in assembly, if A and B are separated by a
linker-relaxable instruction, we should emit a pair of ADD/SUB
relocations (e.g. R_RISCV_ADD32/R_RISCV_SUB32,
R_RISCV_ADD64/R_RISCV_SUB64).
However, the decision is made upfront at parsing time with inadequate
heuristics (requiresFixup). As a result, LLVM integrated assembler
incorrectly suppresses R_RISCV_ADD32/R_RISCV_SUB32 for the following
code:
// Simplified from a workaround https://android-review.googlesource.com/c/platform/art/+/2619609 // Both end and begin are not defined yet. We decide ADD/SUB relocations upfront and don't know they will be needed. .4byte end-begin begin: call foo end:
To fix the bug, make two primary changes:
- Delete requiresFixups and the overridden emitValueImpl (from D103539). This deletion requires accurate evaluateAsAbolute (D153097).
- In MCAssembler::evaluateFixup, call handleAddSubRelocations to emit ADD/SUB relocations.
However, there is a remaining issue in
MCExpr.cpp:AttemptToFoldSymbolOffsetDifference. With MCAsmLayout, we may
incorrectly fold A-B even when A and B are separated by a
linker-relaxable instruction. This deficiency is acknowledged (see
D153097), but was previously bypassed by eagerly emitting ADD/SUB using
requiresFixups. To address this, we partially reintroduce canFold (from
D61584, removed by D103539).
Some expressions (e.g. .size and .fill) need to take the MCAsmLayout
code path in AttemptToFoldSymbolOffsetDifference, avoiding relocations
(weird, but matching GNU assembler and needed to match user
expectation). Switch to evaluateKnownAbsolute to leverage the InSet
condition.
As a bonus, this change allows for the removal of some relocations for
the FDE address_range field in the .eh_frame section.
riscv64-64b-pcrel.s contains the main test.
Add a linker relaxable instruction to dwarf-riscv-relocs.ll to test what
it intends to test.
Merge fixups-relax-diff.ll into fixups-diff.ll.