return false;
}
+ virtual bool evaluateTargetFixup(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &WasForced) {
+ llvm_unreachable("Need to implement hook if target has custom fixups");
+ }
+
/// Apply the \p Value for given \p Fixup into the provided data fragment, at
/// the offset specified by the fixup and following the fixup kind as
/// appropriate. Errors (such as an out of range fixup value) should be
FKF_IsPCRel = (1 << 0),
/// Should this fixup kind force a 4-byte aligned effective PC value?
- FKF_IsAlignedDownTo32Bits = (1 << 1)
+ FKF_IsAlignedDownTo32Bits = (1 << 1),
+
+ /// Should this fixup be evaluated in a target dependent manner?
+ FKF_IsTarget = (1 << 2)
};
/// A target specific name for the fixup kind. The names will be unique for
}
assert(getBackendPtr() && "Expected assembler backend");
+ bool IsTarget = getBackendPtr()->getFixupKindInfo(Fixup.getKind()).Flags &
+ MCFixupKindInfo::FKF_IsTarget;
+
+ if (IsTarget)
+ return getBackend().evaluateTargetFixup(*this, Layout, Fixup, DF, Target,
+ Value, WasForced);
+
bool IsPCRel = getBackendPtr()->getFixupKindInfo(Fixup.getKind()).Flags &
MCFixupKindInfo::FKF_IsPCRel;
#include "RISCVAsmBackend.h"
#include "RISCVMCExpr.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDirectives.h"
bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCValue &Target) {
- bool ShouldForce = false;
-
switch (Fixup.getTargetKind()) {
default:
break;
case RISCV::fixup_riscv_tls_got_hi20:
case RISCV::fixup_riscv_tls_gd_hi20:
return true;
- case RISCV::fixup_riscv_pcrel_lo12_i:
- case RISCV::fixup_riscv_pcrel_lo12_s:
- // For pcrel_lo12, force a relocation if the target of the corresponding
- // pcrel_hi20 is not in the same fragment.
- const MCFixup *T = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup();
- if (!T) {
- Asm.getContext().reportError(Fixup.getLoc(),
- "could not find corresponding %pcrel_hi");
- return false;
- }
-
- switch (T->getTargetKind()) {
- default:
- llvm_unreachable("Unexpected fixup kind for pcrel_lo12");
- break;
- case RISCV::fixup_riscv_got_hi20:
- case RISCV::fixup_riscv_tls_got_hi20:
- case RISCV::fixup_riscv_tls_gd_hi20:
- ShouldForce = true;
- break;
- case RISCV::fixup_riscv_pcrel_hi20: {
- MCFragment *TFragment = T->getValue()->findAssociatedFragment();
- MCFragment *FixupFragment = Fixup.getValue()->findAssociatedFragment();
- assert(FixupFragment && "We should have a fragment for this fixup");
- ShouldForce =
- !TFragment || TFragment->getParent() != FixupFragment->getParent();
- break;
- }
- }
- break;
}
- return ShouldForce || STI.getFeatureBits()[RISCV::FeatureRelax] ||
- ForceRelocs;
+ return STI.getFeatureBits()[RISCV::FeatureRelax] || ForceRelocs;
}
bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup,
}
}
+bool RISCVAsmBackend::evaluateTargetFixup(
+ const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFixup &Fixup,
+ const MCFragment *DF, const MCValue &Target, uint64_t &Value,
+ bool &WasForced) {
+ const MCFixup *AUIPCFixup;
+ const MCFragment *AUIPCDF;
+ MCValue AUIPCTarget;
+ switch (Fixup.getTargetKind()) {
+ default:
+ llvm_unreachable("Unexpected fixup kind!");
+ case RISCV::fixup_riscv_pcrel_hi20:
+ AUIPCFixup = &Fixup;
+ AUIPCDF = DF;
+ AUIPCTarget = Target;
+ break;
+ case RISCV::fixup_riscv_pcrel_lo12_i:
+ case RISCV::fixup_riscv_pcrel_lo12_s: {
+ AUIPCFixup = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(&AUIPCDF);
+ if (!AUIPCFixup) {
+ Asm.getContext().reportError(Fixup.getLoc(),
+ "could not find corresponding %pcrel_hi");
+ return true;
+ }
+
+ // MCAssembler::evaluateFixup will emit an error for this case when it sees
+ // the %pcrel_hi, so don't duplicate it when also seeing the %pcrel_lo.
+ const MCExpr *AUIPCExpr = AUIPCFixup->getValue();
+ if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, &Layout, AUIPCFixup))
+ return true;
+ break;
+ }
+ }
+
+ if (!AUIPCTarget.getSymA() || AUIPCTarget.getSymB())
+ return false;
+
+ const MCSymbolRefExpr *A = AUIPCTarget.getSymA();
+ const MCSymbol &SA = A->getSymbol();
+ if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined())
+ return false;
+
+ auto *Writer = Asm.getWriterPtr();
+ if (!Writer)
+ return false;
+
+ bool IsResolved = Writer->isSymbolRefDifferenceFullyResolvedImpl(
+ Asm, SA, *AUIPCDF, false, true);
+ if (!IsResolved)
+ return false;
+
+ Value = Layout.getSymbolOffset(SA) + AUIPCTarget.getConstant();
+ Value -= Layout.getFragmentOffset(AUIPCDF) + AUIPCFixup->getOffset();
+
+ if (shouldForceRelocation(Asm, *AUIPCFixup, AUIPCTarget)) {
+ WasForced = true;
+ return false;
+ }
+
+ return true;
+}
+
void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
const MCAsmLayout &Layout,
MCAlignFragment &AF) override;
+ bool evaluateTargetFixup(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &WasForced) override;
+
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
uint64_t Value, bool IsResolved,
{ "fixup_riscv_hi20", 12, 20, 0 },
{ "fixup_riscv_lo12_i", 20, 12, 0 },
{ "fixup_riscv_lo12_s", 0, 32, 0 },
- { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel },
- { "fixup_riscv_pcrel_lo12_i", 20, 12, MCFixupKindInfo::FKF_IsPCRel },
- { "fixup_riscv_pcrel_lo12_s", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_riscv_pcrel_hi20", 12, 20,
+ MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget },
+ { "fixup_riscv_pcrel_lo12_i", 20, 12,
+ MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget },
+ { "fixup_riscv_pcrel_lo12_s", 0, 32,
+ MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget },
{ "fixup_riscv_got_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_riscv_tprel_hi20", 12, 20, 0 },
{ "fixup_riscv_tprel_lo12_i", 20, 12, 0 },
OS << ')';
}
-const MCFixup *RISCVMCExpr::getPCRelHiFixup() const {
+const MCFixup *RISCVMCExpr::getPCRelHiFixup(const MCFragment **DFOut) const {
MCValue AUIPCLoc;
if (!getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, nullptr))
return nullptr;
case RISCV::fixup_riscv_tls_got_hi20:
case RISCV::fixup_riscv_tls_gd_hi20:
case RISCV::fixup_riscv_pcrel_hi20:
+ if (DFOut)
+ *DFOut = DF;
return &F;
}
}
return nullptr;
}
-bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout,
- const MCFixup *Fixup) const {
- // VK_RISCV_PCREL_LO has to be handled specially. The MCExpr inside is
- // actually the location of a auipc instruction with a VK_RISCV_PCREL_HI fixup
- // pointing to the real target. We need to generate an MCValue in the form of
- // (<real target> + <offset from this fixup to the auipc fixup>). The Fixup
- // is pcrel relative to the VK_RISCV_PCREL_LO fixup, so we need to add the
- // offset to the VK_RISCV_PCREL_HI Fixup from VK_RISCV_PCREL_LO to correct.
-
- // Don't try to evaluate if the fixup will be forced as a relocation (e.g.
- // as linker relaxation is enabled). If we evaluated pcrel_lo in this case,
- // the modified fixup will be converted into a relocation that no longer
- // points to the pcrel_hi as the linker requires.
- auto &RAB =
- static_cast<RISCVAsmBackend &>(Layout->getAssembler().getBackend());
- if (RAB.willForceRelocations())
- return false;
-
- MCValue AUIPCLoc;
- if (!getSubExpr()->evaluateAsValue(AUIPCLoc, *Layout))
- return false;
-
- const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA();
- // Don't try to evaluate %pcrel_hi/%pcrel_lo pairs that cross fragment
- // boundries.
- if (!AUIPCSRE ||
- findAssociatedFragment() != AUIPCSRE->findAssociatedFragment())
- return false;
-
- const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol();
- if (!AUIPCSymbol)
- return false;
-
- const MCFixup *TargetFixup = getPCRelHiFixup();
- if (!TargetFixup)
- return false;
-
- if ((unsigned)TargetFixup->getKind() != RISCV::fixup_riscv_pcrel_hi20)
- return false;
-
- MCValue Target;
- if (!TargetFixup->getValue()->evaluateAsValue(Target, *Layout))
- return false;
-
- if (!Target.getSymA() || !Target.getSymA()->getSymbol().isInSection())
- return false;
-
- if (&Target.getSymA()->getSymbol().getSection() !=
- findAssociatedFragment()->getParent())
- return false;
-
- // We must use TargetFixup rather than AUIPCSymbol here. They will almost
- // always have the same offset, except for the case when AUIPCSymbol is at
- // the end of a fragment and the fixup comes from offset 0 in the next
- // fragment.
- uint64_t AUIPCOffset = TargetFixup->getOffset();
-
- Res = MCValue::get(Target.getSymA(), nullptr,
- Target.getConstant() + (Fixup->getOffset() - AUIPCOffset));
- return true;
-}
-
bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout,
const MCFixup *Fixup) const {
- if (Kind == VK_RISCV_PCREL_LO && evaluatePCRelLo(Res, Layout, Fixup))
- return true;
-
if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
return false;
int64_t evaluateAsInt64(int64_t Value) const;
- bool evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout,
- const MCFixup *Fixup) const;
-
explicit RISCVMCExpr(const MCExpr *Expr, VariantKind Kind)
: Expr(Expr), Kind(Kind) {}
const MCExpr *getSubExpr() const { return Expr; }
/// Get the corresponding PC-relative HI fixup that a VK_RISCV_PCREL_LO
- /// points to.
+ /// points to, and optionally the fragment containing it.
///
/// \returns nullptr if this isn't a VK_RISCV_PCREL_LO pointing to a
/// known PC-relative HI fixup.
- const MCFixup *getPCRelHiFixup() const;
+ const MCFixup *getPCRelHiFixup(const MCFragment **DFOut) const;
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
# RUN: | FileCheck --check-prefix RELAX %s
# Fixups for %pcrel_hi / %pcrel_lo can be evaluated within a section,
-# regardless of the fragment containing the target address.
+# regardless of the fragment containing the target address, provided symbol
+# binding allows it.
function:
.Lpcrel_label1:
- auipc a0, %pcrel_hi(other_function)
+ auipc a0, %pcrel_hi(local_function)
addi a1, a0, %pcrel_lo(.Lpcrel_label1)
# NORELAX: auipc a0, 0
# NORELAX-NOT: R_RISCV
# NORELAX-NOT: R_RISCV
# RELAX: auipc a0, 0
-# RELAX: R_RISCV_PCREL_HI20 other_function
+# RELAX: R_RISCV_PCREL_HI20 local_function
# RELAX: R_RISCV_RELAX *ABS*
# RELAX: addi a1, a0, 0
# RELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label1
.p2align 2 # Cause a new fragment be emitted here
.Lpcrel_label2:
- auipc a0, %pcrel_hi(other_function)
+ auipc a0, %pcrel_hi(local_function)
addi a1, a0, %pcrel_lo(.Lpcrel_label2)
# NORELAX: auipc a0, 0
# NORELAX-NOT: R_RISCV
# NORELAX-NOT: R_RISCV
# RELAX: auipc a0, 0
-# RELAX: R_RISCV_PCREL_HI20 other_function
+# RELAX: R_RISCV_PCREL_HI20 local_function
# RELAX: R_RISCV_RELAX *ABS*
# RELAX: addi a1, a0, 0
# RELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label2
# RELAX: R_RISCV_RELAX *ABS*
- .type other_function,@function
-other_function:
+ .type local_function,@function
+local_function:
ret
+# Check we correctly evaluate when fixups are in different fragments
+
+.Lpcrel_label3:
+ auipc a0, %pcrel_hi(local_function)
+ .p2align 2 # Cause a new fragment be emitted here
+ addi a1, a0, %pcrel_lo(.Lpcrel_label3)
+# NORELAX: auipc a0, 0
+# NORELAX-NOT: R_RISCV
+# NORELAX: addi a1, a0, -4
+# NORELAX-NOT: R_RISCV
+
+# RELAX: auipc a0, 0
+# RELAX: R_RISCV_PCREL_HI20 local_function
+# RELAX: R_RISCV_RELAX *ABS*
+# RELAX: addi a1, a0, 0
+# RELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label3
+# RELAX: R_RISCV_RELAX *ABS*
+
+# Check handling of symbol binding.
+
+.Lpcrel_label4:
+ auipc a0, %pcrel_hi(global_function)
+ addi a1, a0, %pcrel_lo(.Lpcrel_label4)
+# NORELAX: auipc a0, 0
+# NORELAX: R_RISCV_PCREL_HI20 global_function
+# NORELAX: addi a1, a0, 0
+# NORELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label4
+
+# RELAX: auipc a0, 0
+# RELAX: R_RISCV_PCREL_HI20 global_function
+# RELAX: R_RISCV_RELAX *ABS*
+# RELAX: addi a1, a0, 0
+# RELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label4
+# RELAX: R_RISCV_RELAX *ABS*
+
+.Lpcrel_label5:
+ auipc a0, %pcrel_hi(weak_function)
+ addi a1, a0, %pcrel_lo(.Lpcrel_label5)
+# NORELAX: auipc a0, 0
+# NORELAX: R_RISCV_PCREL_HI20 weak_function
+# NORELAX: addi a1, a0, 0
+# NORELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label5
+
+# RELAX: auipc a0, 0
+# RELAX: R_RISCV_PCREL_HI20 weak_function
+# RELAX: R_RISCV_RELAX *ABS*
+# RELAX: addi a1, a0, 0
+# RELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label5
+# RELAX: R_RISCV_RELAX *ABS*
+
+ .global global_function
+ .type global_function,@function
+global_function:
+ ret
+
+ .weak weak_function
+ .type weak_function,@function
+weak_function:
+ ret
1:
addi a0, a0, %pcrel_lo(1b) # CHECK: :[[@LINE]]:3: error: could not find corresponding %pcrel_hi
+ addi a0, a0, %pcrel_lo(0x123456) # CHECK: :[[@LINE]]:3: error: could not find corresponding %pcrel_hi
+ addi a0, a0, %pcrel_lo(foo) # CHECK: :[[@LINE]]:3: error: could not find corresponding %pcrel_hi
# CHECK-ALIAS....Match the alias (tests instr. to alias mapping)
# CHECK-EXPAND...Match canonical instr. unconditionally (tests alias expansion)
+# Needed for testing valid %pcrel_lo expressions
+.Lpcrel_hi0: auipc a0, %pcrel_hi(foo)
# CHECK-INST: addi a0, zero, 0
# CHECK-ALIAS: mv a0, zero
# CHECK-EXPAND: addi a0, zero, 1110
li a0, %lo(0x123456)
-# CHECK-OBJ-NOALIAS: addi a0, zero, 0
-# CHECK-OBJ: R_RISCV_PCREL_LO12
-li a0, %pcrel_lo(0x123456)
# CHECK-OBJ-NOALIAS: addi a0, zero, 0
# CHECK-OBJ: R_RISCV_LO12
li a0, %lo(foo)
# CHECK-OBJ-NOALIAS: addi a0, zero, 0
# CHECK-OBJ: R_RISCV_PCREL_LO12
-li a0, %pcrel_lo(foo)
+li a0, %pcrel_lo(.Lpcrel_hi0)
.equ CONST, 0x123456
# CHECK-EXPAND: lui a0, 291
.equ CONST, 30
+# Needed for testing valid %pcrel_lo expressions
+.Lpcrel_hi0: auipc a0, %pcrel_hi(foo)
+
# CHECK-ASM-AND-OBJ: lui a0, 2
# CHECK-ASM: encoding: [0x37,0x25,0x00,0x00]
lui a0, 2
# CHECK-OBJ: lbu s5, 0(s6)
# CHECK-OBJ: R_RISCV_LO12
lbu s5, %lo(foo)(s6)
-# CHECK-ASM: lhu t3, %pcrel_lo(foo)(t3)
+# CHECK-ASM: lhu t3, %pcrel_lo(.Lpcrel_hi0)(t3)
# CHECK-ASM: encoding: [0x03,0x5e,0bAAAA1110,A]
# CHECK-OBJ: lhu t3, 0(t3)
# CHECK-OBJ: R_RISCV_PCREL_LO12
-lhu t3, %pcrel_lo(foo)(t3)
+lhu t3, %pcrel_lo(.Lpcrel_hi0)(t3)
# CHECK-ASM-AND-OBJ: lb t0, 30(t1)
# CHECK-ASM: encoding: [0x83,0x02,0xe3,0x01]
lb t0, CONST(t1)
# TODO ld
# TODO sd
+# Needed for testing valid %pcrel_lo expressions
+.Lpcrel_hi0: auipc a0, %pcrel_hi(foo)
+
# CHECK-INST: addi a0, zero, 0
# CHECK-ALIAS: mv a0, zero
li x10, 0
# CHECK-EXPAND: addi a0, zero, 1110
li a0, %lo(0x123456)
-# CHECK-OBJ-NOALIAS: addi a0, zero, 0
-# CHECK-OBJ: R_RISCV_PCREL_LO12
-li a0, %pcrel_lo(0x123456)
# CHECK-OBJ-NOALIAS: addi a0, zero, 0
# CHECK-OBJ: R_RISCV_LO12
li a0, %lo(foo)
# CHECK-OBJ-NOALIAS: addi a0, zero, 0
# CHECK-OBJ: R_RISCV_PCREL_LO12
-li a0, %pcrel_lo(foo)
+li a0, %pcrel_lo(.Lpcrel_hi0)
.equ CONST, 0x123456
# CHECK-EXPAND: lui a0, 291