Skip to content

Commit e77afe0

Browse files
committed
[CHERIoT] Launder sealed pointers when calling cheri.cap.address.get intrinsic
1 parent eb99bc0 commit e77afe0

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6026,10 +6026,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
60266026
return RValue::get(Builder.CreateIntToPtr(Ptr, ResultTy));
60276027
}
60286028

6029-
case Builtin::BI__builtin_cheri_address_get:
6030-
return RValue::get(
6031-
Builder.CreateIntrinsic(llvm::Intrinsic::cheri_cap_address_get,
6032-
{IntPtrTy}, {EmitScalarExpr(E->getArg(0))}));
6029+
case Builtin::BI__builtin_cheri_address_get: {
6030+
const auto *Arg = E->getArg(0);
6031+
auto *RArg = EmitScalarExpr(Arg);
6032+
if (Arg->getType()->isCHERISealedCapabilityType(getContext()))
6033+
RArg = Builder.CreateLaunderInvariantGroup(RArg);
6034+
return RValue::get(Builder.CreateIntrinsic(
6035+
llvm::Intrinsic::cheri_cap_address_get, {IntPtrTy}, {RArg}));
6036+
}
60336037
case Builtin::BI__builtin_cheri_address_set: {
60346038
Value *Cap = EmitScalarExpr(E->getArg(0));
60356039
Value *Address = EmitScalarExpr(E->getArg(1));

clang/test/CodeGen/cheri/riscv/cheriot-static-sealed-value-attr.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,32 @@ SealedInt Obj2 = 10;
2525
// CHECK: @llvm.compiler.used = appending addrspace(200) global [2 x ptr addrspace(200)] [ptr addrspace(200) @Obj1, ptr addrspace(200) @Obj2], section "llvm.metadata"
2626

2727
void doSomething(struct SealedStructObj *__sealed_capability obj);
28+
void doSomethingWithAddr(int addr);
2829
void doSomething2(SealedInt *__sealed_capability obj);
2930

3031
// CHECK: ; Function Attrs: minsize nounwind optsize
3132
// CHECK: define dso_local void @func() local_unnamed_addr addrspace(200) #1 {
3233
void func() {
3334
// CHECK: entry:
34-
// CHECK: tail call void @doSomething(ptr addrspace(200) noundef nonnull @Obj1) #3
35+
// CHECK: tail call void @doSomething(ptr addrspace(200) noundef nonnull @Obj1) #5
3536
doSomething(&Obj1);
3637

37-
// CHECK: tail call void @doSomething2(ptr addrspace(200) noundef nonnull @Obj2) #3
38+
// Verify that observing the address of a sealed global value is done through a call to the launder built-in, so that
39+
// the KnownBits optimisation pass can't assume anything about the value of the pointer, specifically nothing about the alignment of the pointer.
40+
// This is because the CHERIoT RTOS uses the lower bits of the address to store the permissions of the sealed capability, and KnownBits can in turn
41+
// optimise away logical computations on lower parts of the address.
42+
43+
// CHECK: %0 = tail call ptr addrspace(200) @llvm.launder.invariant.group.p200(ptr addrspace(200) nonnull @Obj1)
44+
// CHECK: %1 = tail call i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200) nonnull %0)
45+
// CHECK: tail call void @doSomethingWithAddr(i32 noundef %1) #5
46+
doSomethingWithAddr(__builtin_cheri_address_get(&Obj1));
47+
48+
// CHECK: tail call void @doSomething2(ptr addrspace(200) noundef nonnull @Obj2) #5
3849
doSomething2(&Obj2);
3950
}
4051

4152
// CHECK: declare void @doSomething(ptr addrspace(200) noundef) local_unnamed_addr addrspace(200) #2
53+
// CHECK: declare void @doSomethingWithAddr(i32 noundef) local_unnamed_addr addrspace(200) #2
54+
// CHECK: declare ptr addrspace(200) @llvm.launder.invariant.group.p200(ptr addrspace(200)) addrspace(200) #3
55+
// CHECK: declare i32 @llvm.cheri.cap.address.get.i32(ptr addrspace(200)) addrspace(200) #4
4256
// CHECK: declare void @doSomething2(ptr addrspace(200) noundef) local_unnamed_addr addrspace(200) #2

0 commit comments

Comments
 (0)