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,20 @@ 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")) { + StringRef Mnemonic = static_cast(*Operands[0]).getToken(); + if (!(Mnemonic == "call" || Mnemonic == "tail")) { + Error(getLoc(), "'@plt' operand not valid for instruction"); + return MatchOperand_ParseFail; + } + + 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 @@ -86,6 +86,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 @@ -211,7 +211,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 @@ -32,11 +32,15 @@ } 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 (Kind == VK_RISCV_CALL_PLT) + OS << "@plt"; if (HasVariant) OS << ')'; } @@ -174,7 +178,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: 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 Index: test/MC/RISCV/lla-invalid.s =================================================================== --- test/MC/RISCV/lla-invalid.s +++ test/MC/RISCV/lla-invalid.s @@ -4,3 +4,4 @@ # Non bare symbols must be rejected lla a2, %lo(a_symbol) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name lla a2, %hi(a_symbol) # CHECK: :[[@LINE]]:9: error: operand must be a bare symbol name +lla a2, foo@plt # CHECK: :[[@LINE]]:17: error: '@plt' operand not valid for instruction Index: test/MC/RISCV/tail-call.s =================================================================== --- test/MC/RISCV/tail-call.s +++ test/MC/RISCV/tail-call.s @@ -45,3 +45,9 @@ # INSTR: auipc t1, 0 # INSTR: jr t1 # FIXUP: fixup A - offset: 0, value: ra, kind: + +tail foo@plt +# RELOC: R_RISCV_CALL_PLT foo 0x0 +# INSTR: auipc t1, 0 +# INSTR: jr t1 +# FIXUP: fixup A - offset: 0, value: foo@plt, kind: