Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -266,7 +266,8 @@ if (!isImm() || evaluateConstantImm(getImm(), Imm, VK)) return false; return RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm) && - VK == RISCVMCExpr::VK_RISCV_None; + (VK == RISCVMCExpr::VK_RISCV_None || + VK == RISCVMCExpr::VK_RISCV_CALL_PLT); } bool isCSRSystemRegister() const { return isSystemRegister(); } @@ -1104,8 +1105,14 @@ if (getParser().parseIdentifier(Identifier)) return MatchOperand_ParseFail; - MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); - Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + if (Identifier.consume_back("@plt")) { + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + Res = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL_PLT, getContext()); + } else { + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + } Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); return MatchOperand_Success; } Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -91,6 +91,7 @@ { "fixup_riscv_rvc_jump", 2, 11, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_rvc_branch", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_relax", 0, 0, 0 } }; static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds, Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -185,7 +185,8 @@ Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7); return Value; } - case RISCV::fixup_riscv_call: { + case RISCV::fixup_riscv_call: + case RISCV::fixup_riscv_call_plt: { // Jalr will add UpperImm with the sign-extended 12-bit LowerImm, // we need to add 0x800ULL before extract upper bits to reflect the // effect of the sign extension. Index: lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -96,6 +96,8 @@ return ELF::R_RISCV_RVC_BRANCH; case RISCV::fixup_riscv_call: return ELF::R_RISCV_CALL; + case RISCV::fixup_riscv_call_plt: + return ELF::R_RISCV_CALL_PLT; case RISCV::fixup_riscv_relax: return ELF::R_RISCV_RELAX; } Index: lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -53,6 +53,10 @@ // fixup_riscv_call - A fixup representing a call attached to the auipc // instruction in a pair composed of adjacent auipc+jalr instructions. fixup_riscv_call, + // fixup_riscv_call_plt - A fixup representing a procedure linkage table call + // attached to the auipc instruction in a pair composed of adjacent auipc+jalr + // instructions. + fixup_riscv_call_plt, // fixup_riscv_relax - Used to generate an R_RISCV_RELAX relocation type, // which indicates the linker may relax the instruction pair. fixup_riscv_relax, Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -104,9 +104,15 @@ const MCExpr *Expr = Func.getExpr(); + RISCVMCExpr::VariantKind Kind = RISCVMCExpr::VK_RISCV_CALL; + if (const RISCVMCExpr *RVExpr = dyn_cast(Expr)) { + Expr = RVExpr->getSubExpr(); + Kind = RVExpr->getKind(); + } + // Create function call expression CallExpr for AUIPC. const MCExpr *CallExpr = - RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL, Ctx); + RISCVMCExpr::create(Expr, Kind, Ctx); // Emit AUIPC Ra, Func with R_RISCV_CALL relocation type. TmpInst = MCInstBuilder(RISCV::AUIPC) @@ -241,6 +247,9 @@ case RISCVMCExpr::VK_RISCV_CALL: FixupKind = RISCV::fixup_riscv_call; break; + case RISCVMCExpr::VK_RISCV_CALL_PLT: + FixupKind = RISCV::fixup_riscv_call_plt; + break; } } else if (Kind == MCExpr::SymbolRef && cast(Expr)->getKind() == MCSymbolRefExpr::VK_None) { @@ -262,7 +271,8 @@ ++MCNumFixups; if (EnableRelax) { - if (FixupKind == RISCV::fixup_riscv_call) { + if (FixupKind == RISCV::fixup_riscv_call || + FixupKind == RISCV::fixup_riscv_call_plt) { Fixups.push_back( MCFixup::create(0, Expr, MCFixupKind(RISCV::fixup_riscv_relax), MI.getLoc())); Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -31,6 +31,7 @@ VK_RISCV_PCREL_HI, VK_RISCV_GOT_HI, VK_RISCV_CALL, + VK_RISCV_CALL_PLT, VK_RISCV_Invalid }; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -31,13 +31,17 @@ } void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { - bool HasVariant = - ((getKind() != VK_RISCV_None) && (getKind() != VK_RISCV_CALL)); + VariantKind Kind = getKind(); + bool HasVariant = ((Kind != VK_RISCV_None) && (Kind != VK_RISCV_CALL) && + (Kind != VK_RISCV_CALL_PLT)); + if (HasVariant) OS << '%' << getVariantKindName(getKind()) << '('; Expr->print(OS, MAI); if (HasVariant) OS << ')'; + if (Kind == VK_RISCV_CALL_PLT) + OS << "@plt"; } bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, @@ -98,7 +102,8 @@ MCValue Value; if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || - Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_CALL) + Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_CALL || + Kind == VK_RISCV_CALL_PLT) return false; if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) Index: lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- lib/Target/RISCV/RISCVISelLowering.cpp +++ lib/Target/RISCV/RISCVISelLowering.cpp @@ -1462,9 +1462,28 @@ // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't // split it and then direct call can be matched by PseudoCALL. if (GlobalAddressSDNode *S = dyn_cast(Callee)) { - Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, 0); + const GlobalValue *GV = S->getGlobal(); + unsigned OpFlags = Subtarget + .classifyFunctionReference(*GV->getParent(), GV); + + Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags); + + if (OpFlags == RISCVII::MO_GOT_HI) { + Callee = DAG.getNode(RISCVISD::WRAPPER_PCREL, DL, PtrVT, Callee); + Callee = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Callee, + MachinePointerInfo()); + } } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { - Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, 0); + unsigned OpFlags = Subtarget + .classifyFunctionReference(*MF.getFunction().getParent(), nullptr); + + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags); + + if (OpFlags == RISCVII::MO_GOT_HI) { + Callee = DAG.getNode(RISCVISD::WRAPPER_PCREL, DL, PtrVT, Callee); + Callee = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Callee, + MachinePointerInfo()); + } } // The first call operand is the chain and the second is the target address. Index: lib/Target/RISCV/RISCVMCInstLower.cpp =================================================================== --- lib/Target/RISCV/RISCVMCInstLower.cpp +++ lib/Target/RISCV/RISCVMCInstLower.cpp @@ -52,6 +52,9 @@ case RISCVII::MO_GOT_HI: Kind = RISCVMCExpr::VK_RISCV_GOT_HI; break; + case RISCVII::MO_PLT: + Kind = RISCVMCExpr::VK_RISCV_CALL_PLT; + break; } const MCExpr *ME = Index: lib/Target/RISCV/RISCVSubtarget.h =================================================================== --- lib/Target/RISCV/RISCVSubtarget.h +++ lib/Target/RISCV/RISCVSubtarget.h @@ -44,6 +44,7 @@ RISCVRegisterInfo RegInfo; RISCVTargetLowering TLInfo; SelectionDAGTargetInfo TSInfo; + const TargetMachine &TM; /// Initializes using the passed in CPU and feature strings so that we can /// use initializer lists for subtarget initialization. @@ -81,6 +82,9 @@ bool enableLinkerRelax() const { return EnableLinkerRelax; } MVT getXLenVT() const { return XLenVT; } unsigned getXLen() const { return XLen; } + + unsigned classifyFunctionReference(const Module &M, + const GlobalValue *GV) const; }; } // End llvm namespace Index: lib/Target/RISCV/RISCVSubtarget.cpp =================================================================== --- lib/Target/RISCV/RISCVSubtarget.cpp +++ lib/Target/RISCV/RISCVSubtarget.cpp @@ -45,4 +45,16 @@ const std::string &FS, const TargetMachine &TM) : RISCVGenSubtargetInfo(TT, CPU, FS), FrameLowering(initializeSubtargetDependencies(CPU, FS, TT.isArch64Bit())), - InstrInfo(), RegInfo(getHwMode()), TLInfo(TM, *this) {} + InstrInfo(), RegInfo(getHwMode()), TLInfo(TM, *this), TM(TM) {} + +unsigned +RISCVSubtarget::classifyFunctionReference(const Module &M, + const GlobalValue *GV) const { + if (TM.shouldAssumeDSOLocal(M, GV)) + return 0u; + + if (M.getRtLibUseGOT()) + return RISCVII::MO_GOT_HI; + + return RISCVII::MO_PLT; +} \ No newline at end of file Index: lib/Target/RISCV/Utils/RISCVBaseInfo.h =================================================================== --- lib/Target/RISCV/Utils/RISCVBaseInfo.h +++ lib/Target/RISCV/Utils/RISCVBaseInfo.h @@ -54,6 +54,7 @@ MO_PCREL_LO, MO_PCREL_HI, MO_GOT_HI, + MO_PLT, }; } // namespace RISCVII Index: test/MC/RISCV/function-call.s =================================================================== --- test/MC/RISCV/function-call.s +++ test/MC/RISCV/function-call.s @@ -43,3 +43,11 @@ # INSTR: auipc ra, 0 # INSTR: jalr ra # FIXUP: fixup A - offset: 0, value: mstatus, kind: fixup_riscv_call + +# Ensure that calls to procedure linkage table symbols work. + +call foo@plt +# RELOC: R_RISCV_CALL_PLT foo 0x0 +# INSTR: auipc ra, 0 +# INSTR: jalr ra +# FIXUP: fixup A - offset: 0, value: foo@plt, kind: fixup_riscv_call_plt