diff options
| author | Fangrui Song <i@maskray.me> | 2025-03-29 11:08:13 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-03-29 11:08:13 -0700 |
| commit | fe6fb910df9d1b9a9e2e7a6e8228d020668e0129 (patch) | |
| tree | b03e644f0516ae2281f3354235c81e48f8ac891d /llvm/lib/CodeGen | |
| parent | 666faa7fd98b7a58e089a38083f33c067ed5b955 (diff) | |
| download | llvm-fe6fb910df9d1b9a9e2e7a6e8228d020668e0129.zip llvm-fe6fb910df9d1b9a9e2e7a6e8228d020668e0129.tar.gz llvm-fe6fb910df9d1b9a9e2e7a6e8228d020668e0129.tar.bz2 | |
[RISCV] Replace @plt/@gotpcrel in data directives with %pltpcrel %gotpcrel
clang -fexperimental-relative-c++-abi-vtables might generate `@plt` and
`@gotpcrel` specifiers in data directives. The syntax is not used in
humand-written assembly code, and is not supported by GNU assembler.
Note: the `@plt` in `.word foo@plt` is different from
the legacy `call func@plt` (where `@plt` is simply ignored).
The `@plt` syntax was selected was simply due to a quirk of AsmParser:
the syntax was supported by all targets until I updated it
to be an opt-in feature in a0671758eb6e52a758bd1b096a9b421eec60204c
RISC-V favors the `%specifier(expr)` syntax following MIPS and Sparc,
and we should follow this convention.
This PR adds support for `.word %pltpcrel(foo+offset)` and
`.word %gotpcrel(foo)`, and drops `@plt` and `@gotpcrel`.
* MCValue::SymA can no longer have a SymbolVariant. Add an assert
similar to that of AArch64ELFObjectWriter.cpp before
https://reviews.llvm.org/D81446 (see my analysis at
https://maskray.me/blog/2025-03-16-relocation-generation-in-assemblers
if intrigued)
* `jump foo@plt, x31` now has a different diagnostic.
Pull Request: https://github.com/llvm/llvm-project/pull/132569
Diffstat (limited to 'llvm/lib/CodeGen')
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 66 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 77 |
2 files changed, 90 insertions, 53 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 40abe28..c626202 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -3363,7 +3363,9 @@ void AsmPrinter::emitAlignment(Align Alignment, const GlobalObject *GV, // Constant emission. //===----------------------------------------------------------------------===// -const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { +const MCExpr *AsmPrinter::lowerConstant(const Constant *CV, + const Constant *BaseCV, + uint64_t Offset) { MCContext &Ctx = OutContext; if (CV->isNullValue() || isa<UndefValue>(CV)) @@ -3382,7 +3384,8 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { return lowerBlockAddressConstant(*BA); if (const auto *Equiv = dyn_cast<DSOLocalEquivalent>(CV)) - return getObjFileLowering().lowerDSOLocalEquivalent(Equiv, TM); + return getObjFileLowering().lowerDSOLocalEquivalent( + getSymbol(Equiv->getGlobalValue()), nullptr, 0, std::nullopt, TM); if (const NoCFIValue *NC = dyn_cast<NoCFIValue>(CV)) return MCSymbolRefExpr::create(getSymbol(NC->getGlobalValue()), Ctx); @@ -3428,7 +3431,7 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { // is reasonable to treat their delta as a 32-bit value. [[fallthrough]]; case Instruction::BitCast: - return lowerConstant(CE->getOperand(0)); + return lowerConstant(CE->getOperand(0), BaseCV, Offset); case Instruction::IntToPtr: { const DataLayout &DL = getDataLayout(); @@ -3467,33 +3470,42 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { } case Instruction::Sub: { - GlobalValue *LHSGV; - APInt LHSOffset; + GlobalValue *LHSGV, *RHSGV; + APInt LHSOffset, RHSOffset; DSOLocalEquivalent *DSOEquiv; if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHSGV, LHSOffset, - getDataLayout(), &DSOEquiv)) { - GlobalValue *RHSGV; - APInt RHSOffset; - if (IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset, - getDataLayout())) { - const MCExpr *RelocExpr = - getObjFileLowering().lowerRelativeReference(LHSGV, RHSGV, TM); - if (!RelocExpr) { - const MCExpr *LHSExpr = - MCSymbolRefExpr::create(getSymbol(LHSGV), Ctx); - if (DSOEquiv && - getObjFileLowering().supportDSOLocalEquivalentLowering()) - LHSExpr = - getObjFileLowering().lowerDSOLocalEquivalent(DSOEquiv, TM); - RelocExpr = MCBinaryExpr::createSub( - LHSExpr, MCSymbolRefExpr::create(getSymbol(RHSGV), Ctx), Ctx); - } - int64_t Addend = (LHSOffset - RHSOffset).getSExtValue(); + getDataLayout(), &DSOEquiv) && + IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset, + getDataLayout())) { + auto *LHSSym = getSymbol(LHSGV); + auto *RHSSym = getSymbol(RHSGV); + int64_t Addend = (LHSOffset - RHSOffset).getSExtValue(); + std::optional<int64_t> PCRelativeOffset; + if (getObjFileLowering().hasPLTPCRelative() && RHSGV == BaseCV) + PCRelativeOffset = Offset; + + // Try the generic symbol difference first. + const MCExpr *Res = getObjFileLowering().lowerRelativeReference( + LHSGV, RHSGV, Addend, PCRelativeOffset, TM); + + // (ELF-specific) If the generic symbol difference does not apply, and + // LHS is a dso_local_equivalent of a dso_preemptable function, + // reference the PLT entry instead. + if (DSOEquiv && TM.getTargetTriple().isOSBinFormatELF() && + !(LHSGV->isDSOLocal() || LHSGV->isImplicitDSOLocal())) + Res = getObjFileLowering().lowerDSOLocalEquivalent( + LHSSym, RHSSym, Addend, PCRelativeOffset, TM); + + // Otherwise, return LHS-RHS+Addend. + if (!Res) { + Res = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHSSym, Ctx), + MCSymbolRefExpr::create(RHSSym, Ctx), Ctx); if (Addend != 0) - RelocExpr = MCBinaryExpr::createAdd( - RelocExpr, MCConstantExpr::create(Addend, Ctx), Ctx); - return RelocExpr; + Res = MCBinaryExpr::createAdd( + Res, MCConstantExpr::create(Addend, Ctx), Ctx); } + return Res; } const MCExpr *LHS = lowerConstant(CE->getOperand(0)); @@ -4023,7 +4035,7 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV, // Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it // thread the streamer with EmitValue. - const MCExpr *ME = AP.lowerConstant(CV); + const MCExpr *ME = AP.lowerConstant(CV, BaseCV, Offset); // Since lowerConstant already folded and got rid of all IR pointer and // integer casts, detect GOT equivalent accesses by looking into the MCExpr diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 0e44acd..dd6d85e 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -115,10 +115,6 @@ static void GetObjCImageInfo(Module &M, unsigned &Version, unsigned &Flags, // ELF //===----------------------------------------------------------------------===// -TargetLoweringObjectFileELF::TargetLoweringObjectFileELF() { - SupportDSOLocalEquivalentLowering = true; -} - void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx, const TargetMachine &TgtM) { TargetLoweringObjectFile::Initialize(Ctx, TgtM); @@ -1174,9 +1170,37 @@ MCSection *TargetLoweringObjectFileELF::getStaticDtorSection( KeySym); } +const MCExpr *TargetLoweringObjectFileELF::lowerSymbolDifference( + const MCSymbol *LHS, const MCSymbol *RHS, int64_t Addend, + std::optional<int64_t> PCRelativeOffset) const { + auto &Ctx = getContext(); + const MCExpr *Res; + // Return a relocatable expression with the PLT specifier, %plt(GV) or + // %plt(GV-RHS). + if (PCRelativeOffset && PLTPCRelativeSpecifier) { + Res = MCSymbolRefExpr::create(LHS, Ctx); + // The current location is RHS plus *PCRelativeOffset. Compensate for it. + Addend += *PCRelativeOffset; + if (Addend) + Res = MCBinaryExpr::createAdd(Res, MCConstantExpr::create(Addend, Ctx), + Ctx); + return createTargetMCExpr(Res, PLTPCRelativeSpecifier); + } + + if (!PLTRelativeSpecifier) + return nullptr; + Res = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(LHS, PLTRelativeSpecifier, Ctx), + MCSymbolRefExpr::create(RHS, Ctx), Ctx); + if (Addend) + Res = + MCBinaryExpr::createAdd(Res, MCConstantExpr::create(Addend, Ctx), Ctx); + return Res; +} + const MCExpr *TargetLoweringObjectFileELF::lowerRelativeReference( - const GlobalValue *LHS, const GlobalValue *RHS, - const TargetMachine &TM) const { + const GlobalValue *LHS, const GlobalValue *RHS, int64_t Addend, + std::optional<int64_t> PCRelativeOffset, const TargetMachine &TM) const { // We may only use a PLT-relative relocation to refer to unnamed_addr // functions. if (!LHS->hasGlobalUnnamedAddr() || !LHS->getValueType()->isFunctionTy()) @@ -1188,24 +1212,22 @@ const MCExpr *TargetLoweringObjectFileELF::lowerRelativeReference( RHS->isThreadLocal()) return nullptr; - return MCBinaryExpr::createSub( - MCSymbolRefExpr::create(TM.getSymbol(LHS), PLTRelativeSpecifier, - getContext()), - MCSymbolRefExpr::create(TM.getSymbol(RHS), getContext()), getContext()); + return lowerSymbolDifference(TM.getSymbol(LHS), TM.getSymbol(RHS), Addend, + PCRelativeOffset); } +// Reference the PLT entry of a function, optionally with a subtrahend (`RHS`). const MCExpr *TargetLoweringObjectFileELF::lowerDSOLocalEquivalent( - const DSOLocalEquivalent *Equiv, const TargetMachine &TM) const { - assert(supportDSOLocalEquivalentLowering()); - - const auto *GV = Equiv->getGlobalValue(); - - // A PLT entry is not needed for dso_local globals. - if (GV->isDSOLocal() || GV->isImplicitDSOLocal()) - return MCSymbolRefExpr::create(TM.getSymbol(GV), getContext()); - - return MCSymbolRefExpr::create(TM.getSymbol(GV), PLTRelativeSpecifier, - getContext()); + const MCSymbol *LHS, const MCSymbol *RHS, int64_t Addend, + std::optional<int64_t> PCRelativeOffset, const TargetMachine &TM) const { + if (RHS) + return lowerSymbolDifference(LHS, RHS, Addend, PCRelativeOffset); + + // Only the legacy MCSymbolRefExpr::VariantKind approach is implemented. + // Reference LHS@plt or LHS@plt - RHS. + if (PLTRelativeSpecifier) + return MCSymbolRefExpr::create(LHS, PLTRelativeSpecifier, getContext()); + return nullptr; } MCSection *TargetLoweringObjectFileELF::getSectionForCommandLines() const { @@ -2044,8 +2066,8 @@ MCSection *TargetLoweringObjectFileCOFF::getStaticDtorSection( } const MCExpr *TargetLoweringObjectFileCOFF::lowerRelativeReference( - const GlobalValue *LHS, const GlobalValue *RHS, - const TargetMachine &TM) const { + const GlobalValue *LHS, const GlobalValue *RHS, int64_t Addend, + std::optional<int64_t> PCRelativeOffset, const TargetMachine &TM) const { const Triple &T = TM.getTargetTriple(); if (T.isOSCygMing()) return nullptr; @@ -2069,9 +2091,12 @@ const MCExpr *TargetLoweringObjectFileCOFF::lowerRelativeReference( cast<GlobalVariable>(RHS)->hasInitializer() || RHS->hasSection()) return nullptr; - return MCSymbolRefExpr::create(TM.getSymbol(LHS), - MCSymbolRefExpr::VK_COFF_IMGREL32, - getContext()); + const MCExpr *Res = MCSymbolRefExpr::create( + TM.getSymbol(LHS), MCSymbolRefExpr::VK_COFF_IMGREL32, getContext()); + if (Addend != 0) + Res = MCBinaryExpr::createAdd( + Res, MCConstantExpr::create(Addend, getContext()), getContext()); + return Res; } static std::string APIntToHexString(const APInt &AI) { |
