Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -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"];
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
45 changes: 45 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<DeclRefExpr>(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?
Expand Down
61 changes: 61 additions & 0 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<TYPENAME>()`.
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<FunctionDecl>(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
Expand Down
56 changes: 56 additions & 0 deletions clang/test/CodeGen/cheri/riscv/cheriot-emit-sealed-builtin.c
Original file line number Diff line number Diff line change
@@ -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<struct 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<enum 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: store ptr addrspace(200) @__import.sealing_type.static_sealing_test.int, ptr addrspace(200) %SealingKey8, align 8
int *SealingKey8 = __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" }
// CHECK: attributes #4 = { "cheri-compartment"="static_sealing_test" "cheriot_sealing_key"="sealing_type.static_sealing_test.int*" }
17 changes: 17 additions & 0 deletions llvm/include/llvm/IR/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading