[clang] [llvm] [clang][RISCV] Emit RISCV function-signature-based CFI label in llvm::Function metadata (PR #111661)
Ming-Yi Lai via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 11 04:41:59 PDT 2024
https://github.com/mylai-mtk updated https://github.com/llvm/llvm-project/pull/111661
>From 0cc12aa82111ead067485c0e846313563e516e6c Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Fri, 31 May 2024 17:03:04 +0800
Subject: [PATCH] [clang][RISCV] Emit RISCV function-signature-based CFI label
in llvm::Function metadata
This patch emits the RISC-V Zicfilp func-sig CFI label in the metadata of
generated `llvm::Function`s.
It introduces CodeGenModule::calcRISCVZicfilpFuncSigLabel(), which calculates a
CFI label used in the RISC-V Zicfilp func-sig CFI scheme for a given function
type/declaration. The scheme, according to psABI, encodes the label based on
function signature, and the rules are modified from the Itanium C++ ABI mangling
rule to allow functions (callees) that are called indirectly to have the
expected label as indicated by the function pointer type seen at the call site
(caller).
---
clang/include/clang/AST/ASTContext.h | 7 +
clang/include/clang/AST/Mangle.h | 5 +
clang/lib/AST/ASTContext.cpp | 6 +
clang/lib/AST/ItaniumMangle.cpp | 138 +++++++++++++++++-
clang/lib/CodeGen/CodeGenModule.cpp | 84 +++++++++++
clang/lib/CodeGen/CodeGenModule.h | 19 +++
.../mangle-class-covariant-virtual-method.cpp | 33 +++++
.../mangle-class-destructor.cpp | 17 +++
...angle-class-incovariant-virtual-method.cpp | 18 +++
.../zicfilp-func-sig/mangle-class-method.cpp | 18 +++
.../mangle-class-static-method.cpp | 21 +++
.../mangle-func-empty-param-list.c | 15 ++
.../mangle-func-empty-param-list.cpp | 15 ++
.../mangle-ignore-exception-spec.cpp | 15 ++
.../RISCV/zicfilp-func-sig/mangle-main.cpp | 39 +++++
.../RISCV/zicfilp-func-sig/mangle-wchar-t.cpp | 12 ++
llvm/include/llvm/Support/RISCVISAUtils.h | 6 +-
llvm/lib/Support/RISCVISAUtils.cpp | 22 ++-
18 files changed, 486 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.cpp
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-method.cpp
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp
create mode 100644 clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index a4d36f2eacd5d1..4812e0bac2cfc3 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1876,6 +1876,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const;
+ /// Return the type for "void *"
+ QualType getVoidPtrType() const { return VoidPtrTy; }
+
/// Return the unique type for "size_t" (C99 7.17), defined in
/// <stddef.h>.
///
@@ -1903,6 +1906,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// defined in <stddef.h> as defined by the target.
QualType getWideCharType() const { return WideCharTy; }
+ /// Return the type of wide characters in C context, no matter whether it's C
+ /// or C++ being compiled.
+ QualType getWCharTypeInC() const;
+
/// Return the type of "signed wchar_t".
///
/// Used when in C++, as a GCC extension.
diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h
index d5f6c0f6cc67df..16cbd802177ba4 100644
--- a/clang/include/clang/AST/Mangle.h
+++ b/clang/include/clang/AST/Mangle.h
@@ -212,6 +212,11 @@ class ItaniumMangleContext : public MangleContext {
virtual void mangleModuleInitializer(const Module *Module, raw_ostream &) = 0;
+ virtual void mangleForRISCVZicfilpFuncSigLabel(const FunctionType &FT,
+ const bool IsCXXInstanceMethod,
+ const bool IsCXXVirtualMethod,
+ raw_ostream &) = 0;
+
// This has to live here, otherwise the CXXNameMangler won't have access to
// it.
virtual DiscriminatorOverrideTy getDiscriminatorOverride() const = 0;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 034fbbe0bc7829..ce8688a489cb43 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6442,6 +6442,12 @@ CanQualType ASTContext::getUIntMaxType() const {
return getFromTargetType(Target->getUIntMaxType());
}
+/// Return the type of wide characters in C context, no matter whether it's C
+/// or C++ being compiled.
+QualType ASTContext::getWCharTypeInC() const {
+ return getFromTargetType(Target->getWCharType());
+}
+
/// getSignedWCharType - Return the type of "signed wchar_t".
/// Used when in C++, as a GCC extension.
QualType ASTContext::getSignedWCharType() const {
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 777cdca1a0c0d7..23ec51cfec90fd 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -43,6 +43,14 @@ using namespace clang;
namespace {
+static bool mayBeCovariant(const Type &Ty) {
+ if (auto *const PT = Ty.getAs<PointerType>())
+ return PT->getPointeeType()->isStructureOrClassType();
+ if (auto *const RT = Ty.getAs<ReferenceType>())
+ return RT->getPointeeType()->isStructureOrClassType();
+ return false;
+}
+
static bool isLocalContainerContext(const DeclContext *DC) {
return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || isa<BlockDecl>(DC);
}
@@ -136,6 +144,11 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
void mangleModuleInitializer(const Module *Module, raw_ostream &) override;
+ void mangleForRISCVZicfilpFuncSigLabel(const FunctionType &,
+ const bool IsCXXInstanceMethod,
+ const bool IsCXXVirtualMethod,
+ raw_ostream &) override;
+
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
if (isLambda(ND))
@@ -395,8 +408,10 @@ class CXXNameMangler {
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
llvm::DenseMap<StringRef, unsigned> ModuleSubstitutions;
+protected:
ASTContext &getASTContext() const { return Context.getASTContext(); }
+private:
bool isCompatibleWith(LangOptions::ClangABI Ver) {
return Context.getASTContext().getLangOpts().getClangABICompat() <= Ver;
}
@@ -443,6 +458,8 @@ class CXXNameMangler {
NullOut = true;
}
+ virtual ~CXXNameMangler() = default;
+
struct WithTemplateDepthOffset { unsigned Offset; };
CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
WithTemplateDepthOffset Offset)
@@ -559,9 +576,12 @@ class CXXNameMangler {
StringRef Prefix = "");
void mangleOperatorName(DeclarationName Name, unsigned Arity);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
+
+protected:
void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr);
void mangleRefQualifier(RefQualifierKind RefQualifier);
+private:
void mangleObjCMethodName(const ObjCMethodDecl *MD);
// Declare manglers for every type class.
@@ -572,11 +592,24 @@ class CXXNameMangler {
void mangleType(const TagType*);
void mangleType(TemplateName);
+
+protected:
+ // Use the `Impl` scheme instead of directly virtualizing `mangleType`s since
+ // `mangleType`s are declared by tables
+ virtual void mangleTypeImpl(const BuiltinType *T);
+ virtual void mangleTypeImpl(const FunctionProtoType *T);
+ virtual void mangleTypeImpl(const FunctionNoProtoType *T);
+
+private:
static StringRef getCallingConvQualifierName(CallingConv CC);
void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
void mangleExtFunctionInfo(const FunctionType *T);
+
+protected:
void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType,
const FunctionDecl *FD = nullptr);
+
+private:
void mangleNeonVectorType(const VectorType *T);
void mangleNeonVectorType(const DependentVectorType *T);
void mangleAArch64NeonVectorType(const VectorType *T);
@@ -3058,7 +3091,9 @@ void CXXNameMangler::mangleCXXRecordDecl(const CXXRecordDecl *Record) {
addSubstitution(Record);
}
-void CXXNameMangler::mangleType(const BuiltinType *T) {
+void CXXNameMangler::mangleType(const BuiltinType *T) { mangleTypeImpl(T); }
+
+void CXXNameMangler::mangleTypeImpl(const BuiltinType *T) {
// <type> ::= <builtin-type>
// <builtin-type> ::= v # void
// ::= w # wchar_t
@@ -3563,10 +3598,14 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
mangleVendorQualifier("noescape");
}
+void CXXNameMangler::mangleType(const FunctionProtoType *T) {
+ return mangleTypeImpl(T);
+}
+
// <type> ::= <function-type>
// <function-type> ::= [<CV-qualifiers>] F [Y]
// <bare-function-type> [<ref-qualifier>] E
-void CXXNameMangler::mangleType(const FunctionProtoType *T) {
+void CXXNameMangler::mangleTypeImpl(const FunctionProtoType *T) {
mangleExtFunctionInfo(T);
// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
@@ -3604,6 +3643,10 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
}
void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
+ return mangleTypeImpl(T);
+}
+
+void CXXNameMangler::mangleTypeImpl(const FunctionNoProtoType *T) {
// Function types without prototypes can arise when mangling a function type
// within an overloadable function in C. We mangle these as the absence of any
// parameter types (not even an empty parameter list).
@@ -7074,6 +7117,86 @@ bool CXXNameMangler::shouldHaveAbiTags(ItaniumMangleContextImpl &C,
return TrackAbiTags.AbiTagsRoot.getUsedAbiTags().size();
}
+namespace {
+
+class RISCVZicfilpFuncSigLabelMangler : public CXXNameMangler {
+ bool IsTopLevelAndCXXVirtualMethod;
+
+public:
+ RISCVZicfilpFuncSigLabelMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
+ const bool IsCXXVirtualMethod)
+ : CXXNameMangler(C, Out),
+ IsTopLevelAndCXXVirtualMethod(/*IsTopLevel=*/true &&
+ IsCXXVirtualMethod) {}
+
+ void mangleTypeImpl(const BuiltinType *T) override {
+ if (T->getKind() == BuiltinType::WChar_S ||
+ T->getKind() == BuiltinType::WChar_U) {
+ const Type *const OverrideT =
+ getASTContext().getWCharTypeInC().getTypePtr();
+ assert(isa<BuiltinType>(OverrideT) &&
+ "`wchar_t' in C is expected to be defined to a built-in type");
+ T = static_cast<const BuiltinType *>(OverrideT);
+ }
+ return CXXNameMangler::mangleTypeImpl(T);
+ }
+
+ // This <function-type> is the RISC-V psABI modified version
+ // <function-type> ::= [<CV-qualifiers>] [Dx] F <bare-function-type>
+ // [<ref-qualifier>] E
+ void mangleTypeImpl(const FunctionProtoType *T) override {
+ const bool WasTopLevelAndCXXVirtualMethod = IsTopLevelAndCXXVirtualMethod;
+ IsTopLevelAndCXXVirtualMethod = false; // Not top-level anymore
+
+ // Mangle CV-qualifiers, if present. These are 'this' qualifiers,
+ // e.g. "const" in "int (A::*)() const".
+ mangleQualifiers(T->getMethodQuals());
+
+ getStream() << 'F';
+
+ bool MangleReturnType = true;
+ if (const Type &RetT = *T->getReturnType().getTypePtr();
+ WasTopLevelAndCXXVirtualMethod && mayBeCovariant(RetT)) {
+ // Possible covariant types mangle dummy cv-unqualified `class v` as its
+ // class type
+ if (RetT.isPointerType())
+ getStream() << "P1v";
+ else if (RetT.isLValueReferenceType())
+ getStream() << "R1v";
+ else {
+ assert(RetT.isRValueReferenceType() &&
+ "Expect an r-value ref for covariant return type that is not a "
+ "pointer or an l-value ref");
+ getStream() << "O1v";
+ }
+ MangleReturnType = false;
+ }
+ mangleBareFunctionType(T, MangleReturnType);
+
+ // Mangle the ref-qualifier, if present.
+ mangleRefQualifier(T->getRefQualifier());
+
+ getStream() << 'E';
+ }
+
+ void mangleTypeImpl(const FunctionNoProtoType *T) override {
+ return CXXNameMangler::mangleTypeImpl(toFunctionProtoType(T));
+ }
+
+private:
+ const FunctionProtoType *
+ toFunctionProtoType(const FunctionNoProtoType *const T) {
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExtInfo = T->getExtInfo();
+ const Type *const NewT = getASTContext()
+ .getFunctionType(T->getReturnType(), {}, EPI)
+ .getTypePtr();
+ return static_cast<const FunctionProtoType *>(NewT);
+ }
+}; // class RISCVZicfilpFuncSigLabelMangler
+
+} // anonymous namespace
+
//
/// Mangles the name of the declaration D and emits that name to the given
@@ -7412,6 +7535,17 @@ void ItaniumMangleContextImpl::mangleModuleInitializer(const Module *M,
}
}
+void ItaniumMangleContextImpl::mangleForRISCVZicfilpFuncSigLabel(
+ const FunctionType &FT, const bool IsCXXInstanceMethod,
+ const bool IsCXXVirtualMethod, raw_ostream &Out) {
+ if (IsCXXInstanceMethod)
+ // member methods uses a dummy class named `v` in place of real classes
+ Out << "M1v";
+
+ RISCVZicfilpFuncSigLabelMangler Mangler(*this, Out, IsCXXVirtualMethod);
+ Mangler.mangleType(QualType(&FT, 0));
+}
+
ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context,
DiagnosticsEngine &Diags,
bool IsAux) {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 5ba098144a74e7..3042bc2c105de4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -69,6 +69,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/RISCVISAUtils.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/xxhash.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
@@ -453,6 +454,18 @@ CodeGenModule::CodeGenModule(ASTContext &C,
if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
getModule().addModuleFlag(llvm::Module::Error, "NumRegisterParameters",
CodeGenOpts.NumRegisterParameters);
+
+ if (CodeGenOpts.CFProtectionBranch &&
+ getTarget().checkCFProtectionBranchSupported(getDiags())) {
+ auto Scheme = CodeGenOpts.getCFBranchLabelScheme();
+ if (getTarget().checkCFBranchLabelSchemeSupported(Scheme, getDiags())) {
+ if (Scheme == CFBranchLabelSchemeKind::Default)
+ Scheme = getTarget().getDefaultCFBranchLabelScheme();
+
+ UseRISCVZicfilpFuncSigCFI =
+ (Scheme == CFBranchLabelSchemeKind::FuncSig && getTriple().isRISCV());
+ }
+ }
}
CodeGenModule::~CodeGenModule() {}
@@ -912,6 +925,8 @@ void CodeGenModule::Release() {
}
if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
finalizeKCFITypes();
+ if (UseRISCVZicfilpFuncSigCFI)
+ finalizeRISCVZicfilpFuncSigLabels();
emitAtAvailableLinkGuard();
if (Context.getTargetInfo().getTriple().isWasm())
EmitMainVoidAlias();
@@ -2829,6 +2844,39 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
}
+uint32_t
+CodeGenModule::calcRISCVZicfilpFuncSigLabel(const FunctionType &FT,
+ const bool IsCXXInstanceMethod,
+ const bool IsCXXVirtualMethod) {
+ std::string OutName;
+ llvm::raw_string_ostream Out(OutName);
+ MangleContext &MC = getCXXABI().getMangleContext();
+ cast<ItaniumMangleContext>(MC).mangleForRISCVZicfilpFuncSigLabel(
+ FT, IsCXXInstanceMethod, IsCXXVirtualMethod, Out);
+ return llvm::RISCVISAUtils::zicfilpFuncSigHash(OutName);
+}
+
+uint32_t CodeGenModule::calcRISCVZicfilpFuncSigLabel(const FunctionDecl &FD) {
+ if (FD.isMain())
+ // All main functions use `int main(int, char**)` for label calculation
+ // according to psABI spec. This value is the pre-calculated label.
+ return 0xd0639;
+
+ if (isa<CXXDestructorDecl>(FD))
+ // All destructors use `void (void*)` for label calculation according to the
+ // psABI spec. This value is the pre-calculated label.
+ return 0x639c2;
+
+ bool IsCXXInstanceMethod = false;
+ bool IsCXXVirtualMethod = false;
+ if (const auto *const MD = dyn_cast<CXXMethodDecl>(&FD)) {
+ IsCXXInstanceMethod = MD->isInstance();
+ IsCXXVirtualMethod = MD->isVirtual();
+ }
+ return calcRISCVZicfilpFuncSigLabel(*FD.getFunctionType(),
+ IsCXXInstanceMethod, IsCXXVirtualMethod);
+}
+
void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
llvm::LLVMContext &Ctx = F->getContext();
llvm::MDBuilder MDB(Ctx);
@@ -2837,6 +2885,16 @@ void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
Ctx, MDB.createConstant(CreateKCFITypeId(FD->getType()))));
}
+void CodeGenModule::setRISCVZicfilpFuncSigLabel(const FunctionDecl *FD,
+ llvm::Function *F) {
+ llvm::LLVMContext &Ctx = F->getContext();
+ llvm::MDBuilder MDB(Ctx);
+ F->setMetadata(
+ "riscv_lpad_label",
+ llvm::MDNode::get(Ctx, MDB.createConstant(llvm::ConstantInt::get(
+ Int32Ty, calcRISCVZicfilpFuncSigLabel(*FD)))));
+}
+
static bool allowKCFIIdentifier(StringRef Name) {
// KCFI type identifier constants are only necessary for external assembly
// functions, which means it's safe to skip unusual names. Subset of
@@ -2877,6 +2935,29 @@ void CodeGenModule::finalizeKCFITypes() {
}
}
+void CodeGenModule::finalizeRISCVZicfilpFuncSigLabels() {
+ llvm::Module &M = getModule();
+ for (llvm::Function &F : M.functions())
+ finalizeRISCVZicfilpFuncSigLabel(F);
+}
+
+void CodeGenModule::finalizeRISCVZicfilpFuncSigLabel(llvm::Function &F) {
+ const unsigned MDKindID = F.getContext().getMDKindID("riscv_lpad_label");
+ if (!F.hasAddressTaken() && F.hasLocalLinkage()) {
+ F.eraseMetadata(MDKindID);
+ return;
+ }
+
+ const llvm::MDNode *MD = F.getMetadata(MDKindID);
+ if (!MD) {
+ GlobalDecl GD;
+ if (!lookupRepresentativeDecl(F.getName(), GD))
+ return;
+
+ setRISCVZicfilpFuncSigLabel(cast<FunctionDecl>(GD.getDecl()), &F);
+ }
+}
+
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
bool IsIncompleteFunction,
bool IsThunk) {
@@ -2962,6 +3043,9 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
setKCFIType(FD, F);
+ if (UseRISCVZicfilpFuncSigCFI)
+ setRISCVZicfilpFuncSigLabel(FD, F);
+
if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
getOpenMPRuntime().emitDeclareSimdFunction(FD, F);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index c58bb88035ca8a..a24c92dd2ba546 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1556,9 +1556,26 @@ class CodeGenModule : public CodeGenTypeCache {
/// Set type metadata to the given function.
void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
+ /// Set RISC-V Zicfilp func-sig CFI label in metadata of the given function.
+ void setRISCVZicfilpFuncSigLabel(const FunctionDecl *FD, llvm::Function *F);
+
/// Emit KCFI type identifier constants and remove unused identifiers.
void finalizeKCFITypes();
+ /// Fixup RISCV Zicfilp func-sig CFI labels
+ void finalizeRISCVZicfilpFuncSigLabels();
+
+ /// Fixup RISCV Zicfilp func-sig CFI label for llvm::Function
+ void finalizeRISCVZicfilpFuncSigLabel(llvm::Function &F);
+
+ /// Calculate RISC-V Zicfilp func-sig scheme CFI label
+ uint32_t calcRISCVZicfilpFuncSigLabel(const FunctionType &FT,
+ const bool IsCXXInstanceMethod,
+ const bool IsCXXVirtualMethod);
+
+ /// Calculate RISC-V Zicfilp func-sig scheme CFI label
+ uint32_t calcRISCVZicfilpFuncSigLabel(const FunctionDecl &FD);
+
/// Whether this function's return type has no side effects, and thus may
/// be trivially discarded if it is unused.
bool MayDropFunctionReturn(const ASTContext &Context,
@@ -1676,6 +1693,8 @@ class CodeGenModule : public CodeGenTypeCache {
MustTailCallUndefinedGlobals.insert(Global);
}
+ bool UseRISCVZicfilpFuncSigCFI;
+
private:
bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const;
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp
new file mode 100644
index 00000000000000..f536acbf867b85
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-covariant-virtual-method.cpp
@@ -0,0 +1,33 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s --check-prefixes=PTR,LREF,RREF
+
+class Class {
+public:
+ // test - virtual methods with return type that can possibly be covariant
+ // mangle return class as `class v`
+ // PTR-LABEL: define{{.*}} @_ZN5Class35virtualMethodWithCovariantPtrReturnEv
+ // PTR-SAME: ({{.*}}){{.* !riscv_lpad_label}} [[MD_PTR:![0-9]+]] {{.*}}{
+ //
+ virtual Class *virtualMethodWithCovariantPtrReturn() { return this; }
+
+ // LREF-LABEL: define{{.*}} @_ZN5Class36virtualMethodWithCovariantLRefReturnEv
+ // LREF-SAME: ({{.*}}){{.* !riscv_lpad_label}} [[MD_LREF:![0-9]+]] {{.*}}{
+ //
+ virtual Class &virtualMethodWithCovariantLRefReturn() { return *this; }
+
+ // RREF-LABEL: define{{.*}} @_ZN5Class36virtualMethodWithCovariantRRefReturnEv
+ // RREF-SAME: ({{.*}}){{.* !riscv_lpad_label}} [[MD_RREF:![0-9]+]] {{.*}}{
+ //
+ virtual Class &&virtualMethodWithCovariantRRefReturn() {
+ return static_cast<Class&&>(*this);
+ }
+};
+
+// PTR-DAG: [[MD_PTR]] = !{i32 996333}
+// LREF-DAG: [[MD_LREF]] = !{i32 918198}
+// RREF-DAG: [[MD_RREF]] = !{i32 86168}
+
+void use() { Class C; }
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.cpp
new file mode 100644
index 00000000000000..196bb69c2f61ac
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-destructor.cpp
@@ -0,0 +1,17 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+
+class Class {
+public:
+ // test - destructors should use `void (*)(void*)`
+ // CHECK-LABEL: define{{.*}} @_ZN5ClassD1Ev({{.*}})
+ // CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+ // CHECK: [[MD]] = !{i32 408002}
+ //
+ ~Class() {}
+};
+
+void use() { Class C; }
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp
new file mode 100644
index 00000000000000..9ff4a83046fb72
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-incovariant-virtual-method.cpp
@@ -0,0 +1,18 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+
+class Class {
+public:
+ // test - virtual methods with return type that cannot be covariant mangle
+ // return type as it is declared
+ // CHECK-LABEL: define{{.*}} @_ZN5Class34virtualMethodWithIncovariantReturnEv
+ // CHECK-SAME: ({{.*}}){{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+ // CHECK: [[MD]] = !{i32 910118}
+ //
+ virtual int virtualMethodWithIncovariantReturn() { return 0; }
+};
+
+void use() { Class C; }
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp
new file mode 100644
index 00000000000000..8e335b838b5df1
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-method.cpp
@@ -0,0 +1,18 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+
+class Class {
+public:
+ // test - C++ member functions should use "pointer-to-member" types, with
+ // `<class type>` being `1v` (i.e. using a dummy class named `v`)
+ // CHECK-LABEL: define{{.*}} @_ZN5Class14instanceMethodEv({{.*}})
+ // CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+ // CHECK: [[MD]] = !{i32 974748}
+ //
+ void instanceMethod() {}
+};
+
+void use(Class &C) { C.instanceMethod(); }
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-method.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-method.cpp
new file mode 100644
index 00000000000000..d1bf9914e84a9b
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-class-static-method.cpp
@@ -0,0 +1,21 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+
+// CHECK-LABEL: define{{.*}} @_Z13nonMemberFuncv()
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+//
+void nonMemberFunc() {}
+
+class Class {
+public:
+ // test - static methods are mangled as non-member function
+ // CHECK-LABEL: define{{.*}} @_ZN5Class12staticMethodEv()
+ // CHECK-SAME: {{.* !riscv_lpad_label}} [[MD]] {{.*}}{
+ //
+ static void staticMethod() {}
+};
+
+void use() { Class::staticMethod(); }
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c
new file mode 100644
index 00000000000000..3a122acb600493
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.c
@@ -0,0 +1,15 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c %s \
+// RUN: | FileCheck %s
+
+// test - functions with an empty parameter list are treated as `void (*)(void)`
+// CHECK-LABEL: define{{.*}} @funcWithEmptyParameterList()
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+//
+void funcWithEmptyParameterList() {}
+// CHECK-LABEL: define{{.*}} @funcWithVoidParameterList()
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD]] {{.*}}{
+//
+void funcWithVoidParameterList(void) {}
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp
new file mode 100644
index 00000000000000..561889057f2d5b
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-func-empty-param-list.cpp
@@ -0,0 +1,15 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+
+// test - functions with an empty parameter list are treated as `void (*)(void)`
+// CHECK-LABEL: define{{.*}} @_Z26funcWithEmptyParameterListv()
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+//
+void funcWithEmptyParameterList() {}
+// CHECK-LABEL: define{{.*}} @_Z25funcWithVoidParameterListv()
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD]] {{.*}}{
+//
+void funcWithVoidParameterList(void) {}
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp
new file mode 100644
index 00000000000000..921fcfbb9c08de
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-ignore-exception-spec.cpp
@@ -0,0 +1,15 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -fcxx-exceptions -fexceptions \
+// RUN: -emit-llvm -o - -x c++ %s | FileCheck %s
+
+// test - `<exception-spec>` should be ignored
+// CHECK-LABEL: define{{.*}} @_Z9funcThrowv()
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+///
+void funcThrow() { throw 0; }
+// CHECK-LABEL: define{{.*}} @_Z12funcNoExceptv()
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD]] {{.*}}{
+//
+void funcNoExcept() noexcept {}
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp
new file mode 100644
index 00000000000000..1a8cc4b5723c67
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-main.cpp
@@ -0,0 +1,39 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -DNO_PARAM -triple riscv64 -target-cpu generic-rv64 \
+// RUN: -target-feature +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -DONE_PARAM -triple riscv64 -target-cpu generic-rv64 \
+// RUN: -target-feature +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -DTWO_PARAMS -triple riscv64 -target-cpu generic-rv64 \
+// RUN: -target-feature +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -DTWO_PARAMS -triple riscv64 -target-cpu generic-rv64 \
+// RUN: -target-feature +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+
+// test - main functions should use `int (*)(int, char**)`
+// CHECK-LABEL: define{{.*}} @main({{.*}})
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+// CHECK: [[MD]] = !{i32 853561}
+//
+
+#ifdef NO_PARAM
+int main() { return 0; }
+#endif
+
+#ifdef ONE_PARAM
+int main(int argc) { return argc; }
+#endif
+
+#ifdef TWO_PARAMS
+int main(int argc, char **argv) { return argc; }
+#endif
+
+#ifdef THREE_PARAMS
+int main(int argc, char **argv, char **envp) { return argc; }
+#endif
diff --git a/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp
new file mode 100644
index 00000000000000..14de1b7bbfdda9
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/zicfilp-func-sig/mangle-wchar-t.cpp
@@ -0,0 +1,12 @@
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -target-cpu generic-rv64 -target-feature \
+// RUN: +experimental-zicfilp -fcf-protection=branch \
+// RUN: -mcf-branch-label-scheme=func-sig -emit-llvm -o - -x c++ %s \
+// RUN: | FileCheck %s
+
+// test - `wchar_t` in C++ should be mangled to `wchar_t` in C
+// CHECK-LABEL: define{{.*}} @_Z14funcWithWCharTw({{.*}})
+// CHECK-SAME: {{.* !riscv_lpad_label}} [[MD:![0-9]+]] {{.*}}{
+// CHECK: [[MD]] = !{i32 374765}
+//
+void funcWithWCharT(wchar_t) {}
diff --git a/llvm/include/llvm/Support/RISCVISAUtils.h b/llvm/include/llvm/Support/RISCVISAUtils.h
index 77f8c3e45f1ab5..b569184fddff0a 100644
--- a/llvm/include/llvm/Support/RISCVISAUtils.h
+++ b/llvm/include/llvm/Support/RISCVISAUtils.h
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
-// Utilities shared by TableGen and RISCVISAInfo.
+// Utilities shared by TableGen, RISCVISAInfo and other RISC-V specifics.
//
//===----------------------------------------------------------------------===//
@@ -42,6 +42,10 @@ struct ExtensionComparator {
typedef std::map<std::string, ExtensionVersion, ExtensionComparator>
OrderedExtensionMap;
+/// Obtain a 20-bit integer from a (function-signature) string using the method
+/// defined in the psABI for Zicfilp func-sig CFI scheme
+uint32_t zicfilpFuncSigHash(const StringRef FuncSig);
+
} // namespace RISCVISAUtils
} // namespace llvm
diff --git a/llvm/lib/Support/RISCVISAUtils.cpp b/llvm/lib/Support/RISCVISAUtils.cpp
index d6b002e66e7ab2..386fb157ecdee4 100644
--- a/llvm/lib/Support/RISCVISAUtils.cpp
+++ b/llvm/lib/Support/RISCVISAUtils.cpp
@@ -6,12 +6,13 @@
//
//===----------------------------------------------------------------------===//
//
-// Utilities shared by TableGen and RISCVISAInfo.
+// Utilities shared by TableGen, RISCVISAInfo and other RISC-V specifics.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/RISCVISAUtils.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MD5.h"
#include <cassert>
using namespace llvm;
@@ -90,3 +91,22 @@ bool llvm::RISCVISAUtils::compareExtension(const std::string &LHS,
// If the rank is same, it must be sorted by lexicographic order.
return LHS < RHS;
}
+
+uint32_t llvm::RISCVISAUtils::zicfilpFuncSigHash(const StringRef FuncSig) {
+ const llvm::MD5::MD5Result MD5Result =
+ llvm::MD5::hash({(const uint8_t *)FuncSig.data(), FuncSig.size()});
+
+ uint64_t MD5High = MD5Result.high();
+ uint64_t MD5Low = MD5Result.low();
+ while (MD5High && MD5Low) {
+ const uint32_t Low20Bits = MD5Low & 0xFFFFFULL;
+ if (Low20Bits)
+ return Low20Bits;
+
+ // Logical right shift MD5 result by 20 bits
+ MD5Low = (MD5High & 0xFFFFF) << 44 | MD5Low >> 20;
+ MD5High >>= 20;
+ }
+
+ return llvm::MD5Hash("RISC-V") & 0xFFFFFULL;
+}
More information about the cfe-commits
mailing list