Skip to content

Commit ea2aa89

Browse files
committed
[clang][RISCV] Introduce CodeGenModule::calcRISCVZicfilpFuncSigLabel()
This method 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).
1 parent 6004f55 commit ea2aa89

File tree

6 files changed

+211
-2
lines changed

6 files changed

+211
-2
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,6 +1876,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
18761876
/// (struct/union/class/enum) decl.
18771877
QualType getTagDeclType(const TagDecl *Decl) const;
18781878

1879+
/// Return the type for "void *"
1880+
QualType getVoidPtrType() const { return VoidPtrTy; }
1881+
18791882
/// Return the unique type for "size_t" (C99 7.17), defined in
18801883
/// <stddef.h>.
18811884
///
@@ -1903,6 +1906,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
19031906
/// defined in <stddef.h> as defined by the target.
19041907
QualType getWideCharType() const { return WideCharTy; }
19051908

1909+
/// Return the type of wide characters in C context, no matter whether it's C
1910+
/// or C++ being compiled.
1911+
QualType getWCharTypeInC() const;
1912+
19061913
/// Return the type of "signed wchar_t".
19071914
///
19081915
/// Used when in C++, as a GCC extension.

clang/include/clang/AST/Mangle.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ class ItaniumMangleContext : public MangleContext {
212212

213213
virtual void mangleModuleInitializer(const Module *Module, raw_ostream &) = 0;
214214

215+
virtual void mangleForRISCVZicfilpFuncSigLabel(const FunctionType &FT,
216+
const bool IsCXXInstanceMethod,
217+
const bool IsCXXVirtualMethod,
218+
raw_ostream &) = 0;
219+
215220
// This has to live here, otherwise the CXXNameMangler won't have access to
216221
// it.
217222
virtual DiscriminatorOverrideTy getDiscriminatorOverride() const = 0;

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6442,6 +6442,12 @@ CanQualType ASTContext::getUIntMaxType() const {
64426442
return getFromTargetType(Target->getUIntMaxType());
64436443
}
64446444

6445+
/// Return the type of wide characters in C context, no matter whether it's C
6446+
/// or C++ being compiled.
6447+
QualType ASTContext::getWCharTypeInC() const {
6448+
return getFromTargetType(Target->getWCharType());
6449+
}
6450+
64456451
/// getSignedWCharType - Return the type of "signed wchar_t".
64466452
/// Used when in C++, as a GCC extension.
64476453
QualType ASTContext::getSignedWCharType() const {

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ using namespace clang;
4343

4444
namespace {
4545

46+
static bool mayBeCovariant(const Type &Ty) {
47+
if (auto *const PT = Ty.getAs<PointerType>())
48+
return PT->getPointeeType()->isStructureOrClassType();
49+
if (auto *const RT = Ty.getAs<ReferenceType>())
50+
return RT->getPointeeType()->isStructureOrClassType();
51+
return false;
52+
}
53+
4654
static bool isLocalContainerContext(const DeclContext *DC) {
4755
return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || isa<BlockDecl>(DC);
4856
}
@@ -136,6 +144,11 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
136144

137145
void mangleModuleInitializer(const Module *Module, raw_ostream &) override;
138146

147+
void mangleForRISCVZicfilpFuncSigLabel(const FunctionType &,
148+
const bool IsCXXInstanceMethod,
149+
const bool IsCXXVirtualMethod,
150+
raw_ostream &) override;
151+
139152
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
140153
// Lambda closure types are already numbered.
141154
if (isLambda(ND))
@@ -395,8 +408,10 @@ class CXXNameMangler {
395408
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
396409
llvm::DenseMap<StringRef, unsigned> ModuleSubstitutions;
397410

411+
protected:
398412
ASTContext &getASTContext() const { return Context.getASTContext(); }
399413

414+
private:
400415
bool isCompatibleWith(LangOptions::ClangABI Ver) {
401416
return Context.getASTContext().getLangOpts().getClangABICompat() <= Ver;
402417
}
@@ -443,6 +458,8 @@ class CXXNameMangler {
443458
NullOut = true;
444459
}
445460

461+
virtual ~CXXNameMangler() = default;
462+
446463
struct WithTemplateDepthOffset { unsigned Offset; };
447464
CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
448465
WithTemplateDepthOffset Offset)
@@ -559,9 +576,12 @@ class CXXNameMangler {
559576
StringRef Prefix = "");
560577
void mangleOperatorName(DeclarationName Name, unsigned Arity);
561578
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
579+
580+
protected:
562581
void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr);
563582
void mangleRefQualifier(RefQualifierKind RefQualifier);
564583

584+
private:
565585
void mangleObjCMethodName(const ObjCMethodDecl *MD);
566586

567587
// Declare manglers for every type class.
@@ -572,11 +592,24 @@ class CXXNameMangler {
572592

573593
void mangleType(const TagType*);
574594
void mangleType(TemplateName);
595+
596+
protected:
597+
// Use the `Impl` scheme instead of directly virtualizing `mangleType`s since
598+
// `mangleType`s are declared by tables
599+
virtual void mangleTypeImpl(const BuiltinType *T);
600+
virtual void mangleTypeImpl(const FunctionProtoType *T);
601+
virtual void mangleTypeImpl(const FunctionNoProtoType *T);
602+
603+
private:
575604
static StringRef getCallingConvQualifierName(CallingConv CC);
576605
void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
577606
void mangleExtFunctionInfo(const FunctionType *T);
607+
608+
protected:
578609
void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType,
579610
const FunctionDecl *FD = nullptr);
611+
612+
private:
580613
void mangleNeonVectorType(const VectorType *T);
581614
void mangleNeonVectorType(const DependentVectorType *T);
582615
void mangleAArch64NeonVectorType(const VectorType *T);
@@ -3058,7 +3091,9 @@ void CXXNameMangler::mangleCXXRecordDecl(const CXXRecordDecl *Record) {
30583091
addSubstitution(Record);
30593092
}
30603093

3061-
void CXXNameMangler::mangleType(const BuiltinType *T) {
3094+
void CXXNameMangler::mangleType(const BuiltinType *T) { mangleTypeImpl(T); }
3095+
3096+
void CXXNameMangler::mangleTypeImpl(const BuiltinType *T) {
30623097
// <type> ::= <builtin-type>
30633098
// <builtin-type> ::= v # void
30643099
// ::= w # wchar_t
@@ -3563,10 +3598,14 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
35633598
mangleVendorQualifier("noescape");
35643599
}
35653600

3601+
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
3602+
return mangleTypeImpl(T);
3603+
}
3604+
35663605
// <type> ::= <function-type>
35673606
// <function-type> ::= [<CV-qualifiers>] F [Y]
35683607
// <bare-function-type> [<ref-qualifier>] E
3569-
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
3608+
void CXXNameMangler::mangleTypeImpl(const FunctionProtoType *T) {
35703609
mangleExtFunctionInfo(T);
35713610

35723611
// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
@@ -3604,6 +3643,10 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
36043643
}
36053644

36063645
void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
3646+
return mangleTypeImpl(T);
3647+
}
3648+
3649+
void CXXNameMangler::mangleTypeImpl(const FunctionNoProtoType *T) {
36073650
// Function types without prototypes can arise when mangling a function type
36083651
// within an overloadable function in C. We mangle these as the absence of any
36093652
// parameter types (not even an empty parameter list).
@@ -7074,6 +7117,85 @@ bool CXXNameMangler::shouldHaveAbiTags(ItaniumMangleContextImpl &C,
70747117
return TrackAbiTags.AbiTagsRoot.getUsedAbiTags().size();
70757118
}
70767119

7120+
namespace {
7121+
7122+
class RISCVZicfilpFuncSigLabelMangler : public CXXNameMangler {
7123+
bool IsTopLevelAndCXXVirtualMethod;
7124+
7125+
public:
7126+
RISCVZicfilpFuncSigLabelMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
7127+
const bool IsCXXVirtualMethod)
7128+
: CXXNameMangler(C, Out),
7129+
IsTopLevelAndCXXVirtualMethod(/*IsTopLevel=*/true &&
7130+
IsCXXVirtualMethod) {}
7131+
7132+
void mangleTypeImpl(const BuiltinType *T) override {
7133+
if (T->getKind() == BuiltinType::WChar_S ||
7134+
T->getKind() == BuiltinType::WChar_U) {
7135+
const Type *const OverrideT =
7136+
getASTContext().getWCharTypeInC().getTypePtr();
7137+
assert(isa<BuiltinType>(OverrideT) &&
7138+
"`wchar_t' in C is expected to be defined to a built-in type");
7139+
T = static_cast<const BuiltinType *>(OverrideT);
7140+
}
7141+
return CXXNameMangler::mangleTypeImpl(T);
7142+
}
7143+
7144+
// This <function-type> is the RISC-V psABI modified version
7145+
// <function-type> ::= [<CV-qualifiers>] [Dx] F <bare-function-type>
7146+
// [<ref-qualifier>] E
7147+
void mangleTypeImpl(const FunctionProtoType *T) override {
7148+
// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
7149+
// e.g. "const" in "int (A::*)() const".
7150+
mangleQualifiers(T->getMethodQuals());
7151+
7152+
getStream() << 'F';
7153+
7154+
bool MangleReturnType = true;
7155+
if (const Type &RetT = *T->getReturnType().getTypePtr();
7156+
IsTopLevelAndCXXVirtualMethod && mayBeCovariant(RetT)) {
7157+
// Possible covariant types mangle dummy cv-unqualified `class v` as its
7158+
// class type
7159+
if (RetT.isPointerType())
7160+
getStream() << "P1v";
7161+
else if (RetT.isLValueReferenceType())
7162+
getStream() << "R1v";
7163+
else {
7164+
assert(RetT.isRValueReferenceType() &&
7165+
"Expect an r-value ref for covariant return type that is not a "
7166+
"pointer or an l-value ref");
7167+
getStream() << "O1v";
7168+
}
7169+
7170+
IsTopLevelAndCXXVirtualMethod = false; // Not top-level anymore
7171+
MangleReturnType = false;
7172+
}
7173+
mangleBareFunctionType(T, MangleReturnType);
7174+
7175+
// Mangle the ref-qualifier, if present.
7176+
mangleRefQualifier(T->getRefQualifier());
7177+
7178+
getStream() << 'E';
7179+
}
7180+
7181+
void mangleTypeImpl(const FunctionNoProtoType *T) override {
7182+
return CXXNameMangler::mangleTypeImpl(toFunctionProtoType(T));
7183+
}
7184+
7185+
private:
7186+
const FunctionProtoType *
7187+
toFunctionProtoType(const FunctionNoProtoType *const T) {
7188+
FunctionProtoType::ExtProtoInfo EPI;
7189+
EPI.ExtInfo = T->getExtInfo();
7190+
const Type *const NewT = getASTContext()
7191+
.getFunctionType(T->getReturnType(), {}, EPI)
7192+
.getTypePtr();
7193+
return static_cast<const FunctionProtoType *>(NewT);
7194+
}
7195+
}; // class RISCVZicfilpFuncSigLabelMangler
7196+
7197+
} // anonymous namespace
7198+
70777199
//
70787200

70797201
/// Mangles the name of the declaration D and emits that name to the given
@@ -7412,6 +7534,17 @@ void ItaniumMangleContextImpl::mangleModuleInitializer(const Module *M,
74127534
}
74137535
}
74147536

