diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 644dcf1710cb8..850726e93256b 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4642,6 +4642,12 @@ def CheriConditionalSeal : Builtin { let Prototype = "void* __capability(void const* __capability,void const* __capability)"; } +def CHERIoTEmitSealingType : Builtin { + let Spellings = ["__builtin_cheriot_sealing_type"]; + let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Prototype = "void*(char const*)"; +} + // Safestack builtins. def GetUnsafeStackStart : Builtin { let Spellings = ["__builtin___get_unsafe_stack_start"]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 06f3df5343969..52c79f9c440f3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -155,6 +155,10 @@ def err_cheriot_non_addr_of_expr_on_sealed "the only valid operation on a sealed value is to take its address">; def err_cheriot_invalid_sealed_declaration : Error<"cannot declare a sealed variable as %0">; +def err_cheriot_invalid_sealing_key_type_name + : Error<"the sealing key type name '%0' is not a valid identifier">; +def err_cheriot_use_of_builtin_sealing_key_type_no_compartment + : Error<"%0 used, but no compartment name given">; // C99 variable-length arrays def ext_vla : Extension<"variable length arrays are a C99 feature">, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d39415aad19db..a8a2eef99b9aa 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6154,6 +6154,53 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(Builder.CreateIntrinsic( llvm::Intrinsic::cheri_cap_perms_check, {SizeTy}, {Cap, Perms})); } + case Builtin::BI__builtin_cheriot_sealing_type: { + const auto *ArgLit = dyn_cast(E->getArg(0)); + assert(ArgLit && "Argument to built-in should be a string literal!"); + + auto SealingTypeName = ArgLit->getString().str(); + auto CompartmentName = getLangOpts().CheriCompartmentName; + auto PrefixedImportName = + CHERIoTSealingKeyTypeAttr::getSealingTypeSymbolName(CompartmentName, + SealingTypeName); + auto &Mod = CGM.getModule(); + auto MangledImportName = "__import." + PrefixedImportName; + auto *GV = Mod.getGlobalVariable(MangledImportName); + + if (!GV) { + // This global exists only so that we have a pointer to it and is more + // akin to a GOT entry than a "real" global value: it just + // represents a pointer that we have a way of getting. + + auto *OpaqueTypeName = "struct.__CHERIoT__OpaqueSealingKeyType"; + llvm::StructType *OpaqueType = + llvm::StructType::getTypeByName(CGM.getLLVMContext(), OpaqueTypeName); + + if (!OpaqueType) + OpaqueType = llvm::StructType::create(CGM.getModule().getContext(), + OpaqueTypeName); + else if (!OpaqueType->isOpaque()) + CGM.Error(E->getBeginLoc(), + std::string("type '") + OpaqueTypeName + + "' already exists, but is not an opaque type!"); + + GV = new GlobalVariable(CGM.getModule(), OpaqueType, true, + GlobalValue::ExternalLinkage, nullptr, + MangledImportName); + GV->addAttribute(CHERIoTSealingKeyTypeAttr::getAttrName(), + PrefixedImportName); + GV->addAttribute("cheri-compartment", CompartmentName); + } else { + auto *GVType = dyn_cast(GV->getValueType()); + + if (!GVType || !GVType->isOpaque()) + CGM.Error(E->getBeginLoc(), + std::string("global variable '") + MangledImportName + + "' already exists, but its type is not opaque!"); + } + + return RValue::get(GV); + } // Round to capability precision: // TODO: should we handle targets that don't have any precision constraints // here or in the backend? diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index fcaddda369e7b..5d50c6036ae5d 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2920,6 +2920,30 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; + case Builtin::BI__builtin_cheriot_sealing_type: { + if (checkArgCount(TheCall, 1)) + return ExprError(); + auto *Arg = dyn_cast(TheCall->getArg(0)); + if (!Arg) + return ExprError(); + auto ArgLit = Arg->getString(); + if (!isValidAsciiIdentifier(ArgLit)) { + std::string Escaped; + llvm::raw_string_ostream OS(Escaped); + llvm::printEscapedString(ArgLit, OS); + OS.flush(); + Diag(Arg->getExprLoc(), diag::err_cheriot_invalid_sealing_key_type_name) + << Escaped; + return ExprError(); + } + if (getLangOpts().CheriCompartmentName.empty()) { + Diag(Arg->getExprLoc(), + diag::err_cheriot_use_of_builtin_sealing_key_type_no_compartment) + << Context.BuiltinInfo.getName( + Builtin::BI__builtin_cheriot_sealing_type); + } + break; + } // OpenCL v2.0, s6.13.16 - Pipe functions case Builtin::BIread_pipe: case Builtin::BIwrite_pipe: diff --git a/clang/test/CodeGen/cheri/riscv/cheriot-sealing-type-builtin.c b/clang/test/CodeGen/cheri/riscv/cheriot-sealing-type-builtin.c new file mode 100644 index 0000000000000..cb94334dc4a6f --- /dev/null +++ b/clang/test/CodeGen/cheri/riscv/cheriot-sealing-type-builtin.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 %s -o - "-triple" "riscv32cheriot-unknown-unknown-cheriotrtos" "-emit-llvm" "-cheri-compartment=static_sealing_test" "-mframe-pointer=none" "-mcmodel=small" "-target-abi" "cheriot" "-O0" "-Werror" -std=c2x | FileCheck %s + + +struct StructSealingKey { }; +enum EnumSealingKey { SEALING_KEY_KIND1, SEALING_KEY_KIND2 }; +typedef enum EnumSealingKey TypeDefSealingKey; + +// CHECK: %struct.__CHERIoT__OpaqueSealingKeyType = type opaque +// CHECK: @__import.sealing_type.static_sealing_test.StructSealingKey = external addrspace(200) constant %struct.__CHERIoT__OpaqueSealingKeyType #0 +// CHECK: @__import.sealing_type.static_sealing_test.EnumSealingKey = external addrspace(200) constant %struct.__CHERIoT__OpaqueSealingKeyType #1 +// CHECK: @__import.sealing_type.static_sealing_test.TypeDefSealingKey = external addrspace(200) constant %struct.__CHERIoT__OpaqueSealingKeyType #2 +// CHECK: @__import.sealing_type.static_sealing_test.int = external addrspace(200) constant %struct.__CHERIoT__OpaqueSealingKeyType #3 + +// CHECK: define dso_local void @func() addrspace(200) #4 { +void func() { + +// CHECK: entry: +// CHECK: %SealingKey1 = alloca ptr addrspace(200), align 8, addrspace(200) +// CHECK: %SealingKey2 = alloca ptr addrspace(200), align 8, addrspace(200) +// CHECK: %SealingKey3 = alloca ptr addrspace(200), align 8, addrspace(200) +// CHECK: %SealingKey4 = alloca ptr addrspace(200), align 8, addrspace(200) +// CHECK: %SealingKey5 = alloca ptr addrspace(200), align 8, addrspace(200) +// CHECK: %SealingKey6 = alloca ptr addrspace(200), align 8, addrspace(200) +// CHECK: %SealingKey7 = alloca ptr addrspace(200), align 8, addrspace(200) + +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.StructSealingKey, ptr addrspace(200) %SealingKey1, align 8 + struct StructSealingKey *SealingKey1 = __builtin_cheriot_sealing_type("StructSealingKey"); + +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.EnumSealingKey, ptr addrspace(200) %SealingKey2, align 8 + enum EnumSealingKey *SealingKey2 = __builtin_cheriot_sealing_type("EnumSealingKey"); + +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.TypeDefSealingKey, ptr addrspace(200) %SealingKey3, align 8 + TypeDefSealingKey *SealingKey3 = __builtin_cheriot_sealing_type("TypeDefSealingKey"); + +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey4, align 8 + int *SealingKey4 = __builtin_cheriot_sealing_type("int"); + +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey5, align 8 + int *SealingKey5 = __builtin_cheriot_sealing_type("int"); +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey6, align 8 + int *SealingKey6 = __builtin_cheriot_sealing_type("int"); +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey7, align 8 + int *SealingKey7 = __builtin_cheriot_sealing_type("int"); + +// CHECK: ret void +} + +// CHECK: attributes #0 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.StructSealingKey" } +// CHECK: attributes #1 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.EnumSealingKey" } +// CHECK: attributes #2 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.TypeDefSealingKey" } +// CHECK: attributes #3 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.int" } diff --git a/clang/test/Sema/cheri/cheriot-sealing-type-builtin.c b/clang/test/Sema/cheri/cheriot-sealing-type-builtin.c new file mode 100644 index 0000000000000..dffa4b13f3529 --- /dev/null +++ b/clang/test/Sema/cheri/cheriot-sealing-type-builtin.c @@ -0,0 +1,12 @@ +// RUN: %riscv32_cheri_cc1 "-triple" "riscv32cheriot-unknown-unknown" "-target-abi" "cheriot" -verify %s + +void func() { + int *k1 = __builtin_cheriot_sealing_type(MySealingType); // expected-error{{use of undeclared identifier 'MySealingType'}} + int *k2 = __builtin_cheriot_sealing_type("This is my key"); // expected-error{{the sealing key type name 'This is my key' is not a valid identifier}} + int *k3 = __builtin_cheriot_sealing_type("αβγδ"); // expected-error{{the sealing key type name '\CE\B1\CE\B2\CE\B3\CE\B4' is not a valid identifier}} + int *k4 = __builtin_cheriot_sealing_type("a\0b"); // expected-error{{the sealing key type name 'a\00b' is not a valid identifier}} + int *k5 = __builtin_cheriot_sealing_type("a\"b"); // expected-error{{the sealing key type name 'a\22b' is not a valid identifier}} + int *k6 = __builtin_cheriot_sealing_type("a\nb"); // expected-error{{the sealing key type name 'a\0Ab' is not a valid identifier}} + int *k7 = __builtin_cheriot_sealing_type("a\bb"); // expected-error{{the sealing key type name 'a\08b' is not a valid identifier}} + int *k8 = __builtin_cheriot_sealing_type("ab"); // expected-error{{__builtin_cheriot_sealing_type used, but no compartment name given}} +} diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h index 9b7328f68694b..dae6613391908 100644 --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -1614,6 +1614,23 @@ class CHERIoTSealedValueAttr { /// Get the name of the attribute. static const std::string getAttrName() { return "cheriot_sealed_value"; } }; + +/// Represents the LLVM-level attribute that is used to signal +/// that a global (variable) represents a sealing key type. +class CHERIoTSealingKeyTypeAttr { +public: + /// Get the name of the attribute. + static const std::string getAttrName() { return "cheriot_sealing_key"; } + + /// Get the mangled name of the symbol representing the sealing key. + static const std::string + getSealingTypeSymbolName(StringRef CompartmentName, + StringRef SealingKeyTypeName) { + return "sealing_type." + CompartmentName.str() + "." + + SealingKeyTypeName.str(); + } +}; + } // end namespace llvm #endif // LLVM_IR_ATTRIBUTES_H diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp index 98329b543a876..4eb54e1396a9e 100644 --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -114,12 +114,10 @@ class RISCVAsmPrinter : public AsmPrinter { private: /** - * Struct describing compartment exports that must be emitted for this - * compilation unit. + * Struct describing function-like compartment export objects. */ - struct CompartmentExport - { - /// The compartment name for the function. + struct FunctionCompartmentExport { + /// The compartment name for the object. std::string CompartmentName; /// The IR function corresponding to the function. const Function &Fn; @@ -132,9 +130,26 @@ class RISCVAsmPrinter : public AsmPrinter { /// The size in bytes of the stack frame, 0 if not used. uint32_t stackSize = 0; }; - SmallVector CompartmentEntries; + + /** + * Struct describing sealing key-like compartment export objects. + */ + struct SealingKeyCompartmentExport { + /// The compartment name for the object. + std::string CompartmentName; + /// The name of the sealing key type. + std::string SealingKeyTypeName; + + bool operator==(const SealingKeyCompartmentExport &Other) { + return this->CompartmentName == Other.CompartmentName && + this->SealingKeyTypeName == Other.SealingKeyTypeName; + } + }; + + SmallVector FNCompartmentEntries; + SmallVector SKCompartmentEntries; SmallDenseMap, 1> - CompartmentEntryAliases; + FnCompartmentEntryAliases; void emitAttributes(const MCSubtargetInfo &SubtargetInfo); @@ -312,6 +327,20 @@ void RISCVAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { return; } + auto CheriotSealingKeyTypeAttrName = + llvm::CHERIoTSealingKeyTypeAttr::getAttrName(); + + if (GV->hasAttribute(CheriotSealingKeyTypeAttrName)) { + auto Attr = GV->getAttribute(CheriotSealingKeyTypeAttrName); + auto Entry = SealingKeyCompartmentExport{ + std::string(GV->getAttribute("cheri-compartment").getValueAsString()), + Attr.getValueAsString().str()}; + if (std::find(SKCompartmentEntries.begin(), SKCompartmentEntries.end(), + Entry) == SKCompartmentEntries.end()) { + SKCompartmentEntries.push_back(Entry); + } + } + // Continue through the normal path to emit the global. return AsmPrinter::emitGlobalVariable(GV); } @@ -320,9 +349,12 @@ void RISCVAsmPrinter::emitGlobalAlias(const Module &M, const GlobalAlias &GA) { AsmPrinter::emitGlobalAlias(M, GA); const MCSubtargetInfo &SubtargetInfo = *TM.getMCSubtargetInfo(); + auto CheriotSealingKeyTypeAttrName = + llvm::CHERIoTSealingKeyTypeAttr::getAttrName(); + if (SubtargetInfo.hasFeature(RISCV::FeatureVendorXCheriot)) { if (auto *Fn = dyn_cast(GA.getAliasee()->stripPointerCasts())) { - CompartmentEntryAliases[Fn].push_back(&GA); + FnCompartmentEntryAliases[Fn].push_back(&GA); } } } @@ -582,17 +614,17 @@ bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) { } else stackSize = MF.getFrameInfo().getStackSize(); // FIXME: Get stack size as function attribute if specified - CompartmentEntries.push_back( + FNCompartmentEntries.push_back( {std::string(Fn.getFnAttribute("cheri-compartment").getValueAsString()), Fn, OutStreamer->getContext().getOrCreateSymbol(MF.getName()), countUsedArgRegisters(MF) + interruptFlag, false, stackSize}); } else if (Fn.getCallingConv() == CallingConv::CHERI_LibCall) - CompartmentEntries.push_back( + FNCompartmentEntries.push_back( {"libcalls", Fn, OutStreamer->getContext().getOrCreateSymbol(MF.getName()), countUsedArgRegisters(MF) + interruptFlag}); else if (interruptFlag != 0) - CompartmentEntries.push_back( + FNCompartmentEntries.push_back( {std::string(Fn.getFnAttribute("cheri-compartment").getValueAsString()), Fn, OutStreamer->getContext().getOrCreateSymbol(MF.getName()), countUsedArgRegisters(MF) + interruptFlag, true}); @@ -698,21 +730,21 @@ void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) { RISCVTargetStreamer &RTS = static_cast(*OutStreamer->getTargetStreamer()); - if (!CompartmentEntries.empty()) { + if (!FNCompartmentEntries.empty()) { auto &C = OutStreamer->getContext(); - auto *Exports = C.getELFSection(".compartment_exports", ELF::SHT_PROGBITS, - ELF::SHF_ALLOC | ELF::SHF_GNU_RETAIN); - OutStreamer->switchSection(Exports); auto CompartmentStartSym = C.getOrCreateSymbol("__compartment_pcc_start"); - for (auto &Entry : CompartmentEntries) { + for (auto &Entry : FNCompartmentEntries) { + auto *Exports = C.getELFSection(".compartment_exports", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_GNU_RETAIN); + OutStreamer->switchSection(Exports); std::string ExportName = getImportExportTableName( Entry.CompartmentName, Entry.Fn.getName(), Entry.Fn.getCallingConv(), /*IsImport*/ false); auto Sym = C.getOrCreateSymbol(ExportName); OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject); - // If the function isn't global, don't make its export table entry global - // either. Two different compilation units in the same compartment may - // export different static things. + // If the function isn't global, don't make its export table entry + // global either. Two different compilation units in the same + // compartment may export different static things. if (Entry.Fn.hasExternalLinkage() && !Entry.forceLocal) OutStreamer->emitSymbolAttribute(Sym, MCSA_Global); OutStreamer->emitValueToAlignment(Align(4)); @@ -727,8 +759,8 @@ void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) { OutStreamer->emitELFSize(Sym, MCConstantExpr::create(4, C)); // Emit aliases for this export symbol entry. - auto I = CompartmentEntryAliases.find(&Entry.Fn); - if (I == CompartmentEntryAliases.end()) + auto I = FnCompartmentEntryAliases.find(&Entry.Fn); + if (I == FnCompartmentEntryAliases.end()) continue; for (const GlobalAlias *GA : I->second) { std::string AliasExportName = getImportExportTableName( @@ -747,6 +779,29 @@ void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) { } } } + + if (!SKCompartmentEntries.empty()) { + auto &C = OutStreamer->getContext(); + for (auto &Entry : SKCompartmentEntries) { + auto ExportName = Entry.SealingKeyTypeName; + auto MangledExportName = "__export." + ExportName; + auto *Sym = C.getOrCreateSymbol(MangledExportName); + auto *Exports = C.getELFSection( + ".compartment_exports." + ExportName, ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_GROUP, 0, ExportName, + true); + OutStreamer->switchSection(Exports); + OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeObject); + OutStreamer->emitSymbolAttribute(Sym, MCSA_Global); + OutStreamer->emitValueToAlignment(Align(4)); + OutStreamer->emitLabel(Sym); + OutStreamer->emitIntValue(0, 2); + OutStreamer->emitIntValue(0, 1); + OutStreamer->emitIntValue(0b100000, 1); + OutStreamer->emitELFSize(Sym, MCConstantExpr::create(4, C)); + } + } + // Generate CHERIoT imports if there are any. auto &CHERIoTCompartmentImports = static_cast(TM).ImportedObjects; diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp index 76c3e1fded99e..f68915c4c561e 100644 --- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp +++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp @@ -570,6 +570,9 @@ bool RISCVExpandPseudo::expandAuipccInstPair( std::optional CheriotCapImportAttr = std::nullopt; auto CheriotSealedValueAttrName = llvm::CHERIoTSealedValueAttr::getAttrName(); std::optional CheriotSealedValueAttr = std::nullopt; + auto CheriotSealingKeyTypeAttrName = + llvm::CHERIoTSealingKeyTypeAttr::getAttrName(); + std::optional CheriotSealingKeyTypeAttr = std::nullopt; if (Symbol.isGlobal()) { auto *GV = llvm::dyn_cast(Symbol.getGlobal()); @@ -580,6 +583,10 @@ bool RISCVExpandPseudo::expandAuipccInstPair( CheriotSealedValueAttr.emplace( GV->getAttribute(CheriotSealedValueAttrName)); } + if (GV && GV->hasAttribute(CheriotSealingKeyTypeAttrName)) { + CheriotSealingKeyTypeAttr.emplace( + GV->getAttribute(CheriotSealingKeyTypeAttrName)); + } } if (CheriotCapImportAttr.has_value()) { @@ -659,6 +666,26 @@ bool RISCVExpandPseudo::expandAuipccInstPair( CHERIoTImportedObject::WritableFlagValue::IsWritable, CHERIoTImportedObject::SecondWordKind::SizeOfTypeSecondWord, TypeSize}); + } else if (CheriotSealingKeyTypeAttr.has_value()) { + MCContext &Ctxt = MF->getContext(); + auto KeyTypeAttr = CheriotSealingKeyTypeAttr.value(); + auto SealingKeySymbol = KeyTypeAttr.getValueAsString(); + auto MangledImportName = "__import." + SealingKeySymbol.str(); + auto MangledExportName = "__export." + SealingKeySymbol.str(); + MCSymbol *MangledImportSymbol = Ctxt.getOrCreateSymbol(MangledImportName); + + BuildMI(NewMBB, DL, TII->get(RISCV::AUIPCC), TmpReg) + .addSym(MangledImportSymbol, FlagsHi); + ImportedObjects.insert( + {MangledImportName, MangledExportName, SealingKeySymbol.str(), + CHERIoTImportedObject::LibraryFlagValue::IsNotLibrary, + CHERIoTImportedObject::PublicFlagValue::IsPublic, + CHERIoTImportedObject::GlobalFlagValue::IsGlobal, + CHERIoTImportedObject::COMDATFlagValue::IsCOMDAT, + CHERIoTImportedObject::WeakFlagValue::IsNotWeak, + CHERIoTImportedObject::GroupedFlagValue::IsGrouped, + CHERIoTImportedObject::WritableFlagValue::IsWritable, + CHERIoTImportedObject::SecondWordKind::SizeOfTypeSecondWord, 0}); } else { BuildMI(NewMBB, DL, TII->get(RISCV::AUIPCC), TmpReg) .addDisp(Symbol, 0, FlagsHi); @@ -669,7 +696,8 @@ bool RISCVExpandPseudo::expandAuipccInstPair( .addMBB(NewMBB, IsCheriot ? RISCVII::MO_CHERIOT_COMPARTMENT_LO_I : RISCVII::MO_PCREL_LO); if (!CheriotSealedValueAttr.has_value() && - !CheriotCapImportAttr.has_value() && !InBounds && + !CheriotCapImportAttr.has_value() && + !CheriotSealingKeyTypeAttr.has_value() && !InBounds && MF->getSubtarget().isRV32E() && Symbol.isGlobal() && isa(Symbol.getGlobal()) && (cast(Symbol.getGlobal())->getSection() != @@ -712,7 +740,8 @@ bool RISCVExpandPseudo::expandCapLoadLocalCap( if (GVar && (GVar->hasAttribute( llvm::CHERIoTGlobalCapabilityImportAttr::getAttrName()) || - GVar->hasAttribute(llvm::CHERIoTSealedValueAttr::getAttrName()))) { + GVar->hasAttribute(llvm::CHERIoTSealedValueAttr::getAttrName()) || + GVar->hasAttribute(llvm::CHERIoTSealingKeyTypeAttr::getAttrName()))) { return expandAuipccInstPair(MBB, MBBI, NextMBBI, RISCVII::MO_CHERIOT_COMPARTMENT_HI, RISCV::CLC_64); diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index f8792e859ccc3..74981d853c124 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -8240,8 +8240,11 @@ SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op, llvm::CHERIoTGlobalCapabilityImportAttr::getAttrName(); auto GlobalSealedValueAttrName = llvm::CHERIoTSealedValueAttr::getAttrName(); + auto GlobalSealingKeyTypeAttrName = + llvm::CHERIoTSealingKeyTypeAttr::getAttrName(); if (GVar->hasAttribute(GlobalCapImportAttrName) || - GVar->hasAttribute(GlobalSealedValueAttrName)) { + GVar->hasAttribute(GlobalSealedValueAttrName) || + GVar->hasAttribute(GlobalSealingKeyTypeAttrName)) { SDLoc DL(N); SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); // Force it to be lowered to a `CLLC` regardless what `getAddr` would diff --git a/llvm/test/CodeGen/RISCV/cheri/cheriot-sealing-key-attr.ll b/llvm/test/CodeGen/RISCV/cheri/cheriot-sealing-key-attr.ll new file mode 100644 index 0000000000000..17468909cde17 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/cheri/cheriot-sealing-key-attr.ll @@ -0,0 +1,132 @@ +; RUN: llc -O0 --filetype=asm --mcpu=cheriot --mtriple=riscv32-unknown-unknown-cheriotrtos -target-abi cheriot -mattr=+xcheri,+cap-mode < %s | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128-pf200:64:64:64:32-A200-P200-G200" +target triple = "riscv32-unknown-cheriotrtos-unknown" + +%struct.OpaqueSealingKeyType = type opaque + +@__import.sealing_type.static_sealing_test.StructSealingKey = external addrspace(200) constant %struct.OpaqueSealingKeyType #0 +@__import.sealing_type.static_sealing_test.EnumSealingKey = external addrspace(200) constant %struct.OpaqueSealingKeyType #1 +@__import.sealing_type.static_sealing_test.TypeDefSealingKey = external addrspace(200) constant %struct.OpaqueSealingKeyType #2 +@__import.sealing_type.static_sealing_test.int = external addrspace(200) constant %struct.OpaqueSealingKeyType #3 +;; Test that repeated sealing keys do not generate two separate entries. +@__import.sealing_type.static_sealing_test.int2 = external addrspace(200) constant %struct.OpaqueSealingKeyType #3 + + +; Function Attrs: noinline nounwind optnone +define dso_local void @func() #4 { +entry: + + %SealingKey1 = alloca ptr, align 8, addrspace(200) + %SealingKey2 = alloca ptr, align 8, addrspace(200) + %SealingKey3 = alloca ptr, align 8, addrspace(200) + %SealingKey4 = alloca ptr, align 8, addrspace(200) + %SealingKey5 = alloca ptr, align 8, addrspace(200) +; CHECK: .LBB0_1: # %entry +; CHECK: # Label of block must be emitted +; CHECK: auipcc ca0, %cheriot_compartment_hi(__import.sealing_type.static_sealing_test.StructSealingKey) +; CHECK: clc ca0, %cheriot_compartment_lo_i(.LBB0_1)(ca0) + store ptr addrspace(200) @__import.sealing_type.static_sealing_test.StructSealingKey, ptr addrspace(200) %SealingKey1, align 8 +; CHECK: .LBB0_2: # %entry +; CHECK: # Label of block must be emitted +; CHECK: auipcc ca0, %cheriot_compartment_hi(__import.sealing_type.static_sealing_test.EnumSealingKey) +; CHECK: clc ca0, %cheriot_compartment_lo_i(.LBB0_2)(ca0) + store ptr addrspace(200) @__import.sealing_type.static_sealing_test.EnumSealingKey, ptr addrspace(200) %SealingKey2, align 8 +; CHECK: .LBB0_3: # %entry +; CHECK: # Label of block must be emitted +; CHECK: auipcc ca0, %cheriot_compartment_hi(__import.sealing_type.static_sealing_test.TypeDefSealingKey) +; CHECK: clc ca0, %cheriot_compartment_lo_i(.LBB0_3)(ca0) + store ptr addrspace(200) @__import.sealing_type.static_sealing_test.TypeDefSealingKey, ptr addrspace(200) %SealingKey3, align 8 +; CHECK: .LBB0_4: # %entry +; CHECK: # Label of block must be emitted +; CHECK: auipcc ca0, %cheriot_compartment_hi(__import.sealing_type.static_sealing_test.int) +; CHECK: clc ca0, %cheriot_compartment_lo_i(.LBB0_4)(ca0) + store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey4, align 8 +; CHECK: .LBB0_5: # %entry +; CHECK: # Label of block must be emitted +; CHECK: auipcc ca0, %cheriot_compartment_hi(__import.sealing_type.static_sealing_test.int) +; CHECK: clc ca0, %cheriot_compartment_lo_i(.LBB0_5)(ca0) + store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int2, ptr addrspace(200) %SealingKey5, align 8 +; CHECK: cret +; CHECK: .Lfunc_end0: +; CHECK: .size func, .Lfunc_end0-func + ret void +} + +attributes #0 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.StructSealingKey" } +attributes #1 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.EnumSealingKey" } +attributes #2 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.TypeDefSealingKey" } +attributes #3 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.int" } +attributes #4 = { noinline nounwind optnone "cheri-compartment"="test" "frame-pointer"="none" "interrupt-state"="enabled" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cheriot" "target-features"="+relax,+xcheri,+xcheri-rvc,-64bit,-save-restore" } + +; CHECK: __export.sealing_type.static_sealing_test.StructSealingKey: +; CHECK: .half 0 +; CHECK: .byte 0 +; CHECK: .byte 32 +; CHECK: .size __export.sealing_type.static_sealing_test.StructSealingKey, 4 +; CHECK: .section .compartment_exports.sealing_type.static_sealing_test.EnumSealingKey,"awG",@progbits,sealing_type.static_sealing_test.EnumSealingKey,comdat +; CHECK: .type __export.sealing_type.static_sealing_test.EnumSealingKey,@object +; CHECK: .globl __export.sealing_type.static_sealing_test.EnumSealingKey +; CHECK: .p2align 2, 0x0 +; CHECK: __export.sealing_type.static_sealing_test.EnumSealingKey: +; CHECK: .half 0 +; CHECK: .byte 0 +; CHECK: .byte 32 +; CHECK: .size __export.sealing_type.static_sealing_test.EnumSealingKey, 4 +; CHECK: .section .compartment_exports.sealing_type.static_sealing_test.TypeDefSealingKey,"awG",@progbits,sealing_type.static_sealing_test.TypeDefSealingKey,comdat +; CHECK: .type __export.sealing_type.static_sealing_test.TypeDefSealingKey,@object +; CHECK: .globl __export.sealing_type.static_sealing_test.TypeDefSealingKey +; CHECK: .p2align 2, 0x0 +; CHECK: __export.sealing_type.static_sealing_test.TypeDefSealingKey: +; CHECK: .half 0 +; CHECK: .byte 0 +; CHECK: .byte 32 +; CHECK: .size __export.sealing_type.static_sealing_test.TypeDefSealingKey, 4 +; CHECK: .section .compartment_exports.sealing_type.static_sealing_test.int,"awG",@progbits,sealing_type.static_sealing_test.int,comdat +; CHECK: .type __export.sealing_type.static_sealing_test.int,@object +; CHECK: .globl __export.sealing_type.static_sealing_test.int +; CHECK: .p2align 2, 0x0 +; CHECK: __export.sealing_type.static_sealing_test.int: +; CHECK: .half 0 +; CHECK: .byte 0 +; CHECK: .byte 32 +; CHECK: .size __export.sealing_type.static_sealing_test.int, 4 +; CHECK: .section .compartment_imports.sealing_type.static_sealing_test.StructSealingKey,"awG",@progbits,__import.sealing_type.static_sealing_test.StructSealingKey,comdat +; CHECK: .type __import.sealing_type.static_sealing_test.StructSealingKey,@object +; CHECK: .globl __import.sealing_type.static_sealing_test.StructSealingKey +; CHECK: .p2align 3, 0x0 +; CHECK: __import.sealing_type.static_sealing_test.StructSealingKey: +; CHECK: .word __export.sealing_type.static_sealing_test.StructSealingKey +; CHECK: .word 0 +; CHECK: .size __import.sealing_type.static_sealing_test.StructSealingKey, 8 +; CHECK: .section .compartment_imports.sealing_type.static_sealing_test.EnumSealingKey,"awG",@progbits,__import.sealing_type.static_sealing_test.EnumSealingKey,comdat +; CHECK: .type __import.sealing_type.static_sealing_test.EnumSealingKey,@object +; CHECK: .globl __import.sealing_type.static_sealing_test.EnumSealingKey +; CHECK: .p2align 3, 0x0 +; CHECK: __import.sealing_type.static_sealing_test.EnumSealingKey: +; CHECK: .word __export.sealing_type.static_sealing_test.EnumSealingKey +; CHECK: .word 0 +; CHECK: .size __import.sealing_type.static_sealing_test.EnumSealingKey, 8 +; CHECK: .section .compartment_imports.sealing_type.static_sealing_test.TypeDefSealingKey,"awG",@progbits,__import.sealing_type.static_sealing_test.TypeDefSealingKey,comdat +; CHECK: .type __import.sealing_type.static_sealing_test.TypeDefSealingKey,@object +; CHECK: .globl __import.sealing_type.static_sealing_test.TypeDefSealingKey +; CHECK: .p2align 3, 0x0 +; CHECK: __import.sealing_type.static_sealing_test.TypeDefSealingKey: +; CHECK: .word __export.sealing_type.static_sealing_test.TypeDefSealingKey +; CHECK: .word 0 +; CHECK: .size __import.sealing_type.static_sealing_test.TypeDefSealingKey, 8 +; CHECK: .section .compartment_imports.sealing_type.static_sealing_test.int,"awG",@progbits,__import.sealing_type.static_sealing_test.int,comdat +; CHECK: .type __import.sealing_type.static_sealing_test.int,@object +; CHECK: .globl __import.sealing_type.static_sealing_test.int +; CHECK: .p2align 3, 0x0 +; CHECK: __import.sealing_type.static_sealing_test.int: +; CHECK: .word __export.sealing_type.static_sealing_test.int +; CHECK: .word 0 +; CHECK: .size __import.sealing_type.static_sealing_test.int, 8 + + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{i32 1, !"target-abi", !"cheriot"} +!2 = !{i32 6, !"riscv-isa", !3} +!3 = !{!"rv32e2p0_m2p0_c2p0_zmmul1p0_xcheri0p0_xcheriot1p0"} +!4 = !{i32 8, !"SmallDataLimit", i32 0}