diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -291,7 +291,8 @@ if (!isImm() || evaluateConstantImm(getImm(), Imm, VK)) return false; return RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm) && - VK == RISCVMCExpr::VK_RISCV_CALL; + (VK == RISCVMCExpr::VK_RISCV_CALL || + VK == RISCVMCExpr::VK_RISCV_CALL_PLT); } bool isCSRSystemRegister() const { return isSystemRegister(); } @@ -1142,6 +1143,11 @@ if (getParser().parseIdentifier(Identifier)) return MatchOperand_ParseFail; + if (Identifier.consume_back("@plt")) { + Error(getLoc(), "'@plt' operand not valid for instruction"); + return MatchOperand_ParseFail; + } + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); if (Sym->isVariable()) { @@ -1169,9 +1175,13 @@ if (getParser().parseIdentifier(Identifier)) return MatchOperand_ParseFail; + RISCVMCExpr::VariantKind Kind = RISCVMCExpr::VK_RISCV_CALL; + if (Identifier.consume_back("@plt")) + Kind = RISCVMCExpr::VK_RISCV_CALL_PLT; + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); - Res = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, getContext()); + Res = RISCVMCExpr::create(Res, Kind, getContext()); Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); return MatchOperand_Success; } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -110,6 +110,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 }, { "fixup_riscv_align", 0, 0, 0 } }; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -230,7 +230,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. diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -95,6 +95,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; case RISCV::fixup_riscv_align: diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -52,6 +52,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, diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -242,6 +242,10 @@ FixupKind = RISCV::fixup_riscv_call; RelaxCandidate = true; break; + case RISCVMCExpr::VK_RISCV_CALL_PLT: + FixupKind = RISCV::fixup_riscv_call_plt; + RelaxCandidate = true; + break; } } else if (Kind == MCExpr::SymbolRef && cast(Expr)->getKind() == MCSymbolRefExpr::VK_None) { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -30,6 +30,7 @@ VK_RISCV_PCREL_HI, VK_RISCV_GOT_HI, VK_RISCV_CALL, + VK_RISCV_CALL_PLT, VK_RISCV_Invalid }; diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -33,11 +33,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 << ')'; } @@ -200,7 +204,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)) diff --git a/llvm/test/MC/RISCV/function-call.s b/llvm/test/MC/RISCV/function-call.s --- a/llvm/test/MC/RISCV/function-call.s +++ b/llvm/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 diff --git a/llvm/test/MC/RISCV/lla-invalid.s b/llvm/test/MC/RISCV/lla-invalid.s --- a/llvm/test/MC/RISCV/lla-invalid.s +++ b/llvm/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 diff --git a/llvm/test/MC/RISCV/tail-call.s b/llvm/test/MC/RISCV/tail-call.s --- a/llvm/test/MC/RISCV/tail-call.s +++ b/llvm/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: