diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 68f0841c51bddbf8637506bdc4e41af65f3cf6d0..3c11f7ba85aef736d5658f868331ea041403e296 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1742,6 +1742,22 @@ def NoUniqueAddress : InheritableAttr, TargetSpecificAttr { let SimpleHandler = 1; } +// OHOS_LOCAL start +def PacDataTag : InheritableAttr { + let Spellings = [GCC<"pac_protected_data">]; + let Subjects = SubjectList<[Field], ErrorDiag>; + let Documentation = [PacDataTagDocs]; + let SimpleHandler = 1; +} + +def PacPtrTag : InheritableAttr { + let Spellings = [GCC<"pac_protected_ptr">]; + let Subjects = SubjectList<[Field], ErrorDiag>; + let Documentation = [PacPtrTagDocs]; + let SimpleHandler = 1; +} +// OHOS_LOCAL end + def ReturnsTwice : InheritableAttr { let Spellings = [GCC<"returns_twice">]; let Subjects = SubjectList<[Function]>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 5c84e2fc5b77d1a20831f977b7b779bdb19017ee..ff9a7c5bc84a138c9f1fe06f6570baeca7134d81 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -513,16 +513,16 @@ def NoMergeDocs : Documentation { let Category = DocCatStmt; let Content = [{ If a statement is marked ``nomerge`` and contains call expressions, those call -expressions inside the statement will not be merged during optimization. This +expressions inside the statement will not be merged during optimization. This attribute can be used to prevent the optimizer from obscuring the source location of certain calls. For example, it will prevent tail merging otherwise identical code sequences that raise an exception or terminate the program. Tail merging normally reduces the precision of source location information, making stack traces less useful for debugging. This attribute gives the user control -over the tradeoff between code size and debug information precision. +over the tradeoff between code size and debug information precision. -``nomerge`` attribute can also be used as function attribute to prevent all -calls to the specified function from merging. It has no effect on indirect +``nomerge`` attribute can also be used as function attribute to prevent all +calls to the specified function from merging. It has no effect on indirect calls. }]; } @@ -1355,6 +1355,22 @@ in C++11 onwards. }]; } +// OHOS_LOCAL start +def PacDataTagDocs : Documentation { + let Category = DocCatField; + let Content = [{ +The ``pac_protected_data`` attribute asks the compiler to protect the struct field with PA + }]; +} + +def PacPtrTagDocs : Documentation { + let Category = DocCatField; + let Content = [{ +The ``pac_protected_ptr`` attribute asks the compiler to protect the struct pointer type field with PA + }]; +} +// OHOS_LOCAL end + def ObjCRequiresSuperDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -1555,7 +1571,7 @@ attributes are ignored. Supported platforms are: ``watchos`` Apple's watchOS operating system. The minimum deployment target is specified by the ``-mwatchos-version-min=*version*`` command-line argument. - + ``driverkit`` Apple's DriverKit userspace kernel extensions. The minimum deployment target is specified as part of the triple. @@ -3816,7 +3832,7 @@ Whether a particular pointer may be "null" is an important concern when working with pointers in the C family of languages. The various nullability attributes indicate whether a particular pointer can be null or not, which makes APIs more expressive and can help static analysis tools identify bugs involving null -pointers. Clang supports several kinds of nullability attributes: the +pointers. Clang supports several kinds of nullability attributes: the ``nonnull`` and ``returns_nonnull`` attributes indicate which function or method parameters and result types can never be null, while nullability type qualifiers indicate which pointer types can be null (``_Nullable``) or cannot @@ -3992,7 +4008,7 @@ memory is not available rather than returning a null pointer: The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner -(because it is part of the type system) and does not imply undefined behavior, +(because it is part of the type system) and does not imply undefined behavior, making it more widely applicable }]; } @@ -5893,15 +5909,15 @@ def CFGuardDocs : Documentation { let Content = [{ Code can indicate CFG checks are not wanted with the ``__declspec(guard(nocf))`` attribute. This directs the compiler to not insert any CFG checks for the entire -function. This approach is typically used only sparingly in specific situations -where the programmer has manually inserted "CFG-equivalent" protection. The -programmer knows that they are calling through some read-only function table -whose address is obtained through read-only memory references and for which the -index is masked to the function table limit. This approach may also be applied -to small wrapper functions that are not inlined and that do nothing more than -make a call through a function pointer. Since incorrect usage of this directive -can compromise the security of CFG, the programmer must be very careful using -the directive. Typically, this usage is limited to very small functions that +function. This approach is typically used only sparingly in specific situations +where the programmer has manually inserted "CFG-equivalent" protection. The +programmer knows that they are calling through some read-only function table +whose address is obtained through read-only memory references and for which the +index is masked to the function table limit. This approach may also be applied +to small wrapper functions that are not inlined and that do nothing more than +make a call through a function pointer. Since incorrect usage of this directive +can compromise the security of CFG, the programmer must be very careful using +the directive. Typically, this usage is limited to very small functions that only call one function. `Control Flow Guard documentation ` diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 18adb21e2be08530974a275e723a3284a1c5a1a9..037e29a5155f78395a64bf176e969dbc59a6d608 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -539,7 +539,7 @@ def err_invalid_operator_on_type : Error< def err_expected_unqualified_id : Error< "expected %select{identifier|unqualified-id}0">; def err_while_loop_outside_of_a_function : Error< - "while loop outside of a function">; + "while loop outside of a function">; def err_brackets_go_after_unqualified_id : Error< "brackets are not allowed here; to declare an array, " "place the brackets after the %select{identifier|name}0">; @@ -1610,4 +1610,9 @@ def ext_hlsl_access_specifiers : ExtWarn< "access specifiers are a clang HLSL extension">, InGroup; +// OHOS_LOCAL start +def warn_unsupported_pac_dfi_type : Warning< + "unsupported type %0 for attribute '%1'">; +// OHOS_LOCAL end + } // end of Parser diagnostics diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 84fc0893c8b59d9e237ef0b6dd5cb98c1560442c..47e4c2754dd05865e4a055a17d892090cf839325 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -434,6 +434,8 @@ KEYWORD(__builtin_LINE , KEYALL) KEYWORD(__builtin_COLUMN , KEYALL) KEYWORD(__builtin_source_location , KEYCXX) +UNARY_EXPR_OR_TYPE_TRAIT(__builtin_get_modifier_bytype, PacModifierByType, KEYALL) // OHOS_LOCAL + // __builtin_types_compatible_p is a GNU C extension that we handle like a C++ // type trait. TYPE_TRAIT_2(__builtin_types_compatible_p, TypeCompatible, KEYNOCXX) diff --git a/clang/include/clang/Pac/PacDfi.h b/clang/include/clang/Pac/PacDfi.h new file mode 100644 index 0000000000000000000000000000000000000000..0d028417cdcc56b218a139d0674719d19dc26a2f --- /dev/null +++ b/clang/include/clang/Pac/PacDfi.h @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Zaheer Gauhar +// Gilang Mentari Hamidy +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef PAC_DFI_H +#define PAC_DFI_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Decl.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Module.h" +#include "clang/CodeGen/CodeGenABITypes.h" +using namespace clang; + +void PacDfiParseStruct(RecordDecl *TagDecl, ASTContext &Ctx, DiagnosticsEngine &Diags); +void PacDfiEmitStructFieldsMetadata(llvm::Module &M, llvm::LLVMContext &VMContext, CodeGen::CodeGenModule *CGM); +void PacDfiRecordDecl2StructName(const RecordDecl *RD, llvm::StructType *Entry); + +#endif + diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9d92c848ccb841a8c07bcd2891cad45b200b80da..d22135079fa636dde8244b034b16b13de0c87d72 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -13280,6 +13280,15 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( return false; return Success(Sizeof, E); } + // OHOS_LOCAL Begin + case UETT_PacModifierByType: { + QualType FuncTy = E->getTypeOfArgument(); + if (!FuncTy->isFunctionType()) { + return false; + } + return Success(0, E); + } + // OHOS_LOCAL End case UETT_OpenMPRequiredSimdAlign: assert(E->isArgumentType()); return Success( diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 91f41778ee68fce0f287f488859127b8f2ca685b..b1091945d85f076b841a6bea73e8193344fe6ed9 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4691,6 +4691,11 @@ recurse: Diags.Report(DiagID); return; } + // OHOS_LOCAL Begin + case UETT_PacModifierByType: { + return; + } + // OHOS_LOCAL End } break; } diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt index 1526d65795f8adfe258f15e8ac75d4903dd48f67..71fa062db5234b7515965e0810ba059fbc0892d1 100644 --- a/clang/lib/CMakeLists.txt +++ b/clang/lib/CMakeLists.txt @@ -30,3 +30,4 @@ if(CLANG_INCLUDE_TESTS) endif() add_subdirectory(Interpreter) add_subdirectory(Support) +add_subdirectory(Pac) # OHOS_LOCAL diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index b150aaa376eb081378cbaf72222666d4f4497303..747bb00dee299edb487a428b75bcb97186adb84f 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -42,6 +42,7 @@ #include "llvm/IR/MatrixBuilder.h" #include "llvm/IR/Module.h" #include "llvm/Support/TypeSize.h" +#include "llvm/PARTS/Parts.h" // OHOS_LOCAL #include using namespace clang; @@ -2999,7 +3000,16 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( E->getTypeOfArgument()->getPointeeType())) .getQuantity(); return llvm::ConstantInt::get(CGF.SizeTy, Alignment); + // OHOS_LOCAL Begin + } else if (E->getKind() == clang::UETT_PacModifierByType) { + auto ArgTy = E->getTypeOfArgument(); + auto *FuncTy = ConvertType(ArgTy); + if (!FuncTy) { + return llvm::ConstantInt::get(CGF.Int64Ty, 0); + } + return llvm::ConstantInt::get(CGF.Int64Ty, llvm::PARTS::getTypeIdFor(FuncTy)); } + // OHOS_LOCAL End // If this isn't sizeof(vla), the result must be constant; use the constant // folding logic so we don't have to duplicate it here. diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 0bb5abcf60455b08b9cb845ec14ecc41a2e7c06a..60a45250389dddbac9e2f41e0ff52923c7aa1c6c 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -96,4 +96,5 @@ add_clang_library(clangCodeGen clangFrontend clangLex clangSerialization + pacDfi # OHOS_LOCAL ) diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c67643c43a7d1d13591bb3ea8c47711bab317b47..6e61a85771d46cf2b310e7ac4d043fae33a36a9b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -47,6 +47,9 @@ #include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/ConstantInitBuilder.h" #include "clang/Frontend/FrontendDiagnostic.h" +// OHOS_LOCAL start +#include "clang/Pac/PacDfi.h" +// OHOS_LOCAL end #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -835,6 +838,7 @@ void CodeGenModule::Release() { if (getLangOpts().OpenMPIsDevice) getModule().addModuleFlag(llvm::Module::Max, "openmp-device", LangOpts.OpenMP); + PacDfiEmitStructFieldsMetadata(getModule(), VMContext, this); // OHOS_LOCAL // Emit OpenCL specific module metadata: OpenCL/SPIR version. if (LangOpts.OpenCL || (LangOpts.CUDAIsDevice && getTriple().isSPIRV())) { diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index fcce424747f1c3245c5b8d7e269b65f7e27771ea..97725ccbae8c00d0e43d97c1d9ecf61e678cc293 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -22,6 +22,9 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CGFunctionInfo.h" +// OHOS_LOCAL start +#include "clang/Pac/PacDfi.h" +// OHOS_LOCAL end #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" @@ -852,6 +855,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) { if (!Entry) { Entry = llvm::StructType::create(getLLVMContext()); addRecordTypeName(RD, Entry, ""); + PacDfiRecordDecl2StructName(RD, Entry); // OHOS_LOCAL } llvm::StructType *Ty = Entry; diff --git a/clang/lib/Pac/CMakeLists.txt b/clang/lib/Pac/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bc1d3dcffaa075817476cf5f499ddf3dfddb9c6f --- /dev/null +++ b/clang/lib/Pac/CMakeLists.txt @@ -0,0 +1,7 @@ +add_clang_library(pacDfi + PacDfi.cpp + + LINK_LIBS + Parts + clangCodeGen +) \ No newline at end of file diff --git a/clang/lib/Pac/PacDfi.cpp b/clang/lib/Pac/PacDfi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ab2b19ea0691ca7bf7d4d61648b935745e5518c --- /dev/null +++ b/clang/lib/Pac/PacDfi.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Zaheer Gauhar +// Gilang Mentari Hamidy +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Constants.h" +#include "llvm/PARTS/Parts.h" +#include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/Attributes.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Pac/PacDfi.h" +#include "llvm/IR/Metadata.h" +#include "clang/CodeGen/CodeGenABITypes.h" +#include "clang/Basic/DiagnosticParse.h" +using namespace clang; + +std::map RecordDecl2StructName; +std::map> PacPtrNameInfos; +std::map> PacFieldNameInfos; +std::map RecordDecl2StructType; +void PacDfiParseStruct(RecordDecl *TagDecl, ASTContext &Ctx, DiagnosticsEngine &Diags) +{ + if (!llvm::PARTS::useDataFieldTag()) { + return; + } + // find pac_tag attr fields, and insert new fields + std::vector PacPtrNames; + std::vector PacFieldNames; + unsigned int ArraySize = 0; + + for (auto *Field : TagDecl->fields()) { + auto ElemTy = Field->getType(); + if (Field->hasAttr()) { + unsigned Inc = 1; + // if Field is array type ElemTy is equal to array element type. + if (Field->getType()->isConstantArrayType()) { + auto *ArrayTy = llvm::dyn_cast(ElemTy); + ElemTy = ArrayTy->getElementType(); + Inc = ArrayTy->getSize().getZExtValue(); + } + // pac_protected_data [not] support structure type or structure array. + if (TagDecl->isUnion()) { + Diags.Report(Field->getLocation(), diag::warn_unsupported_pac_dfi_type) << "union" + << Field->getAttr()->getSpelling(); + continue; + } + if (ElemTy->isStructureOrClassType()) { + Diags.Report(Field->getLocation(), diag::warn_unsupported_pac_dfi_type) << Field->getType() + << Field->getAttr()->getSpelling(); + continue; + } + ArraySize += Inc; + PacFieldNames.push_back(Field); + } else if (Field->hasAttr()) { + // pac_protected_ptr [only] support pointer type. + if (!ElemTy->isAnyPointerType()) { + Diags.Report(Field->getLocation(), diag::warn_unsupported_pac_dfi_type) << Field->getType() + << Field->getAttr()->getSpelling(); + continue; + } + PacPtrNames.push_back(Field); + } + } + + if (!PacFieldNames.empty()) { + llvm::APInt ArraySizeInt(32, ArraySize); + auto ArrayTy = Ctx.getConstantArrayType(Ctx.IntTy, ArraySizeInt, nullptr, ArrayType::Normal, + /*IndexTypeQuals=*/ 0); + FieldDecl *PacFD = FieldDecl::Create(Ctx, TagDecl, SourceLocation(), SourceLocation(), nullptr, + ArrayTy, nullptr, nullptr, true, ICIS_NoInit); + + TagDecl->addDecl(PacFD); + PacFieldNameInfos.insert(std::make_pair(TagDecl, PacFieldNames)); + } + if (!PacPtrNames.empty()) { + PacPtrNameInfos.insert(std::make_pair(TagDecl, PacPtrNames)); + } +} + +void PacDfiCreateMetaData(std::map> &fieldInfos, StringRef mdName, + llvm::Module &M, llvm::LLVMContext &VMContext, CodeGen::CodeGenModule *CGM) +{ + llvm::NamedMDNode *PacNMD = M.getOrInsertNamedMetadata(mdName); + for (auto item : fieldInfos) { + if (RecordDecl2StructName.find(item.first) == RecordDecl2StructName.end()) { + continue; + } + std::vector PacFields; + auto styName = RecordDecl2StructName.find(item.first)->second; + PacFields.push_back(llvm::MDString::get(VMContext, styName)); + for (auto *Field : item.second) { + unsigned idx = CodeGen::getLLVMFieldNumber(*CGM, item.first, Field); + PacFields.push_back(llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), idx))); + } + PacNMD->addOperand(llvm::MDNode::get(VMContext, PacFields)); + } +} + +void PacDfiEmitStructFieldsMetadata(llvm::Module &M, llvm::LLVMContext &VMContext, CodeGen::CodeGenModule *CGM) +{ + if (!llvm::PARTS::useDataFieldTag()) { + return; + } + // emit struct fields that need to protect with PA + if (!PacFieldNameInfos.empty()) { + PacDfiCreateMetaData(PacFieldNameInfos, "pa_field_info", M, VMContext, CGM); + } + if (!PacPtrNameInfos.empty()) { + PacDfiCreateMetaData(PacPtrNameInfos, "pa_ptr_field_info", M, VMContext, CGM); + } +} + +void PacDfiRecordDecl2StructName(const RecordDecl *RD, llvm::StructType *Entry) +{ + if (!llvm::PARTS::useDataFieldTag()) { + return; + } + if (Entry->isLiteral()) { + return; + } + RecordDecl2StructName.insert(std::make_pair(RD, Entry->getName())); +} \ No newline at end of file diff --git a/clang/lib/Parse/CMakeLists.txt b/clang/lib/Parse/CMakeLists.txt index 7e90b37386f9e64b2b36c84c68f0093204e37840..c6e17e5948bc99ee501a1ac470293217418ac9c3 100644 --- a/clang/lib/Parse/CMakeLists.txt +++ b/clang/lib/Parse/CMakeLists.txt @@ -28,6 +28,7 @@ add_clang_library(clangParse clangBasic clangLex clangSema + pacDfi # OHOS_LOCAL DEPENDS omp_gen diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index aef9909a7c971e867a75ddbff29f9e0c7e572341..92944a127fcb2b10d991c219ef0ad1ad8c30c443 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -25,6 +25,9 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaDiagnostic.h" +// OHOS_LOCAL start +#include "clang/Pac/PacDfi.h" +// OHOS_LOCAL end #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" @@ -4529,6 +4532,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, TryConsumeToken(tok::semi); } + // find pac_tag attr fields, and insert new fields + PacDfiParseStruct(TagDecl, Actions.getASTContext(), Diags); // OHOS_LOCAL + T.consumeClose(); ParsedAttributes attrs(AttrFactory); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index a6a946d7f31b18c0ae8c2f2a9f4f0cf32e31e65a..1c0e0c62a3c5f6a51de6c378cc2ba9e56752560b 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1422,6 +1422,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression // unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')' case tok::kw___builtin_omp_required_simd_align: + case tok::kw___builtin_get_modifier_bytype: // OHOS_LOCAL if (NotPrimaryExpression) *NotPrimaryExpression = true; AllowSuffix = false; @@ -2284,7 +2285,9 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step, - tok::kw___builtin_omp_required_simd_align) && + tok::kw___builtin_omp_required_simd_align, + tok::kw___builtin_get_modifier_bytype // OHOS_LOCAL + ) && "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -2294,7 +2297,9 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, // If construct allows a form without parenthesis, user may forget to put // pathenthesis around type name. if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, - tok::kw__Alignof)) { + tok::kw__Alignof, + tok::kw___builtin_get_modifier_bytype // OHOS_LOCAL + )) { if (isTypeIdUnambiguously()) { DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); @@ -2479,7 +2484,10 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { ExprKind = UETT_VecStep; else if (OpTok.is(tok::kw___builtin_omp_required_simd_align)) ExprKind = UETT_OpenMPRequiredSimdAlign; - + // OHOS_LOCAL Begin + else if (OpTok.is(tok::kw___builtin_get_modifier_bytype)) + ExprKind = UETT_PacModifierByType; + // OHOS_LOCAL End if (isCastExpr) return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 838fd48357fb71fdc2625a8e22bf59c572a07158..bac86bb767a18cdf75d9cf4743a5e42393ae8ad4 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -9093,7 +9093,16 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_UsingIfExists: handleSimpleAttribute(S, D, AL); break; + // OHOS_LOCAL start + case ParsedAttr::AT_PacDataTag: + handleSimpleAttribute(S, D, AL); + break; + + case ParsedAttr::AT_PacPtrTag: + handleSimpleAttribute(S, D, AL); + break; } + // OHOS_LOCAL end } /// ProcessDeclAttributeList - Apply all the decl attributes in the specified diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td index fc66bdfc35e04f13e59a37972504166b79edced4..c126267950e145052a61fa2a9b0de4c3cd9262ab 100644 --- a/llvm/include/llvm/IR/IntrinsicsAArch64.td +++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td @@ -848,7 +848,7 @@ def int_aarch64_crc32x : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llv def int_aarch64_crc32cx : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i64_ty], [IntrNoMem]>; } - +include "llvm/PARTS/Intrinsics.td" // OHOS_LOCAL //===----------------------------------------------------------------------===// // Memory Tagging Extensions (MTE) Intrinsics let TargetPrefix = "aarch64" in { diff --git a/llvm/include/llvm/PARTS/AArch64InstInfo.td b/llvm/include/llvm/PARTS/AArch64InstInfo.td new file mode 100644 index 0000000000000000000000000000000000000000..6e6ff0fc56150a84b081eabd9926bd726b724491 --- /dev/null +++ b/llvm/include/llvm/PARTS/AArch64InstInfo.td @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let isPseudo = 1, hasNoSchedulingInfo = 1 in { + def PARTS_PACIA : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr, GPR64sp:$mod), + [(set i64:$dst, (int_pa_pacia GPR64:$ptr, GPR64sp:$mod))], + "$dst = $ptr">; + def PARTS_AUTIA : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr, GPR64sp:$mod), + [(set i64:$dst, (int_pa_autia GPR64:$ptr, GPR64sp:$mod))], + "$dst = $ptr">; + def PARTS_AUTCALL : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr, GPR64sp:$mod), + [(set i64:$dst, (int_pa_autcall GPR64:$ptr, GPR64sp:$mod))], + "$dst = $ptr">; + + def PARTS_PACDA : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr, GPR64sp:$mod), + [(set i64:$dst, (int_pa_pacda GPR64:$ptr, GPR64sp:$mod))], + "$dst = $ptr">; + def PARTS_AUTDA : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr, GPR64sp:$mod), + [(set i64:$dst, (int_pa_autda GPR64:$ptr, GPR64sp:$mod))], + "$dst = $ptr">; + def PARTS_XPACD : Pseudo<(outs GPR64:$dst), + (ins GPR64:$ptr), + [(set i64:$dst, (int_pa_xpacd GPR64:$ptr))], + "$dst = $ptr">; +} + +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [SP] in { + def TCRETURNriAA : Pseudo<(outs), (ins tcGPR64:$dst, i32imm:$FPDiff, GPR64sp:$mod), []>, + Sched<[WriteBrReg]>; +} diff --git a/llvm/include/llvm/PARTS/Intrinsics.td b/llvm/include/llvm/PARTS/Intrinsics.td new file mode 100644 index 0000000000000000000000000000000000000000..c7461af4a5f5cf0e4635990e103175f6a8f904c1 --- /dev/null +++ b/llvm/include/llvm/PARTS/Intrinsics.td @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def int_pa_pacia : Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i64_ty], [IntrNoMem]>; +def int_pa_autia : Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i64_ty], [IntrNoMem]>; +def int_pa_autcall : Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i64_ty], [IntrNoMem], "", [SDNPOutGlue]>; +def int_pa_pacda : Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i64_ty], [IntrNoMem]>; +def int_pa_autda : Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i64_ty], [IntrNoMem, IntrHasSideEffects]>; +def int_pa_xpacd : Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>], [IntrNoMem]>; \ No newline at end of file diff --git a/llvm/include/llvm/PARTS/Parts.h b/llvm/include/llvm/PARTS/Parts.h new file mode 100644 index 0000000000000000000000000000000000000000..b4a29e88588542ac6bb3a6a31b9bcb5bddf9ab0b --- /dev/null +++ b/llvm/include/llvm/PARTS/Parts.h @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PARTS_H +#define LLVM_PARTS_H + +#include "llvm/IR/Constant.h" +#include "llvm/IR/Type.h" +#include "llvm/Pass.h" + +namespace llvm { +namespace PARTS { + +enum PartsBeCfiType { + PartsBeCfiNone, + PartsBeCfiFull, + PartsBeCfiNgFull +}; + +enum PartsDpiType { + PartsDpiNone, + PartsDpiFull, + PartsDpiFullNoType +}; + +bool useBeCfi(); +bool useFeCfi(); +bool useDataPointerConfig(); +bool useDataPointerProtection(); +bool useDataFieldTag(); +bool useDataFieldProtection(); +PartsBeCfiType getBeCfiType(); +Pass *createPartsPluginPass(); +uint16_t getTypeIdFor(const Type *T); +} +} +#endif \ No newline at end of file diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt index 5ecdf5af956a31a5b75f8645624ce81a1fba9f3a..dedbc5775990e66df2c37453f0d3c1adaf20af43 100644 --- a/llvm/lib/CMakeLists.txt +++ b/llvm/lib/CMakeLists.txt @@ -43,6 +43,7 @@ if (LLVM_INCLUDE_TESTS) endif() add_subdirectory(WindowsDriver) add_subdirectory(WindowsManifest) +add_subdirectory(PARTS) # OHOS_LOCAL set(LLVMCONFIGLIBRARYDEPENDENCIESINC "${LLVM_BINARY_DIR}/tools/llvm-config/LibraryDependencies.inc") diff --git a/llvm/lib/PARTS/CMakeLists.txt b/llvm/lib/PARTS/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..196de8467f3e1952d880b15e21900a539c8bb24d --- /dev/null +++ b/llvm/lib/PARTS/CMakeLists.txt @@ -0,0 +1,23 @@ +add_llvm_component_library(Parts + Parts.cpp + PartsPluginPass.cpp + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/PARTS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Support + ${LLVM_MAIN_INCLUDE_DIR}/llvm/IR + + DEPENDS + intrinsics_gen + LLVMCore + LLVMSupport + LLVMTransformUtils + LLVMCodeGen + + LINK_LIBS + LLVMCore + LLVMSupport + LLVMTransformUtils + LLVMCodeGen + ) +set_property(TARGET Parts PROPERTY LLVM_SYSTEM_LIBS) \ No newline at end of file diff --git a/llvm/lib/PARTS/Parts.cpp b/llvm/lib/PARTS/Parts.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a49b889829a688664d2a74c88d4898a355b8466f --- /dev/null +++ b/llvm/lib/PARTS/Parts.cpp @@ -0,0 +1,139 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "llvm/PARTS/Parts.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/SHA256.h" +#include +#include +using namespace llvm; +using namespace PARTS; +static std::map TypeIdCache; +static cl::opt EnableFeCfi( + "FECFI", cl::Hidden, + cl::desc("forward-edge CFI"), + cl::init(false)); + +static cl::opt EnableBeCfi( + "FGBECFI", cl::Hidden, + cl::desc("backward-edge CFI"), + cl::init(false)); + +static cl::opt EnableDfiDpTag( + "DFIDPTAG", cl::Hidden, + cl::desc("Data field DFI identify by tag"), + cl::init(false)); + +static cl::opt EnableDfiDppTag( + "DFIDPPTAG", cl::Hidden, + cl::desc("Data pointer DFI identify by tag"), + cl::init(false)); + +static cl::opt EnableDfiDpp( + "DFIDPP", cl::Hidden, + cl::desc("Data pointer DFI identify by config"), + cl::init(false)); + +bool llvm::PARTS::useFeCfi() { + return EnableFeCfi; +} + +bool llvm::PARTS::useBeCfi() { + return EnableBeCfi; +} + +bool llvm::PARTS::useDataPointerConfig() { + return EnableDfiDpp; +} + +bool llvm::PARTS::useDataPointerProtection() { + return EnableDfiDpp || EnableDfiDppTag; +} + +bool llvm::PARTS::useDataFieldTag() { + return EnableDfiDpTag || EnableDfiDppTag; +} + +bool llvm::PARTS::useDataFieldProtection() { + return EnableDfiDpTag; +} + +PartsBeCfiType PARTS::getBeCfiType() { + if (EnableBeCfi) { + return PartsBeCfiFull; + } + return PartsBeCfiNone; +} + +static void buildTypeString(const Type *T, llvm::raw_string_ostream &O) +{ + if (T->isPointerTy()) { + O << "ptr."; + buildTypeString(T->getNonOpaquePointerElementType(), O); + } else if (T->isStructTy()) { + if (dyn_cast(T)->isLiteral()) { + return; + } + auto Sty = dyn_cast(T)->getStructName(); + std::regex E("^(\\w+\\.\\w+)(\\.\\w+)?$"); + O << std::regex_replace(Sty.str(), E, "$1"); + } else if (T->isArrayTy()) { + O << "ptr."; + buildTypeString(T->getArrayElementType(), O); + } else if (T->isFunctionTy()) { + auto *FuncTy = dyn_cast<::llvm::FunctionType>(T); + O << "f."; + buildTypeString(FuncTy->getReturnType(), O); + for (auto *Param = FuncTy->param_begin(); Param != FuncTy->param_end(); Param++) { + buildTypeString(*Param, O); + } + } else if (T->isVectorTy()) { + O << "vec." << dyn_cast<::llvm::VectorType>(T)->getElementCount().getKnownMinValue(); + buildTypeString(dyn_cast<::llvm::VectorType>(T)->getElementType(), O); + } else if (T->isVoidTy()) { + O << "v"; + } else { + /* Make sure we've handled all cases we want to*/ + if (!(T->isIntegerTy() || T->isFloatingPointTy())) { + outs() << "buildTypeString: assert!!\n"; + } + T->print(O); + } +} + +static uint16_t getTypeId(const std::string &Context) +{ + uint16_t TheTypeId = 0; + llvm::SHA256 ALG; + auto HashCode = ALG.hash(ArrayRef(reinterpret_cast(Context.c_str()), Context.size())); + std::copy(HashCode.begin(), HashCode.begin() + 2, reinterpret_cast(&TheTypeId)); + return TheTypeId; +} + +uint16_t llvm::PARTS::getTypeIdFor(const Type *T) +{ + if (!T->isPointerTy()) { + return 0; + } + auto TypeIdIter = TypeIdCache.find(T); + if (TypeIdIter != TypeIdCache.end()) { + return TypeIdIter->second; + } + std::string Buf; + llvm::raw_string_ostream TypeIdStr(Buf); + buildTypeString(T, TypeIdStr); + TypeIdStr.flush(); + uint16_t TheTypeId = getTypeId(Buf); + TypeIdCache.emplace(T, TheTypeId); + return TheTypeId; +} \ No newline at end of file diff --git a/llvm/lib/PARTS/PartsPluginPass.cpp b/llvm/lib/PARTS/PartsPluginPass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97319040e10d9e0c75cad142af994ca66e91c9cf --- /dev/null +++ b/llvm/lib/PARTS/PartsPluginPass.cpp @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Author: Zaheer Gauhar +// Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "llvm/IR/AbstractCallSite.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/Pass.h" +#include "llvm/PARTS/Parts.h" +#include "llvm/Support/Debug.h" +#include "llvm/IR/Attributes.h" + +using namespace llvm; +using namespace llvm::PARTS; + +#define DEBUG_TYPE "PartsPluginPass" + +namespace { + +class PartsPluginPass : public ModulePass { +public: + static char ID; + PartsPluginPass() : ModulePass(ID) {} + bool runOnModule(Module &M) override; + +private: + /* + Check the input Value V and recursively change inner parameters, or if V itself needs to be replaced + in the containint function, then uses give builder to generate PACed value and returns said value. + @param M + @param I + @param V + @return + */ + bool handleInstruction(Function &F, Instruction &I); + CallInst *handleAutCallInstruction(Function &F, Instruction &I, Value *value); +}; + +} + +char PartsPluginPass::ID = 0; +static RegisterPass X("parts-plugin", "PARTS Plugin pass"); + +Pass *llvm::PARTS::createPartsPluginPass() { return new PartsPluginPass(); } + +bool PartsPluginPass::runOnModule(Module &M) { + if (!PARTS::useFeCfi()) + return false; + + bool modified = false; + for (auto &F : M) { + for (auto &BB: F) { + for (auto &I: BB) { + modified = handleInstruction(F, I) || modified; + } + } + } + return modified; +} + +bool PartsPluginPass::handleInstruction(Function &F, Instruction &I) { + auto CI = dyn_cast(&I); + if (!CI || CI->isInlineAsm()) { + return false; + } + auto calledValue = CI->getCalledOperand(); + IntrinsicInst *II = dyn_cast(calledValue); + if (II && II->getIntrinsicID() == Intrinsic::pa_autcall) { + Value *paced = nullptr; + paced = handleAutCallInstruction(F, I, calledValue); + if (paced) { + CI->setCalledOperand(paced); + } + } + return false; +} + +CallInst *PartsPluginPass::handleAutCallInstruction(Function &F, Instruction &I, Value *value) { + Instruction *Insn = dyn_cast(value); + auto *Call_BB = I.getParent(); + auto *Insn_BB = Insn->getParent(); + + if (Call_BB == Insn_BB) { + return nullptr; + } + + auto calledValue = Insn->getOperand(0); + const auto calledValueType = calledValue->getType(); + IRBuilder<> Builder(&I); + auto autcall = Intrinsic::getDeclaration(F.getParent(), Intrinsic::pa_autcall, { calledValueType}); + auto typeIdConstant = Insn->getOperand(1); + CallInst *paced = Builder.CreateCall(autcall, { calledValue, typeIdConstant }, ""); + return paced; + } \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h index a6065d4ed9ec3c447d6ddefea86d876e185c8ead..0fbd926dadf26a12bb70e5e493e8de1ba3eac0f6 100644 --- a/llvm/lib/Target/AArch64/AArch64.h +++ b/llvm/lib/Target/AArch64/AArch64.h @@ -68,6 +68,11 @@ FunctionPass *createAArch64PostLegalizerLowering(); FunctionPass *createAArch64PostSelectOptimize(); FunctionPass *createAArch64StackTaggingPass(bool IsOptNone); FunctionPass *createAArch64StackTaggingPreRAPass(); +// OHOS_LOCAL start +FunctionPass *createAArch64EarlyPartsCpiPass(); +FunctionPass *createAArch64PartsCpiPass(); +FunctionPass *createPartsPassDpi(); +// OHOS_LOCAL end void initializeAArch64A53Fix835769Pass(PassRegistry&); void initializeAArch64A57FPLoadBalancingPass(PassRegistry&); diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 8ed54a6703cf0110566bd4abd773557b86871ace..e786056aafdf1a5465e898d497adc0f922a73e22 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -579,7 +579,7 @@ void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) { // generates code that does this, it is always safe to set. OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols); } - + // Emit stack and fault map information. emitStackMaps(SM); FM.serializeToFaultMapSection(); @@ -1310,6 +1310,16 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, TmpInst); return; } + // OHOS_LOCAL start + case AArch64::TCRETURNriAA: { + MCInst TmpInst; + TmpInst.setOpcode(AArch64::BRAA); + TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); + TmpInst.addOperand(MCOperand::createReg(MI->getOperand(2).getReg())); + EmitToStreamer(*OutStreamer, TmpInst); + return; + } + // OHOS_LOCAL end case AArch64::TCRETURNdi: { MCOperand Dest; MCInstLowering.lowerOperand(MI->getOperand(0), Dest); diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp index a7a1c969faf5e7d11c7d27b3bf639ff1d840e27f..72acfa7fc66a687e50fb4f77a3480d05545630bd 100644 --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -192,6 +192,7 @@ #include "AArch64StackProtectorRetLowering.h" #include "AArch64Subtarget.h" #include "AArch64TargetMachine.h" +#include "AArch64PARTS/PartsFrameLowering.h" // OHOS_LOCAL #include "MCTargetDesc/AArch64AddressingModes.h" #include "MCTargetDesc/AArch64MCTargetDesc.h" #include "llvm/ADT/ScopeExit.h" @@ -274,6 +275,7 @@ static int64_t getArgumentStackToRestore(MachineFunction &MF, unsigned RetOpcode = MBBI->getOpcode(); IsTailCallReturn = RetOpcode == AArch64::TCRETURNdi || RetOpcode == AArch64::TCRETURNri || + RetOpcode == AArch64::TCRETURNriAA || // OHOS_LOCAL RetOpcode == AArch64::TCRETURNriBTI; } AArch64FunctionInfo *AFI = MF.getInfo(); @@ -1429,6 +1431,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF, .setMIFlags(MachineInstr::FrameSetup); } } + PartsFrameLowering::instrumentPrologue(TII, Subtarget.getRegisterInfo(), MBB, MBBI, DebugLoc()); // OHOS_LOCAL if (EmitCFI && MFnI.isMTETagged()) { BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITMTETAGGED)) .setMIFlag(MachineInstr::FrameSetup); @@ -1914,6 +1917,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF, auto FinishingTouches = make_scope_exit([&]() { InsertReturnAddressAuth(MF, MBB); + PartsFrameLowering::instrumentEpilogue(TII, Subtarget.getRegisterInfo(), MBB); // OHOS_LOCAL if (needsShadowCallStackPrologueEpilogue(MF)) emitShadowCallStackEpilogue(*TII, MF, MBB, MBB.getFirstTerminator(), DL); if (EmitCFI) diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td index e70d304f37b92f25a5f653bc8ca4e8287bbe8c4b..7a4cbab21ee8836ea6aa91e6472cc6b1431eb449 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -1747,7 +1747,7 @@ class RCPCLoad sz, string asm, RegisterClass RC> class AuthBase M, dag oops, dag iops, string asm, string operands, list pattern> - : I, Sched<[]> { + : I, Sched<[WriteBrReg]> { // OHOS_LOCAL let isAuthenticated = 1; let Inst{31-25} = 0b1101011; let Inst{20-11} = 0b1111100001; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 4976f51b82e16cee9784bab0ad4882be7ab283d6..5e25409d63439297372a1fe77bd9ddb678b95290 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -8413,3 +8413,4 @@ include "AArch64InstrAtomics.td" include "AArch64SVEInstrInfo.td" include "AArch64SMEInstrInfo.td" include "AArch64InstrGISel.td" +include "llvm/PARTS/AArch64InstInfo.td" // OHOS_LOCAL \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h index f070f989a5b7d1504df40ac01963b05b3940880e..5fbf1e7e195bed3d860fd08dac2c190edf734453 100644 --- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h +++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h @@ -186,7 +186,9 @@ class AArch64FunctionInfo final : public MachineFunctionInfo { /// True if the function need asynchronous unwind information. mutable Optional NeedsAsyncDwarfUnwindInfo; - + /// Temporary symbol used by PARTS to generate a runtime dependent modifier based on + /// the position of function. Epilogue emission relys on this value beging set. + MCSymbol *PartsSym = nullptr; // OHOS_LOCAL public: explicit AArch64FunctionInfo(MachineFunction &MF); @@ -433,7 +435,10 @@ public: bool needsDwarfUnwindInfo() const; bool needsAsyncDwarfUnwindInfo() const; - + // OHOS_LOCAL start + void setPartsSym(MCSymbol *Sym) { PartsSym = Sym; } + MCSymbol *getPartsSym() const { return PartsSym; } + // OHOS_LOCAL end private: // Hold the lists of LOHs. MILOHContainer LOHContainerSet; diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/AArch64EarlyPartsCpiPass.cpp b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64EarlyPartsCpiPass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63d38b6729f911ab137545a3f2bad57b80e01951 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64EarlyPartsCpiPass.cpp @@ -0,0 +1,178 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AArch64.h" +#include "AArch64Subtarget.h" +#include "AArch64RegisterInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/PARTS/Parts.h" + +#define DEBUG_TYPE "AArch64EarlyPartsCpiPass" + +STATISTIC(StatAutcall, DEBUG_TYPE ": inserted authenticate and branch instructions"); + +using namespace llvm; +using namespace llvm::PARTS; + +namespace { + +class AArch64EarlyPartsCpiPass : public MachineFunctionPass { +public: + static char ID; + AArch64EarlyPartsCpiPass() : MachineFunctionPass(ID) {} + StringRef getPassName() const override { return DEBUG_TYPE; } + virtual bool doInitialization(Module &M) override; + bool runOnMachineFunction(MachineFunction &) override; +private: + const AArch64Subtarget *STI = nullptr; + const AArch64InstrInfo *TII = nullptr; + inline bool handleInstruction(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator &MIi); + inline MachineInstr *findIndirectCallMachineInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineInstr *MIptr); + void triggerCompilationErrorOrphanAUTCALL(MachineBasicBlock &MBB); + inline bool isIndirectCall(const MachineInstr &MI) const; + inline bool isPartsAUTCALLIntrinsic(unsigned Opcode); + inline const MCInstrDesc &getIndirectCallAuth(MachineInstr *MI_indcall); + inline void replaceBranchByAuthenticatedBranch(MachineBasicBlock &MBB, MachineInstr *MI_indcall, MachineInstr &MI); + inline void insertCOPYInstr(MachineBasicBlock &MBB, MachineInstr *MI_indcall, MachineInstr &MI); +}; +} + +FunctionPass *llvm::createAArch64EarlyPartsCpiPass() { + return new AArch64EarlyPartsCpiPass(); +} + +char AArch64EarlyPartsCpiPass::ID = 0; +bool AArch64EarlyPartsCpiPass::doInitialization(Module &M) { + return true; +} + +bool AArch64EarlyPartsCpiPass::runOnMachineFunction(MachineFunction &MF) { + bool found = false; + STI = &MF.getSubtarget(); + TII = STI->getInstrInfo(); + + for (auto &MBB : MF) { + for (auto MIi = MBB.instr_begin(), MIie = MBB.instr_end(); MIi != MIie; ++MIi) { + found= handleInstruction(MF, MBB, MIi) || found; + } + } + return found; +} + +/** +* @param MF +* @param MBB +* @param MIi +* @return return true when changing something, otherwise false +**/ +inline bool AArch64EarlyPartsCpiPass::handleInstruction(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator &MIi) { + const auto MIOpcode = MIi->getOpcode(); + if (!isPartsAUTCALLIntrinsic(MIOpcode)) { + return false; + } + auto MIptr = &*MIi; + MachineInstr *MI_indcall = findIndirectCallMachineInstr(MF, MBB, MIptr); + if (MI_indcall == nullptr) { + outs() << "MI_indcall is NULL!!!\n"; + triggerCompilationErrorOrphanAUTCALL(MBB); + } + auto &MI = *MIi--; + replaceBranchByAuthenticatedBranch(MBB, MI_indcall, MI); + ++StatAutcall; + return true; +} + +inline bool AArch64EarlyPartsCpiPass::isPartsAUTCALLIntrinsic(unsigned Opcode) { + switch (Opcode) { + case AArch64::PARTS_AUTCALL: + return true; + } + return false; +} + +inline const MCInstrDesc& AArch64EarlyPartsCpiPass::getIndirectCallAuth(MachineInstr *MI_indcall) { + if (MI_indcall->getOpcode() == AArch64::BLR) { + return TII->get(AArch64::BLRAA); + } + // This is a tail call return, and we need to use BRAA + // (tail-call: ~optimation where a tail-call is coverted to a direct call so that + // the tail-called function can return immediately to the current callee, without + // going through the currently active function.) + + return TII->get(AArch64::TCRETURNriAA); +} + +inline MachineInstr* AArch64EarlyPartsCpiPass::findIndirectCallMachineInstr(MachineFunction &MF, + MachineBasicBlock &MBB, MachineInstr *MIptr) { + unsigned AUTCALLinstr_oper0 = MIptr->getOperand(0).getReg(); + unsigned BLRinstr_oper0 = 0; + for (auto &MBB: MF) { + for (auto MIi = MBB.instr_begin(), MIie = MBB.instr_end(); MIi != MIie; ++MIi) { + if (&*MIi != nullptr && isIndirectCall(*MIi)) { + BLRinstr_oper0 = MIi->getOperand(0).getReg(); + if (AUTCALLinstr_oper0 == BLRinstr_oper0) { + return &*MIi; + } + } + } + } + return nullptr; +} + +inline bool AArch64EarlyPartsCpiPass::isIndirectCall(const MachineInstr &MI) const { + switch(MI.getOpcode()) { + case AArch64::BLR: // Normal indirect call + case AArch64::TCRETURNri: // Indirect tail call + return true; + } + return false; +} + +void AArch64EarlyPartsCpiPass::triggerCompilationErrorOrphanAUTCALL(MachineBasicBlock &MBB) { + LLVM_DEBUG(MBB.dump()); + llvm_unreachable("failed to find BLR for AUTCALL"); +} + +inline void AArch64EarlyPartsCpiPass::replaceBranchByAuthenticatedBranch(MachineBasicBlock &MBB, + MachineInstr *MI_indcall, MachineInstr &MI) { + auto modOperand = MI.getOperand(2); + insertCOPYInstr(MBB, MI_indcall, MI); + auto BMI = BuildMI(MBB, *MI_indcall, MI_indcall->getDebugLoc(), getIndirectCallAuth(MI_indcall)); + BMI.addUse(MI_indcall->getOperand(0).getReg()); + if (MI_indcall->getOpcode() == AArch64::TCRETURNri) { + BMI.add(MI_indcall->getOperand(1)); // Copy FPDiff from original tail call pseudo instruction + } + BMI.add(modOperand); + BMI.copyImplicitOps(*MI_indcall); + + MI_indcall->removeFromParent(); + MI.removeFromParent(); +} +inline void AArch64EarlyPartsCpiPass::insertCOPYInstr(MachineBasicBlock &MBB, MachineInstr *MI_indcall, + MachineInstr &MI) { + auto dstOperand = MI.getOperand(0); + auto srcOperand = MI.getOperand(1); + + auto COPYMI = BuildMI(MBB, *MI_indcall, MI_indcall->getDebugLoc(), TII->get(AArch64::COPY)); + COPYMI.add(dstOperand); + COPYMI.add(srcOperand); +} \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsCpiPass.cpp b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsCpiPass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ea8a652ee627c9c4850ea433b2563d47191f83f --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsCpiPass.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include "AArch64.h" +#include "AArch64Subtarget.h" +#include "AArch64RegisterInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/PARTS/Parts.h" + +#define DEBUG_TYPE "AArch64PartsCpiPass" + +STATISTIC(StatAutia, DEBUG_TYPE ": code pointers authenticated and unPACed"); +STATISTIC(StatPacia, DEBUG_TYPE ": code pointers signed"); + +using namespace llvm; +using namespace llvm::PARTS; + +namespace { +class AArch64PartsCpiPass : public MachineFunctionPass { +public: + static char ID; + AArch64PartsCpiPass() : MachineFunctionPass(ID) {} + StringRef getPassName() const override {return DEBUG_TYPE; } + bool doInitialization(Module &M) override; + bool runOnMachineFunction(MachineFunction &) override; +private: + const AArch64InstrInfo *TII = nullptr; + void lowerPARTSAUTCALL(MachineBasicBlock &MBB, MachineInstr &MI); + void lowerPARTSPACIA(MachineBasicBlock &MBB, MachineInstr &MI); + + inline bool handleInstruction(MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator &MIi); + inline void lowerPARTSAUTIA(MachineBasicBlock &MBB, MachineInstr &MI); + void lowerPARTSIntrinsicCommon(MachineBasicBlock &MBB, MachineInstr &MI, const MCInstrDesc &InstrDesc); + inline bool isPartsIntrinsic(unsigned Opcode); +}; + +} + +FunctionPass *llvm::createAArch64PartsCpiPass() { + return new AArch64PartsCpiPass(); +} + +char AArch64PartsCpiPass::ID = 0; + +bool AArch64PartsCpiPass::doInitialization(Module &M) { + return true; +} + +bool AArch64PartsCpiPass::runOnMachineFunction(MachineFunction &MF) { + bool found = false; + TII = MF.getSubtarget().getInstrInfo(); + + for (auto &MBB : MF) { + for (auto MIi = MBB.instr_begin(), MIie = MBB.instr_end(); MIi != MIie; ++ MIi) { + found = handleInstruction(MBB, MIi) || found; + } + } + return found; +} + +/** +* @param MBB +* @param MIi +* @return return true when changing something, otherwise false +**/ +inline bool AArch64PartsCpiPass::handleInstruction(MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator &MIi) { + const auto MIOpcode = MIi->getOpcode(); + if (!isPartsIntrinsic(MIOpcode)) + return false; + + auto &MI = *MIi--; + switch (MIOpcode) { + default: + llvm_unreachable("Unhandled PARTS intrinsic!!"); + case AArch64::PARTS_PACIA: + lowerPARTSPACIA(MBB, MI); + break; + case AArch64::PARTS_AUTIA: + lowerPARTSAUTIA(MBB, MI); + break; + case AArch64::PARTS_AUTCALL: + lowerPARTSAUTCALL(MBB, MI); + break; + } + MI.removeFromParent(); // Remove the PARTS intrinsic! + return true; +} + +inline bool AArch64PartsCpiPass::isPartsIntrinsic(unsigned Opcode) { + switch (Opcode) { + case AArch64::PARTS_PACIA: + case AArch64::PARTS_AUTIA: + case AArch64::PARTS_AUTCALL: + return true; + } + return false; +} + +void AArch64PartsCpiPass::lowerPARTSPACIA(MachineBasicBlock &MBB, MachineInstr &MI) { + lowerPARTSIntrinsicCommon(MBB, MI, TII->get(AArch64::PACIA)); + ++StatPacia; +} + +inline void AArch64PartsCpiPass::lowerPARTSAUTIA(MachineBasicBlock &MBB, MachineInstr &MI) { + lowerPARTSIntrinsicCommon(MBB, MI, TII->get(AArch64::AUTIA)); + ++StatAutia; +} + +void AArch64PartsCpiPass::lowerPARTSAUTCALL(MachineBasicBlock &MBB, MachineInstr &MI) { + LLVM_DEBUG(MBB.dump()); + llvm_unreachable("Unexpected PARTSAUTCALL found!!!!"); +} + +void AArch64PartsCpiPass::lowerPARTSIntrinsicCommon(MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc) { + auto &mod = MI.getOperand(2); + auto &dst = MI.getOperand(0); + auto BMI = BuildMI(MBB, MI, MI.getDebugLoc(), InstrDesc); + BMI.add(dst); + BMI.add(dst); + BMI.add(mod); +} \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsDpiPass.cpp b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsDpiPass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..88edb11064bc0b85079e69508e08d6b4948295cf --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsDpiPass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +// LLVM includes +#include "AArch64.h" +#include "AArch64Subtarget.h" +#include "AArch64RegisterInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +// PARTS includes +#include "llvm/PARTS/Parts.h" +#include "AArch64PartsPassCommon.h" + +#define DEBUG_TYPE "AArch64PartsDpiPass" + +STATISTIC(StatDataStore, DEBUG_TYPE ": instrumented data stores"); +STATISTIC(StatDataLoad, DEBUG_TYPE ": instrumented data loads"); +STATISTIC(StatInsecureDataLoad, DEBUG_TYPE ": Insecure data loads"); + +using namespace llvm; +using namespace llvm::PARTS; + +namespace { +class AArch64PartsDpiPass : public MachineFunctionPass, private AArch64PartsPassCommon { +public: + static char ID; + AArch64PartsDpiPass() : MachineFunctionPass(ID) {} + StringRef getPassName() const override {return DEBUG_TYPE; } + bool runOnMachineFunction(MachineFunction &) override; + bool lowerDpiIntrinsics(MachineFunction &MF); +}; +} + +FunctionPass *llvm::createPartsPassDpi() { + return new AArch64PartsDpiPass(); +} + +char AArch64PartsDpiPass::ID = 0; + +bool AArch64PartsDpiPass::runOnMachineFunction(MachineFunction &MF) { + bool modified = false; + initRunOn(MF); + modified |= lowerDpiIntrinsics(MF); + return modified; +} + +bool AArch64PartsDpiPass::lowerDpiIntrinsics(MachineFunction &MF) { + bool modified = false; + for (auto &MBB : MF) { + for (auto MBBI = MBB.instr_begin(), end = MBB.instr_end(); MBBI != end;) { + auto &MI = *MBBI++; + switch(MI.getOpcode()) { + default: + break; + case AArch64::PARTS_PACDA: + replacePartsIntrinsic(MF, MBB, MI, TII->get(AArch64::PACDA)); + ++StatDataStore; + modified = true; + break; + case AArch64::PARTS_AUTDA: + replacePartsIntrinsic(MF, MBB, MI, TII->get(AArch64::AUTDA)); + ++StatDataLoad; + modified = true; + break; + case AArch64::PARTS_XPACD: + replacePartsXPACDIntrinsic(MF, MBB, MI); + ++StatInsecureDataLoad; + modified = true; + break; + } + } + } + return modified; +} \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsPassCommon.h b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsPassCommon.h new file mode 100644 index 0000000000000000000000000000000000000000..524be5733b68ede61ee6ea882de064a3ca229fed --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/AArch64PartsPassCommon.h @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __AARCH64PARTSOPTPASS_H__ +#define __AARCH64PARTSOPTPASS_H__ + +#include "AArch64InstrInfo.h" +#include "AArch64Subtarget.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/PARTS/Parts.h" + +using namespace llvm; +using namespace llvm::PARTS; + +namespace llvm { +namespace PARTS { + +class AArch64PartsPassCommon { +protected: + inline void initRunOn(MachineFunction &MF); + inline bool hasNoPartsAttribute(MachineFunction &MF); + inline void lowerPartsIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc); + inline void insertMovInstr(MachineBasicBlock &MBB, MachineInstr *MI, unsigned dstReg, unsigned srcReg); + inline void replacePartsIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc); + inline void replacePartsXPACDIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI); + + const TargetMachine *TM = nullptr; + const AArch64Subtarget *STI = nullptr; + const AArch64InstrInfo *TII = nullptr; + const AArch64RegisterInfo *TRI = nullptr; + +public: + static inline void insertPACInstr(MachineBasicBlock &MBB, MachineInstr *MI, unsigned dstReg, + unsigned modReg, const MCInstrDesc &InstrDesc); +}; +} +} + +inline void AArch64PartsPassCommon::initRunOn(MachineFunction &MF) { + TM = &MF.getTarget(); + STI = &MF.getSubtarget(); + TII = STI->getInstrInfo(); + TRI = STI->getRegisterInfo(); +} + +inline bool AArch64PartsPassCommon::hasNoPartsAttribute(MachineFunction &MF) { + return MF.getFunction().getFnAttribute("no-parts").getValueAsString() == "true"; +} + +inline void AArch64PartsPassCommon::lowerPartsIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc) { + const unsigned mod = MI.getOperand(2).getReg(); + const unsigned dst = MI.getOperand(0).getReg(); + insertPACInstr(MBB, &MI, dst, mod, InstrDesc); +} + +inline void AArch64PartsPassCommon::replacePartsIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, MachineInstr &MI, + const MCInstrDesc &InstrDesc) { + lowerPartsIntrinsic(MF, MBB, MI, InstrDesc); + MI.removeFromParent(); +} + +inline void AArch64PartsPassCommon::insertPACInstr(MachineBasicBlock &MBB, MachineInstr *MI, unsigned dstReg, + unsigned modReg, const MCInstrDesc &InstrDesc) { + if (MI != nullptr) { + BuildMI(MBB, MI, MI->getDebugLoc(), InstrDesc, dstReg) + .addReg(dstReg) + .addReg(modReg, RegState::InternalRead); + } else { + BuildMI(&MBB, DebugLoc(), InstrDesc, dstReg) + .addReg(dstReg) + .addReg(modReg, RegState::InternalRead); + } +} + +inline void AArch64PartsPassCommon::insertMovInstr(MachineBasicBlock &MBB, MachineInstr *MI, unsigned dstReg, + unsigned srcReg) { + BuildMI(MBB, MI, MI->getDebugLoc(), TII->get(AArch64::ORRXrs), dstReg) + .addUse(AArch64::XZR) + .addUse(srcReg) + .addImm(0); +} + +inline void AArch64PartsPassCommon::replacePartsXPACDIntrinsic(MachineFunction &MF, MachineBasicBlock &MBB, + MachineInstr &MI) { + const unsigned dst = MI.getOperand(0).getReg(); + BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(AArch64::XPACD), dst); + MI.removeFromParent(); +} + +#endif + diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2414ddbf1bb5dfacba00d028d5303ba668400a74 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.cpp @@ -0,0 +1,188 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Zaheer Gauhar +// Gilang Mentari Hamidy +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PartsFrameLowering.h" +#include "AArch64PartsPassCommon.h" +#include "AArch64InstrInfo.h" +#include "AArch64MachineFunctionInfo.h" +#include "AArch64RegisterInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/Debug.h" +#include "llvm/PARTS/Parts.h" +#include + +using namespace llvm; +using namespace llvm::PARTS; +#define DEBUG_TYPE "PartsOptRasPass" + +static constexpr const unsigned modReg = AArch64::X16; +static constexpr const unsigned modScratchReg = AArch64::X17; + +static bool doInstrument(const MachineFunction &MF) { + static const auto becfi = PARTS::getBeCfiType(); + + // Just skip if we're not even using backward-edge CFI + if (becfi == PartsBeCfiNone) return false; + + const Function &F = MF.getFunction(); + // Ignore function with the no-parts attribute + if (F.hasFnAttribute("no-parts")) return false; + // Ignore function without function-id (if we need it) + if (becfi == PartsBeCfiFull && !F.hasFnAttribute("parts-function_id")) return false; + + // Skip if we don't spill LR + for (const auto &Info : MF.getFrameInfo().getCalleeSavedInfo()) { + if (Info.getReg() != AArch64::LR) { + return true; + } + } + return false; +} + +static void createBeCfiModifier(const TargetInstrInfo *TII, MachineBasicBlock &MBB, MachineInstr *MIi, + const DebugLoc &DL) { + auto &F = MBB.getParent()->getFunction(); + + assert(F.hasFnAttribute("parts-function_id") && "missing parts-function_id attribute"); + + uint64_t type_id; + std::istringstream iss(F.getFnAttribute("parts-function_id").getValueAsString().str()); + iss >> type_id; + + const auto t1 = ((type_id) % UINT16_MAX); + const auto t2 = ((type_id << 16) % UINT16_MAX); + const auto t3 = ((type_id << 32) % UINT16_MAX); + + if (MIi == nullptr) { + BuildMI(&MBB, DL, TII->get(AArch64::ADDXri), modReg).addReg(AArch64::SP).addImm(0).addImm(0); + BuildMI(&MBB, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t1).addImm(16); + BuildMI(&MBB, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t2).addImm(32); + BuildMI(&MBB, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t3).addImm(48); + } else{ + BuildMI(MBB, MIi, DL, TII->get(AArch64::ADDXri), modReg).addReg(AArch64::SP).addImm(0).addImm(0); + BuildMI(MBB, MIi, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t1).addImm(16); + BuildMI(MBB, MIi, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t2).addImm(32); + BuildMI(MBB, MIi, DL, TII->get(AArch64::MOVKXi), modReg).addReg(modReg).addImm(t3).addImm(48); + } +} + +static MachineInstr *insertFastModifierInstructions(const TargetInstrInfo *TII, MachineBasicBlock &MBB, + MachineInstr *MI, MCSymbol *Sym, const DebugLoc &DL) { + LLVM_DEBUG(dbgs() << "insertFastModifierInstructions with MI begin.\n"); + + auto FirstModifierMI = BuildMI(MBB, MI, DL, TII->get(AArch64::ADR), modReg) + .addSym(Sym); + BuildMI(MBB, MI, DL, TII->get(AArch64::ADDXri), modScratchReg) + .addReg(AArch64::SP) + .addImm(0) + .addImm(0); + BuildMI(MBB, MI, DL, TII->get(AArch64::BFMXri), modReg) + .addUse(modReg) + .addReg(modScratchReg) + .addImm(32) + .addImm(31); + LLVM_DEBUG(dbgs() << "insertFastModifierInstructions with MI end.\n"); + return FirstModifierMI; +} + +static void insertFastModifierInstructions(const TargetInstrInfo *TII, MachineBasicBlock &MBB, + MCSymbol *Sym, const DebugLoc &DL) { + LLVM_DEBUG(dbgs() << "insertFastModifierInstructions begin.\n"); + + BuildMI(&MBB, DL, TII->get(AArch64::ADR), modReg) + .addSym(Sym); + BuildMI(&MBB, DL, TII->get(AArch64::ADDXri), modScratchReg) + .addReg(AArch64::SP) + .addImm(0) + .addImm(0); + BuildMI(&MBB, DL, TII->get(AArch64::BFMXri), modReg) + .addUse(modReg) + .addReg(modScratchReg) + .addImm(32) + .addImm(31); + LLVM_DEBUG(dbgs() << "insertFastModifierInstructions end.\n"); +} + +#define PARTS_SYMBOL "parts_becfi" + +static MCSymbol *createBeCfiPrologueSymbol(MachineBasicBlock &MBB) { + LLVM_DEBUG(dbgs() << "createBeCfiPrologueSymbol.\n"); + + auto &MF = *MBB.getParent(); + AArch64FunctionInfo *AFI = MF.getInfo(); + auto Sym = MF.getContext().createNamedTempSymbol(PARTS_SYMBOL); + AFI->setPartsSym(Sym); + return Sym; +} + +static MCSymbol *getBeCfiPrologueSymbol(MachineBasicBlock &MBB) { + auto &MF = *MBB.getParent(); + AArch64FunctionInfo *AFI = MF.getInfo(); + return AFI->getPartsSym(); +} + +static void insertPrologueFastBeCfiModifier(const TargetInstrInfo *TII, MachineBasicBlock &MBB, + MachineInstr *MIi, const DebugLoc &DL) { + assert(PARTS::getBeCfiType() == PartsBeCfiNgFull); + LLVM_DEBUG(dbgs() << "insertPrologueFastBeCfiModifier.\n"); + + auto Sym = createBeCfiPrologueSymbol(MBB); + auto MI = insertFastModifierInstructions(TII, MBB, MIi, Sym, DL); + MI->setPreInstrSymbol(*MBB.getParent(), Sym); +} + +static void insertEpilogueFastBeCfiModifier(const TargetInstrInfo *TII, MachineBasicBlock &MBB, + MachineInstr *MIi, const DebugLoc &DL) { + assert(PARTS::getBeCfiType() == PartsBeCfiNgFull); + + auto Sym = getBeCfiPrologueSymbol(MBB); + assert(Sym && "Missing PARTS prologue instruction symbol/label\n"); + LLVM_DEBUG(dbgs() << "insertEpilogueFastBeCfiModifier.\n"); + if (MIi == nullptr) { + insertFastModifierInstructions(TII, MBB, Sym, DL); + } else { + (void)insertFastModifierInstructions(TII, MBB, MIi, Sym, DL); + } +} + +void PartsFrameLowering::instrumentEpilogue(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, + MachineBasicBlock &MBB) { + if (!doInstrument(*MBB.getParent())) + return; + + const auto loc = MBB.getFirstTerminator(); + auto *MI = (loc != MBB.end() ? &*loc : nullptr); + LLVM_DEBUG(dbgs() << "instrumentEpilogue.\n"); + + if (PARTS::getBeCfiType() == PartsBeCfiFull) + createBeCfiModifier(TII, MBB, MI, DebugLoc()); + else + insertEpilogueFastBeCfiModifier(TII, MBB, MI, DebugLoc()); + + AArch64PartsPassCommon::insertPACInstr(MBB, MI, AArch64::LR, modReg, TII->get(AArch64::AUTIB)); +} + +void PartsFrameLowering::instrumentPrologue(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, + MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &DL) { + if (!doInstrument(*MBB.getParent())) + return; + + LLVM_DEBUG(dbgs() << "instrumentPrologue.\n"); + + if (PARTS::getBeCfiType() == PartsBeCfiFull) + createBeCfiModifier(TII, MBB, &*MBBI, DebugLoc()); + else + insertPrologueFastBeCfiModifier(TII, MBB, &*MBBI, DebugLoc()); + + AArch64PartsPassCommon::insertPACInstr(MBB, &*MBBI, AArch64::LR, modReg, TII->get(AArch64::PACIB)); +} \ No newline at end of file diff --git a/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.h b/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.h new file mode 100644 index 0000000000000000000000000000000000000000..9d21d8a101a68db1c3b7f717ac68e12dcb8867a6 --- /dev/null +++ b/llvm/lib/Target/AArch64/AArch64PARTS/PartsFrameLowering.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Author: Hans Liljestrand +// Zaheer Ahmed Gauhar +// Copyright (C) 2018 Secure Systems Group, Aalto University +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PARTSFRAMELOWERING_H +#define LLVM_PARTSFRAMELOWERING_H + +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/IR/DebugLoc.h" + +namespace llvm { +namespace PartsFrameLowering { + +void instrumentEpilogue(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, + MachineBasicBlock &MBB); +void instrumentPrologue(const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, + MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &DL); +} +} + +#endif diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp index 47e4c6589c26cb3e953ee1c8dfcf82b8b2ce344d..45628ae66e64f05a6e1024fdf45dc3313a78bb15 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -42,6 +42,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/PARTS/Parts.h" // OHOS_LOCAL #include "llvm/Pass.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" @@ -591,6 +592,11 @@ void AArch64PassConfig::addIRPasses() { if (TM->getTargetTriple().isOSWindows()) addPass(createCFGuardCheckPass()); + // OHOS_LOCAL start + if (PARTS::useFeCfi()) + addPass(PARTS::createPartsPluginPass()); + // OHOS_LOCAL end + if (TM->Options.JMCInstrument) addPass(createJMCInstrumenterPass()); } @@ -643,6 +649,11 @@ bool AArch64PassConfig::addInstSelector() { getOptLevel() != CodeGenOpt::None) addPass(createAArch64CleanupLocalDynamicTLSPass()); + // OHOS_LOCAL start + if (PARTS::useFeCfi()) + // Replace indirect jump instruction such as : BR BLR --> BRAA BLRAA + addPass(createAArch64EarlyPartsCpiPass()); + // OHOS_LOCAL end return false; } @@ -805,6 +816,13 @@ void AArch64PassConfig::addPreEmitPass() { if (TM->getOptLevel() != CodeGenOpt::None && EnableCollectLOH && TM->getTargetTriple().isOSBinFormatMachO()) addPass(createAArch64CollectLOHPass()); + + // OHOS_LOCAL start + if (PARTS::useFeCfi()) + addPass(createAArch64PartsCpiPass()); + if ((PARTS::useDataPointerProtection())) + addPass(createPartsPassDpi()); + // OHOS_LOCAL end } void AArch64PassConfig::addPreEmitPass2() { diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt index e7aba115d6a631bb310e9d2994df575ad07eefa0..1bc430899572070426bce5ce96fc83591fd53b4f 100644 --- a/llvm/lib/Target/AArch64/CMakeLists.txt +++ b/llvm/lib/Target/AArch64/CMakeLists.txt @@ -40,6 +40,7 @@ add_llvm_target(AArch64CodeGen GISel/AArch64PostLegalizerLowering.cpp GISel/AArch64PostSelectOptimize.cpp GISel/AArch64RegisterBankInfo.cpp + AArch64PARTS/PartsFrameLowering.cpp # OHOS_LOCAL AArch64A57FPLoadBalancing.cpp AArch64AdvSIMDScalarPass.cpp AArch64AsmPrinter.cpp @@ -85,9 +86,20 @@ add_llvm_target(AArch64CodeGen AArch64TargetTransformInfo.cpp SVEIntrinsicOpts.cpp AArch64SIMDInstrOpt.cpp + # OHOS_LOCAL start + AArch64PARTS/AArch64EarlyPartsCpiPass.cpp + AArch64PARTS/AArch64PartsCpiPass.cpp + AArch64PARTS/AArch64PartsDpiPass.cpp + # OHOS_LOCAL end DEPENDS intrinsics_gen + # OHOS_LOCAL start + Parts + + LINK_LIBS + Parts + # OHOS_LOCAL end LINK_COMPONENTS AArch64Desc diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index e03b7026f802d735178ce4ee2042b923edf7b52d..4e151a91288d3ed9f64b2c243aa185b7eef9bad2 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -1372,7 +1372,8 @@ Instruction *InstCombinerImpl::visitStoreInst(StoreInst &SI) { // If we have a store to a location which is known constant, we can conclude // that the store must be storing the constant value (else the memory // wouldn't be constant), and this must be a noop. - if (AA->pointsToConstantMemory(Ptr)) + // OHOS_LOCAL: CFI&DFI need add pac for ptr saved in constant memory + if (AA->pointsToConstantMemory(Ptr) && (SI.getFunction()->getFnAttribute("no-parts").getValueAsString() != "true")) return eraseInstFromFunction(SI); // Do really simple DSE, to catch cases where there are several consecutive