diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 80116f79a81a0243d9c82844321d119c4969a384..855caefa7ac088b2ac1d927d095a278c5e5052cf 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1316,6 +1316,13 @@ def Constructor : InheritableAttr { let Documentation = [CtorDtorDocs]; } +def CfiModifier : InheritableAttr { + let Spellings = [GCC<"modifier">]; + let Args = [DefaultIntArgument<"Modifier", 65535>]; + let Subjects = SubjectList<[Function]>; + let Documentation = [CfiModifierDocs]; +} + def CPUSpecific : InheritableAttr { let Spellings = [Clang<"cpu_specific">, Declspec<"cpu_specific">]; let Args = [VariadicIdentifierArgument<"Cpus">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index b5d468eb5ec95291e08e034cbca37c013ce5537d..fd2f848cd17925c8835517948108261c22d14410 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7878,6 +7878,14 @@ attribute, they default to the value ``65535``. }]; } +def CfiModifierDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``modifier`` attribute is used to pass the discriminator value to the pass plugin. +This attribute is added in a specific plugin. Please do not set it manually. +}]; +} + def CoroOnlyDestroyWhenCompleteDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 2b2e23f1e5d7fb64f571a17b6538a9873e4de102..6870ece8662b69f98f7df36e2c8de1fc71948468 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1474,6 +1474,14 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, DebugInfo = nullptr; } + if (FD->hasAttr()) { + llvm::Attribute ModifierAttr + = llvm::Attribute::get(Fn->getContext(), + llvm::Attribute::CfiModifier, + FD->getAttr()->getModifier()); + Fn->addFnAttr(ModifierAttr); + } + // The function might not have a body if we're generating thunks for a // function declaration. SourceRange BodyRange; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index cc9288c9b831832dab49a1debb3a85bdf53db87f..b15351e5c42675bd3dc5c9cd9950c19561e348f3 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1775,8 +1775,17 @@ void RelrBaseSection::mergeRels() { for (const auto &v : relocsVec) newSize += v.size(); relocs.reserve(newSize); - for (const auto &v : relocsVec) - llvm::append_range(relocs, v); + + for (const auto &v : relocsVec) { + for (const auto &reloc : v) { + const OutputSection *relOsec = reloc.inputSec->getOutputSection(); + if (relOsec && relOsec->name == ".cfi.modifier.ro") + relocsCfi.push_back(reloc); + else + relocs.push_back(reloc); + } + } + relocsVec.clear(); } @@ -2123,6 +2132,22 @@ template bool RelrSection::updateAllocSize() { return relrRelocs.size() != oldSize; } +template void RelrSection::writeTo(uint8_t *buf) { + memcpy(buf, relrRelocs.data(), getSize()); + + for (const auto &reloc : relocsCfi) { + if (reloc.inputSec->relocs().size() == 1) { + uint64_t *ptr = + reinterpret_cast(Out::bufferStart + reloc.getOffset()); + auto &rel = reloc.inputSec->relocs()[0]; + if (rel.sym) + *ptr = rel.sym->getVA(rel.addend); + else + *ptr = rel.offset; + } + } +} + SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &strTabSec) : SyntheticSection(strTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, strTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 03aed2a0516d5a85bbbbf435b802567c3da2ea77..1af7d3fdeb3c241d6f764277c3a1de39522d2615 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -615,6 +615,7 @@ public: llvm::any_of(relocsVec, [](auto &v) { return !v.empty(); }); } SmallVector relocs; + SmallVector relocsCfi; SmallVector, 0> relocsVec; }; @@ -630,9 +631,7 @@ public: bool updateAllocSize() override; size_t getSize() const override { return relrRelocs.size() * this->entsize; } - void writeTo(uint8_t *buf) override { - memcpy(buf, relrRelocs.data(), getSize()); - } + void writeTo(uint8_t *buf) override; private: SmallVector relrRelocs; diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h index e381295802009a00298d69bca9646148a28e4c09..aea6e6ba145cb4ff4a5b1830594e7b5a74b0ba00 100644 --- a/llvm/include/llvm/AsmParser/LLParser.h +++ b/llvm/include/llvm/AsmParser/LLParser.h @@ -310,6 +310,7 @@ namespace llvm { bool parseOptionalCallingConv(unsigned &CC); bool parseOptionalAlignment(MaybeAlign &Alignment, bool AllowParens = false); + bool parseOptionalCfiModifier(uint64_t &Modifier, bool AllowParens); bool parseOptionalCodeModel(CodeModel::Model &model); bool parseOptionalDerefAttrBytes(lltok::Kind AttrKind, uint64_t &Bytes); bool parseOptionalUWTableKind(UWTableKind &Kind); diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index fb88f2fe75adb51fe6ede7e9fc226ebff63ea60c..efaedce0318dc050732c3e60ddc438a299abbc72 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -758,6 +758,7 @@ enum AttributeKindCodes { ATTR_KIND_SANITIZE_NUMERICAL_STABILITY = 93, ATTR_KIND_INITIALIZES = 94, ATTR_KIND_HYBRID_PATCHABLE = 95, + ATTR_KIND_CFI_MODIFIER = 96, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h index 5a80a072dbbd274629b670623364e293cfd2c44a..cd20322bb8cb9160667eadb3d8c542c5fddb35a8 100644 --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -1229,6 +1229,9 @@ public: /// Add memory effect attribute. AttrBuilder &addMemoryAttr(MemoryEffects ME); + /// Add cfi modifier attribute. + AttrBuilder &addCfiModifierAttr(uint64_t Modifier); + // Add nofpclass attribute AttrBuilder &addNoFPClassAttr(FPClassTest NoFPClassMask); diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index e1bd193891c1e1dd3c1379d95c96493df794d401..01eb24d3c6c7854d3304f99e737b9ff4315bf6ee 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -136,6 +136,9 @@ def Memory : IntAttr<"memory", [FnAttr]>; /// Forbidden floating-point classes. def NoFPClass : IntAttr<"nofpclass", [ParamAttr, RetAttr]>; +/// Save cfi modifier +def CfiModifier : IntAttr<"cfimodifier", [FnAttr]>; + /// Function must be optimized for size first. def MinSize : EnumAttr<"minsize", [FnAttr]>; diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index a886f6e3a4b93df8c21e45e021e1b75db421cc1a..8ecf5afd2bc2c811907716f0ec641d29c6d8b1c0 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1580,6 +1580,19 @@ bool LLParser::parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B, B.addStackAlignmentAttr(Alignment); return false; } + case Attribute::CfiModifier: { + uint64_t Value = 0; + if (InAttrGroup) { + Lex.Lex(); + if (parseToken(lltok::equal, "expected '=' here") || parseUInt64(Value)) + return true; + } else { + if (parseOptionalCfiModifier(Value, true)) + return true; + } + B.addCfiModifierAttr(Value); + return false; + } case Attribute::AllocSize: { unsigned ElemSizeArg; std::optional NumElemsArg; @@ -2380,6 +2393,32 @@ bool LLParser::parseOptionalAlignment(MaybeAlign &Alignment, bool AllowParens) { return false; } +/// parseOptionalCfiModifier +/// ::= /* empty */ +/// ::= 'cfimodifier' 18596 +bool LLParser::parseOptionalCfiModifier(uint64_t &Modifier, bool AllowParens) { + Modifier = 0; + if (!EatIfPresent(lltok::kw_cfimodifier)) + return false; + uint64_t Value = 0; + + LocTy ParenLoc = Lex.getLoc(); + bool HaveParens = false; + if (AllowParens) { + if (EatIfPresent(lltok::lparen)) + HaveParens = true; + } + + if (parseUInt64(Value)) + return true; + + if (HaveParens && !EatIfPresent(lltok::rparen)) + return error(ParenLoc, "expected ')'"); + + Modifier = Value; + return false; +} + /// parseOptionalCodeModel /// ::= /* empty */ /// ::= 'code_model' "large" diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 84d624f6cf8fa2576f84ee72e5c884163c99f2af..97e06b3176a579508d0dba672cda2faf6edb39f4 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2185,6 +2185,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::Range; case bitc::ATTR_KIND_INITIALIZES: return Attribute::Initializes; + case bitc::ATTR_KIND_CFI_MODIFIER: + return Attribute::CfiModifier; } } @@ -2327,6 +2329,8 @@ Error BitcodeReader::parseAttributeGroupBlock() { else if (Kind == Attribute::NoFPClass) B.addNoFPClassAttr( static_cast(Record[++i] & fcAllFlags)); + else if (Kind == Attribute::CfiModifier) + B.addCfiModifierAttr(Record[++i]); } else if (Record[i] == 3 || Record[i] == 4) { // String attribute bool HasValue = (Record[i++] == 4); SmallString<64> KindStr; diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 324dcbca8137ed56078f91e1794529a5207753d6..9fc67febe7608fab17df331a24c6bf917a387ee5 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -745,6 +745,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_MEMORY; case Attribute::NoFPClass: return bitc::ATTR_KIND_NOFPCLASS; + case Attribute::CfiModifier: + return bitc::ATTR_KIND_CFI_MODIFIER; case Attribute::Naked: return bitc::ATTR_KIND_NAKED; case Attribute::Nest: diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index b2fdd218e5d4bf1f03be2f6d65b6fed611f64fbb..2400081819ae293c1ccce742406d717209be445a 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -550,6 +550,9 @@ std::string Attribute::getAsString(bool InAttrGrp) const { .str(); }; + if (hasAttribute(Attribute::CfiModifier)) + return AttrWithBytesToString("cfimodifier"); + if (hasAttribute(Attribute::StackAlignment)) return AttrWithBytesToString("alignstack"); @@ -1977,6 +1980,10 @@ AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) { return addRawIntAttr(Attribute::Memory, ME.toIntValue()); } +AttrBuilder &AttrBuilder::addCfiModifierAttr(uint64_t Modifier) { + return addRawIntAttr(Attribute::CfiModifier, Modifier); +} + AttrBuilder &AttrBuilder::addNoFPClassAttr(FPClassTest Mask) { if (Mask == fcNone) return *this; diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp index 889de3a81536d1c5a8c35b5361706fd7c54ca3ae..53fadcbf3b02abaeeaef107421bda4029ba93df1 100644 --- a/llvm/lib/Target/DirectX/DXILPrepare.cpp +++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp @@ -72,6 +72,7 @@ constexpr bool isValidForDXIL(Attribute::AttrKind Attr) { Attribute::ReturnsTwice, Attribute::SExt, Attribute::StackAlignment, + Attribute::CfiModifier, Attribute::StackProtect, Attribute::StackProtectReq, Attribute::StackProtectStrong, diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp index 3433408f051715daab9b78a94d2bda16e7537550..7b787aeda3ce5aa6d9bdb668f9b29408225f0769 100644 --- a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp +++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp @@ -682,6 +682,8 @@ uint64_t DXILBitcodeWriter::getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_S_EXT; case Attribute::StackAlignment: return bitc::ATTR_KIND_STACK_ALIGNMENT; + case Attribute::CfiModifier: + return bitc::ATTR_KIND_CFI_MODIFIER; case Attribute::StackProtect: return bitc::ATTR_KIND_STACK_PROTECT; case Attribute::StackProtectReq: diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 5bca5cf8ff91f7c0acfbcc2d422a14caa151d04e..e3263ebeedd0acf1ff48083d30f87313c8c62668 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -924,6 +924,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::PresplitCoroutine: case Attribute::Memory: case Attribute::NoFPClass: + case Attribute::CfiModifier: case Attribute::CoroDestroyOnlyWhenComplete: continue; // Those attributes should be safe to propagate to the extracted function.