From 830224216a9d14061d6cf8aab0be40563dbb9c6f Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Thu, 5 Jun 2025 10:19:00 +0200 Subject: [PATCH] [CHERIoT]: Add `cheriot_sealing_type` clang built-in --- clang/include/clang/Basic/Builtins.td | 6 + clang/include/clang/Basic/TokenKinds.def | 1 + clang/lib/CodeGen/CGBuiltin.cpp | 45 +++++ clang/lib/Parse/ParseExpr.cpp | 61 +++++++ .../cheri/riscv/cheriot-emit-sealed-builtin.c | 56 ++++++ llvm/include/llvm/IR/Attributes.h | 17 ++ llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp | 163 ++++++++++++------ .../Target/RISCV/RISCVExpandPseudoInsts.cpp | 30 +++- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 5 +- .../RISCV/cheri/cheriot-sealing-key-attr.ll | 49 ++++++ 10 files changed, 375 insertions(+), 58 deletions(-) create mode 100644 clang/test/CodeGen/cheri/riscv/cheriot-emit-sealed-builtin.c create mode 100644 llvm/test/CodeGen/RISCV/cheri/cheriot-sealing-key-attr.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 93a6efb9f4aa5..cc3c839758936 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4648,6 +4648,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, Constexpr]; + let Prototype = "void*(...)"; +} + // Safestack builtins. def GetUnsafeStackStart : Builtin { let Spellings = ["__builtin___get_unsafe_stack_start"]; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 7c8b18c66f898..16ada874d7010 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -356,6 +356,7 @@ KEYWORD(__cheri_input , KEYALL) // CHERIoT Predefine Expr KEYWORD(__cheriot_minimum_stack__ , KEYALL) +KEYWORD(__builtin_cheriot_sealing_type , KEYALL) // Cheriot Qualifiers KEYWORD(__sealed_capability , KEYALL) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index a9386264ba299..aabb945a45171 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6155,6 +6155,51 @@ 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 Expr *Callee = E->getCallee(); + Callee = Callee->IgnoreImplicit(); + + const auto *DeclRef = dyn_cast(Callee); + assert(DeclRef && "DeclRef to built-in callee can't be null!"); + assert(DeclRef->getTemplateArgs() && + "template type in built-in callee can't be null!"); + + const auto SealingType = + DeclRef->getTemplateArgs()->getArgument().getAsType(); + auto CompartmentName = getLangOpts().CheriCompartmentName; + + clang::PrintingPolicy policy(getLangOpts()); + policy.SuppressTagKeyword = true; + policy.SuppressElaboration = true; + policy.SuppressCapabilityQualifier = true; + + std::string SealingTypeName = SealingType.getAsString(policy); + SealingTypeName.erase( + std::remove_if(SealingTypeName.begin(), SealingTypeName.end(), isspace), + SealingTypeName.end()); + + auto PrefixedImportName = + CHERIoTSealingKeyTypeAttr::getSealingTypeSymbolName(CompartmentName, + SealingTypeName); + auto *Mod = &CGM.getModule(); + auto MangledImportName = "__import." + PrefixedImportName; + auto *GV = Mod->getGlobalVariable(MangledImportName); + + if (!GV) { + // llvm::StructType* opaqueType = + // llvm::StructType::create(CGM.getModule().getContext(), ""); + auto *opaquePtrType = + llvm::PointerType::getUnqual(CGM.getModule().getContext()); + GV = new GlobalVariable(CGM.getModule(), opaquePtrType, true, + GlobalValue::ExternalLinkage, nullptr, + MangledImportName); + GV->addAttribute(CHERIoTSealingKeyTypeAttr::getAttrName(), + PrefixedImportName); + GV->addAttribute("cheri-compartment", CompartmentName); + } + + 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/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 38ff626807ddc..edc41388e25c1 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1201,6 +1201,67 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, isVectorLiteral, NotPrimaryExpression); + case tok::kw___builtin_cheriot_sealing_type: { + // We expect: `__builtin_cheriot_sealing_type()`. + auto KWLoc = Tok.getLocation(); + ConsumeToken(); + auto LAngleLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::less)) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + auto TyArgLoc = Tok.getLocation(); + TypeResult TyArg = ParseTypeName(); + if (TyArg.isInvalid()) + return ExprError(); + + TypeSourceInfo *SealingTypeInfo = nullptr; + QualType SealingType = + Actions.GetTypeFromParser(TyArg.get(), &SealingTypeInfo); + + auto RAngleLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::greater)) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + if (ExpectAndConsume(tok::l_paren)) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + SourceLocation RParenLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::r_paren)) { + SkipUntil(tok::semi, StopAtSemi); + return ExprError(); + } + + auto *Ctxt = &Actions.getASTContext(); + auto BuiltinID = clang::Builtin::BI__builtin_cheriot_sealing_type; + + auto BuiltinName = Ctxt->BuiltinInfo.getName(BuiltinID); + IdentifierInfo *II = &Ctxt->Idents.get(BuiltinName); + LookupResult R(Actions, II, SourceLocation(), Sema::LookupOrdinaryName); + if (!Actions.LookupBuiltin(R)) { + return ExprError(); + } + + FunctionDecl *BuiltinDecl = dyn_cast(R.getFoundDecl()); + TemplateArgument Arg(SealingType); + TemplateArgumentListInfo TArgs(LAngleLoc, RAngleLoc); + + TArgs.addArgument(TemplateArgumentLoc( + Arg, Ctxt->getTrivialTypeSourceInfo(SealingType, TyArgLoc))); + + DeclRefExpr *FnRef = DeclRefExpr::Create( + *Ctxt, NestedNameSpecifierLoc(), SourceLocation(), BuiltinDecl, false, + KWLoc, BuiltinDecl->getType(), VK_LValue, R.getFoundDecl(), &TArgs); + + return CallExpr::Create(*Ctxt, FnRef, {}, BuiltinDecl->getReturnType(), + clang::ExprValueKind::VK_PRValue, RParenLoc, + FPOptionsOverride()); + } case tok::identifier: ParseIdentifier: { // primary-expression: identifier // unqualified-id: identifier diff --git a/clang/test/CodeGen/cheri/riscv/cheriot-emit-sealed-builtin.c b/clang/test/CodeGen/cheri/riscv/cheriot-emit-sealed-builtin.c new file mode 100644 index 0000000000000..0d7a14f2be6bd --- /dev/null +++ b/clang/test/CodeGen/cheri/riscv/cheriot-emit-sealed-builtin.c @@ -0,0 +1,56 @@ +// 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: @__import.sealing_type.static_sealing_test.StructSealingKey = external addrspace(200) constant ptr #0 +// CHECK: @__import.sealing_type.static_sealing_test.EnumSealingKey = external addrspace(200) constant ptr #1 +// CHECK: @__import.sealing_type.static_sealing_test.TypeDefSealingKey = external addrspace(200) constant ptr #2 +// CHECK: @__import.sealing_type.static_sealing_test.int = external addrspace(200) constant ptr #3 +// CHECK: @"__import.sealing_type.static_sealing_test.int*" = external addrspace(200) constant ptr #4 + +// CHECK: define dso_local void @func() addrspace(200) #5 { +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: %SealingKey8 = 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(); + +// 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(); + +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.TypeDefSealingKey, ptr addrspace(200) %SealingKey3, align 8 + TypeDefSealingKey *SealingKey3 = __builtin_cheriot_sealing_type(); + +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey4, align 8 + int *SealingKey4 = __builtin_cheriot_sealing_type(); + +// CHECK: store ptr addrspace(200) @"__import.sealing_type.static_sealing_test.int*", ptr addrspace(200) %SealingKey5, align 8 + int **SealingKey5 = __builtin_cheriot_sealing_type(); + +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey6, align 8 + int *SealingKey6 = __builtin_cheriot_sealing_type(); +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey7, align 8 + int *SealingKey7 = __builtin_cheriot_sealing_type(); +// CHECK: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey8, align 8 + int *SealingKey8 = __builtin_cheriot_sealing_type(); + +// 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" } +// CHECK: attributes #4 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.int*" } diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h index 84aca51bcd9f0..1f33e0202c7cb 100644 --- a/llvm/include/llvm/IR/Attributes.h +++ b/llvm/include/llvm/IR/Attributes.h @@ -1612,6 +1612,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..779a104807ca5 100644 --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -114,13 +114,9 @@ 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. - std::string CompartmentName; + struct FunctionCompartmentExport { /// The IR function corresponding to the function. const Function &Fn; /// The symbol for the function @@ -132,6 +128,24 @@ class RISCVAsmPrinter : public AsmPrinter { /// The size in bytes of the stack frame, 0 if not used. uint32_t stackSize = 0; }; + + /** + * Struct describing sealing key-like compartment export objects. + */ + struct SealingKeyCompartmentExport { + /// The name of the sealing key type. + std::string SealingKeyTypeName; + }; + + /** + * Struct describing compartment exports that must be emitted for this + * compilation unit. + */ + struct CompartmentExport { + /// The compartment name for the object. + std::string CompartmentName; + std::variant Object; + }; SmallVector CompartmentEntries; SmallDenseMap, 1> CompartmentEntryAliases; @@ -312,6 +326,16 @@ void RISCVAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { return; } + auto CheriotSealingKeyTypeAttrName = + llvm::CHERIoTSealingKeyTypeAttr::getAttrName(); + + if (GV->hasAttribute(CheriotSealingKeyTypeAttrName)) { + auto Attr = GV->getAttribute(CheriotSealingKeyTypeAttrName); + CompartmentEntries.push_back( + {std::string(GV->getAttribute("cheri-compartment").getValueAsString()), + SealingKeyCompartmentExport{Attr.getValueAsString().str()}}); + } + // Continue through the normal path to emit the global. return AsmPrinter::emitGlobalVariable(GV); } @@ -582,20 +606,24 @@ bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) { } else stackSize = MF.getFrameInfo().getStackSize(); // FIXME: Get stack size as function attribute if specified - CompartmentEntries.push_back( - {std::string(Fn.getFnAttribute("cheri-compartment").getValueAsString()), - Fn, OutStreamer->getContext().getOrCreateSymbol(MF.getName()), - countUsedArgRegisters(MF) + interruptFlag, false, stackSize}); + CompartmentEntries.push_back(CompartmentExport{ + std::string(Fn.getFnAttribute("cheri-compartment").getValueAsString()), + FunctionCompartmentExport{ + Fn, OutStreamer->getContext().getOrCreateSymbol(MF.getName()), + countUsedArgRegisters(MF) + interruptFlag, false, stackSize}, + }); } else if (Fn.getCallingConv() == CallingConv::CHERI_LibCall) CompartmentEntries.push_back( - {"libcalls", Fn, - OutStreamer->getContext().getOrCreateSymbol(MF.getName()), - countUsedArgRegisters(MF) + interruptFlag}); + {"libcalls", + FunctionCompartmentExport{ + Fn, OutStreamer->getContext().getOrCreateSymbol(MF.getName()), + countUsedArgRegisters(MF) + interruptFlag}}); else if (interruptFlag != 0) CompartmentEntries.push_back( {std::string(Fn.getFnAttribute("cheri-compartment").getValueAsString()), - Fn, OutStreamer->getContext().getOrCreateSymbol(MF.getName()), - countUsedArgRegisters(MF) + interruptFlag, true}); + FunctionCompartmentExport{ + Fn, OutStreamer->getContext().getOrCreateSymbol(MF.getName()), + countUsedArgRegisters(MF) + interruptFlag, true}}); if (EmittedOptionArch) RTS.emitDirectiveOptionPop(); @@ -700,50 +728,73 @@ void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) { if (!CompartmentEntries.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) { - 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 (Entry.Fn.hasExternalLinkage() && !Entry.forceLocal) - OutStreamer->emitSymbolAttribute(Sym, MCSA_Global); - OutStreamer->emitValueToAlignment(Align(4)); - OutStreamer->emitLabel(Sym); - emitLabelDifference(Entry.FnSym, CompartmentStartSym, 2); - auto stackSize = Entry.stackSize; - // Round up to multiple of 8 and divide by 8. - stackSize = (stackSize + 7) / 8; - // TODO: We should probably warn if the std::min truncates here. - OutStreamer->emitIntValue(std::min(uint32_t(255), stackSize), 1); - OutStreamer->emitIntValue(Entry.LiveIns, 1); - OutStreamer->emitELFSize(Sym, MCConstantExpr::create(4, C)); - - // Emit aliases for this export symbol entry. - auto I = CompartmentEntryAliases.find(&Entry.Fn); - if (I == CompartmentEntryAliases.end()) - continue; - for (const GlobalAlias *GA : I->second) { - std::string AliasExportName = getImportExportTableName( - Entry.CompartmentName, GA->getName(), Entry.Fn.getCallingConv(), + if (std::holds_alternative(Entry.Object)) { + auto *Exports = + C.getELFSection(".compartment_exports", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_GNU_RETAIN); + OutStreamer->switchSection(Exports); + auto Fn = std::get(Entry.Object); + std::string ExportName = getImportExportTableName( + Entry.CompartmentName, Fn.Fn.getName(), Fn.Fn.getCallingConv(), /*IsImport*/ false); - auto AliasExportSym = C.getOrCreateSymbol(AliasExportName); - - // Emit symbol alias in the export table for the alias using the same - // attributes, linkage, and size as the primary entry. - OutStreamer->emitSymbolAttribute(AliasExportSym, MCSA_ELF_TypeObject); - if (GA->hasExternalLinkage() && !Entry.forceLocal) - OutStreamer->emitSymbolAttribute(AliasExportSym, MCSA_Global); - OutStreamer->emitAssignment(AliasExportSym, - MCSymbolRefExpr::create(Sym, C)); - OutStreamer->emitELFSize(AliasExportSym, MCConstantExpr::create(4, C)); + 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 (Fn.Fn.hasExternalLinkage() && !Fn.forceLocal) + OutStreamer->emitSymbolAttribute(Sym, MCSA_Global); + OutStreamer->emitValueToAlignment(Align(4)); + OutStreamer->emitLabel(Sym); + emitLabelDifference(Fn.FnSym, CompartmentStartSym, 2); + auto stackSize = Fn.stackSize; + // Round up to multiple of 8 and divide by 8. + stackSize = (stackSize + 7) / 8; + // TODO: We should probably warn if the std::min truncates here. + OutStreamer->emitIntValue(std::min(uint32_t(255), stackSize), 1); + OutStreamer->emitIntValue(Fn.LiveIns, 1); + OutStreamer->emitELFSize(Sym, MCConstantExpr::create(4, C)); + + // Emit aliases for this export symbol entry. + auto I = CompartmentEntryAliases.find(&Fn.Fn); + if (I == CompartmentEntryAliases.end()) + continue; + for (const GlobalAlias *GA : I->second) { + std::string AliasExportName = getImportExportTableName( + Entry.CompartmentName, GA->getName(), Fn.Fn.getCallingConv(), + /*IsImport*/ false); + auto AliasExportSym = C.getOrCreateSymbol(AliasExportName); + + // Emit symbol alias in the export table for the alias using the same + // attributes, linkage, and size as the primary entry. + OutStreamer->emitSymbolAttribute(AliasExportSym, MCSA_ELF_TypeObject); + if (GA->hasExternalLinkage() && !Fn.forceLocal) + OutStreamer->emitSymbolAttribute(AliasExportSym, MCSA_Global); + OutStreamer->emitAssignment(AliasExportSym, + MCSymbolRefExpr::create(Sym, C)); + OutStreamer->emitELFSize(AliasExportSym, + MCConstantExpr::create(4, C)); + } + } else { + auto SealingKey = std::get(Entry.Object); + auto ExportName = SealingKey.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)); } } } diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp index 76c3e1fded99e..927506c5a89ab 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); @@ -712,7 +739,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 f3fc67b3dd72c..e448f151a4588 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -8242,8 +8242,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..ed381819acf12 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/cheri/cheriot-sealing-key-attr.ll @@ -0,0 +1,49 @@ +; 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" + +@__import.sealing_type.static_sealing_test.SealingType= external addrspace(200) constant ptr #0 + +; Function Attrs: noinline nounwind optnone +define dso_local void @func() #1 { +entry: + + %SealingKey = 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.SealingType) +; CHECK: clc ca0, %cheriot_compartment_lo_i(.LBB0_1) + store ptr addrspace(200) @__import.sealing_type.static_sealing_test.SealingType, ptr addrspace(200) %SealingKey, align 8 + ret void +} + +attributes #0 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.SealingType" } +attributes #1 = { noinline nounwind optnone "cheri-compartment"="static_sealing_test" "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit,+a,+c,+d,+f,+m,+relax,+zaamo,+zalrsc,+zicsr,+zmmul,-b,-e,-experimental-sdext,-experimental-sdtrig,-experimental-smctr,-experimental-ssctr,-experimental-svukte,-experimental-xqcia,-experimental-xqciac,-experimental-xqcicli,-experimental-xqcicm,-experimental-xqcics,-experimental-xqcicsr,-experimental-xqciint,-experimental-xqcilo,-experimental-xqcilsm,-experimental-xqcisls,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-experimental-zvbc32e,-experimental-zvkgs,-h,-sha,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smdbltrp,-smepmp,-smmpm,-smnpm,-smrnmi,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssdbltrp,-ssnpm,-sspm,-ssqosid,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-supm,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-svvptc,-v,-xcheri,-xcheriot,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xmipscmove,-xmipslsp,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zabha,-zacas,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zifencei,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } + + + +; CHECK: .section .compartment_exports.sealing_type.static_sealing_test.SealingType,"awG",@progbits,sealing_type.static_sealing_test.SealingType,comdat +; CHECK: .type __export.sealing_type.static_sealing_test.SealingType,@object +; CHECK: .globl __export.sealing_type.static_sealing_test.SealingType +; CHECK: .p2align 2, 0x0 +; CHECK:__export.sealing_type.static_sealing_test.SealingType: +; CHECK: .half 0 +; CHECK: .byte 0 +; CHECK: .byte 32 +; CHECK: .size __export.sealing_type.static_sealing_test.SealingType, 4 +; CHECK: .section .compartment_imports.sealing_type.static_sealing_test.SealingType,"awG",@progbits,__import.sealing_type.static_sealing_test.SealingType,comdat +; CHECK: .type __import.sealing_type.static_sealing_test.SealingType,@object +; CHECK: .globl __import.sealing_type.static_sealing_test.SealingType +; CHECK: .p2align 3, 0x0 +; CHECK:__import.sealing_type.static_sealing_test.SealingType: +; CHECK: .word __export.sealing_type.static_sealing_test.SealingType +; CHECK: .word 0 + + + +!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}