7537+
void ItaniumMangleContextImpl::mangleForRISCVZicfilpFuncSigLabel(
7538+
const FunctionType &FT, const bool IsCXXInstanceMethod,
7539+
const bool IsCXXVirtualMethod, raw_ostream &Out) {
7540+
if (IsCXXInstanceMethod)
7541+
// member methods uses a dummy class named `v` in place of real classes
7542+
Out << "M1v";
7543+
7544+
RISCVZicfilpFuncSigLabelMangler Mangler(*this, Out, IsCXXVirtualMethod);
7545+
Mangler.mangleType(QualType(&FT, 0));
7546+
}
7547+
74157548
ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context,
74167549
DiagnosticsEngine &Diags,
74177550
bool IsAux) {

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2829,6 +2829,56 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
28292829
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
28302830
}
28312831

2832+
uint32_t
2833+
CodeGenModule::calcRISCVZicfilpFuncSigLabel(const FunctionType &FT,
2834+
const bool IsCXXInstanceMethod,
2835+
const bool IsCXXVirtualMethod) {
2836+
std::string OutName;
2837+
llvm::raw_string_ostream Out(OutName);
2838+
MangleContext &MC = getCXXABI().getMangleContext();
2839+
cast<ItaniumMangleContext>(MC).mangleForRISCVZicfilpFuncSigLabel(
2840+
FT, IsCXXInstanceMethod, IsCXXVirtualMethod, Out);
2841+
2842+
const llvm::MD5::MD5Result MD5Result =
2843+
llvm::MD5::hash({(const uint8_t *)OutName.data(), OutName.size()});
2844+
2845+
// Take 20 bits of MD5 result with the approach specified by psABI
2846+
uint64_t MD5High = MD5Result.high();
2847+
uint64_t MD5Low = MD5Result.low();
2848+
while (MD5High && MD5Low) {
2849+
const uint32_t Low20Bits = MD5Low & 0xFFFFFULL;
2850+
if (Low20Bits)
2851+
return Low20Bits;
2852+
2853+
// Logical right shift MD5 result by 20 bits
2854+
MD5Low = (MD5High & 0xFFFFF) << 44 | MD5Low >> 20;
2855+
MD5High >>= 20;
2856+
}
2857+
2858+
return llvm::MD5Hash("RISC-V") & 0xFFFFFULL;
2859+
}
2860+
2861+
uint32_t CodeGenModule::calcRISCVZicfilpFuncSigLabel(const FunctionDecl &FD) {
2862+
if (FD.isMain())
2863+
// All main functions use `int main(int, char**)` for label calculation
2864+
// according to psABI spec. This value is the pre-calculated label.
2865+
return 0xd0639;
2866+
2867+
if (isa<CXXDestructorDecl>(FD))
2868+
// All destructors use `void (void*)` for label calculation according to the
2869+
// psABI spec. This value is the pre-calculated label.
2870+
return 0x639c2;
2871+
2872+
bool IsCXXInstanceMethod = false;
2873+
bool IsCXXVirtualMethod = false;
2874+
if (const auto *const MD = dyn_cast<CXXMethodDecl>(&FD)) {
2875+
IsCXXInstanceMethod = MD->isInstance();
2876+
IsCXXVirtualMethod = MD->isVirtual();
2877+
}
2878+
return calcRISCVZicfilpFuncSigLabel(*FD.getFunctionType(),
2879+
IsCXXInstanceMethod, IsCXXVirtualMethod);
2880+
}
2881+
28322882
void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
28332883
llvm::LLVMContext &Ctx = F->getContext();
28342884
llvm::MDBuilder MDB(Ctx);

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,14 @@ class CodeGenModule : public CodeGenTypeCache {
15591559
/// Emit KCFI type identifier constants and remove unused identifiers.
15601560
void finalizeKCFITypes();
15611561

1562+
/// Calculate RISC-V Zicfilp func-sig scheme CFI label
1563+
uint32_t calcRISCVZicfilpFuncSigLabel(const FunctionType &FT,
1564+
const bool IsCXXInstanceMethod,
1565+
const bool IsCXXVirtualMethod);
1566+
1567+
/// Calculate RISC-V Zicfilp func-sig scheme CFI label
1568+
uint32_t calcRISCVZicfilpFuncSigLabel(const FunctionDecl &FD);
1569+
15621570
/// Whether this function's return type has no side effects, and thus may
15631571
/// be trivially discarded if it is unused.
15641572
bool MayDropFunctionReturn(const ASTContext &Context,

0 commit comments

Comments
 (0)