Skip to content

Commit 7575bda

Browse files
ojhunttru
authored andcommitted
[clang][Obj-C][PAC] Add support for authenticating block metadata (llvm#152978)
Introduces the use of pointer authentication to protect the invocation, copy and dispose, reference, and descriptor pointers in Objective-C block objects. Resolves llvm#141176
1 parent 6989071 commit 7575bda

File tree

9 files changed

+142
-34
lines changed

9 files changed

+142
-34
lines changed

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtr
157157
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
158158
FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
159159
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
160+
FEATURE(ptrauth_signed_block_descriptors, LangOpts.PointerAuthCalls)
160161
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
161162
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
162163
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)

clang/include/clang/Basic/PointerAuthOptions.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323

2424
namespace clang {
2525

26+
/// Constant discriminator to be used with block descriptor pointers. The value
27+
/// is ptrauth_string_discriminator("block_descriptor")
28+
constexpr uint16_t BlockDescriptorConstantDiscriminator = 0xC0BB;
29+
2630
/// Constant discriminator to be used with function pointers in .init_array and
2731
/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
2832
constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;
@@ -223,6 +227,18 @@ struct PointerAuthOptions {
223227
/// The ABI for function addresses in .init_array and .fini_array
224228
PointerAuthSchema InitFiniPointers;
225229

230+
/// The ABI for block invocation function pointers.
231+
PointerAuthSchema BlockInvocationFunctionPointers;
232+
233+
/// The ABI for block object copy/destroy function pointers.
234+
PointerAuthSchema BlockHelperFunctionPointers;
235+
236+
/// The ABI for __block variable copy/destroy function pointers.
237+
PointerAuthSchema BlockByrefHelperFunctionPointers;
238+
239+
/// The ABI for pointers to block descriptors.
240+
PointerAuthSchema BlockDescriptorPointers;
241+
226242
/// The ABI for Objective-C method lists.
227243
PointerAuthSchema ObjCMethodListFunctionPointers;
228244

clang/lib/CodeGen/Address.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ class Address {
176176
static Address invalid() { return Address(nullptr); }
177177
bool isValid() const { return Pointer.getPointer() != nullptr; }
178178

179+
llvm::Value *getPointerIfNotSigned() const {
180+
assert(isValid() && "pointer isn't valid");
181+
return !isSigned() ? Pointer.getPointer() : nullptr;
182+
}
183+
179184
/// This function is used in situations where the caller is doing some sort of
180185
/// opaque "laundering" of the pointer.
181186
void replaceBasePointer(llvm::Value *P) {

clang/lib/CodeGen/CGBlocks.cpp

Lines changed: 71 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,14 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
188188
// Optional copy/dispose helpers.
189189
bool hasInternalHelper = false;
190190
if (blockInfo.NeedsCopyDispose) {
191+
auto &Schema = CGM.getCodeGenOpts().PointerAuth.BlockHelperFunctionPointers;
191192
// copy_func_helper_decl
192193
llvm::Constant *copyHelper = buildCopyHelper(CGM, blockInfo);
193-
elements.add(copyHelper);
194+
elements.addSignedPointer(copyHelper, Schema, GlobalDecl(), QualType());
194195

195196
// destroy_func_decl
196197
llvm::Constant *disposeHelper = buildDisposeHelper(CGM, blockInfo);
197-
elements.add(disposeHelper);
198+
elements.addSignedPointer(disposeHelper, Schema, GlobalDecl(), QualType());
198199

199200
if (cast<llvm::Function>(copyHelper->stripPointerCasts())
200201
->hasInternalLinkage() ||
@@ -567,9 +568,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
567568
llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
568569
info.CanBeGlobal = true;
569570
return;
570-
}
571-
else if (C.getLangOpts().ObjC &&
572-
CGM.getLangOpts().getGC() == LangOptions::NonGC)
571+
} else if (C.getLangOpts().ObjC &&
572+
CGM.getLangOpts().getGC() == LangOptions::NonGC)
573573
info.HasCapturedVariableLayout = true;
574574

575575
if (block->doesNotEscape())
@@ -783,7 +783,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
783783

784784
llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
785785
bool IsOpenCL = CGM.getContext().getLangOpts().OpenCL;
786-
auto GenVoidPtrTy =
786+
llvm::PointerType *GenVoidPtrTy =
787787
IsOpenCL ? CGM.getOpenCLRuntime().getGenericVoidPointerType() : VoidPtrTy;
788788
LangAS GenVoidPtrAddr = IsOpenCL ? LangAS::opencl_generic : LangAS::Default;
789789
auto GenVoidPtrSize = CharUnits::fromQuantity(
@@ -817,9 +817,6 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
817817
: CGM.getNSConcreteStackBlock();
818818
isa = blockISA;
819819

820-
// Build the block descriptor.
821-
descriptor = buildBlockDescriptor(CGM, blockInfo);
822-
823820
// Compute the initial on-stack block flags.
824821
if (!CGM.getCodeGenOpts().DisableBlockSignatureString)
825822
flags = BLOCK_HAS_SIGNATURE;
@@ -833,6 +830,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
833830
flags |= BLOCK_USE_STRET;
834831
if (blockInfo.NoEscape)
835832
flags |= BLOCK_IS_NOESCAPE | BLOCK_IS_GLOBAL;
833+
834+
// Build the block descriptor.
835+
descriptor = buildBlockDescriptor(CGM, blockInfo);
836836
}
837837

838838
auto projectField = [&](unsigned index, const Twine &name) -> Address {
@@ -883,19 +883,34 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
883883
llvm::ConstantInt::get(IntTy, blockInfo.BlockAlign.getQuantity()),
884884
getIntSize(), "block.align");
885885
}
886-
addHeaderField(blockFn, GenVoidPtrSize, "block.invoke");
887-
if (!IsOpenCL)
888-
addHeaderField(descriptor, getPointerSize(), "block.descriptor");
889-
else if (auto *Helper =
890-
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
886+
887+
if (!IsOpenCL) {
888+
llvm::Value *blockFnPtr =
889+
llvm::ConstantExpr::getBitCast(InvokeFn, VoidPtrTy);
890+
QualType type = blockInfo.getBlockExpr()
891+
->getType()
892+
->castAs<BlockPointerType>()
893+
->getPointeeType();
894+
addSignedHeaderField(
895+
blockFnPtr,
896+
CGM.getCodeGenOpts().PointerAuth.BlockInvocationFunctionPointers,
897+
GlobalDecl(), type, getPointerSize(), "block.invoke");
898+
899+
addSignedHeaderField(
900+
descriptor, CGM.getCodeGenOpts().PointerAuth.BlockDescriptorPointers,
901+
GlobalDecl(), type, getPointerSize(), "block.descriptor");
902+
} else if (auto *Helper =
903+
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
904+
addHeaderField(blockFn, GenVoidPtrSize, "block.invoke");
891905
for (auto I : Helper->getCustomFieldValues(*this, blockInfo)) {
892906
addHeaderField(
893907
I.first,
894908
CharUnits::fromQuantity(
895909
CGM.getDataLayout().getTypeAllocSize(I.first->getType())),
896910
I.second);
897911
}
898-
}
912+
} else
913+
addHeaderField(blockFn, GenVoidPtrSize, "block.invoke");
899914
}
900915

901916
// Finally, capture all the values into the block.
@@ -1166,6 +1181,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
11661181
ASTContext &Ctx = getContext();
11671182
CallArgList Args;
11681183

1184+
llvm::Value *FuncPtr = nullptr;
1185+
11691186
if (getLangOpts().OpenCL) {
11701187
// For OpenCL, BlockPtr is already casted to generic block literal.
11711188

@@ -1185,7 +1202,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
11851202
if (!isa<ParmVarDecl>(E->getCalleeDecl()))
11861203
Func = CGM.getOpenCLRuntime().getInvokeFunction(E->getCallee());
11871204
else {
1188-
llvm::Value *FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 2);
1205+
FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 2);
11891206
Func = Builder.CreateAlignedLoad(GenericVoidPtrTy, FuncPtr,
11901207
getPointerAlign());
11911208
}
@@ -1194,7 +1211,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
11941211
BlockPtr =
11951212
Builder.CreatePointerCast(BlockPtr, UnqualPtrTy, "block.literal");
11961213
// Get pointer to the block invoke function
1197-
llvm::Value *FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 3);
1214+
FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 3);
11981215

11991216
// First argument is a block literal casted to a void pointer
12001217
BlockPtr = Builder.CreatePointerCast(BlockPtr, VoidPtrTy);
@@ -1211,7 +1228,15 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
12111228
CGM.getTypes().arrangeBlockFunctionCall(Args, FuncTy);
12121229

12131230
// Prepare the callee.
1214-
CGCallee Callee(CGCalleeInfo(), Func);
1231+
CGPointerAuthInfo PointerAuth;
1232+
if (auto &AuthSchema =
1233+
CGM.getCodeGenOpts().PointerAuth.BlockInvocationFunctionPointers) {
1234+
assert(FuncPtr != nullptr && "Missing function pointer for AuthInfo");
1235+
PointerAuth =
1236+
EmitPointerAuthInfo(AuthSchema, FuncPtr, GlobalDecl(), FnType);
1237+
}
1238+
1239+
CGCallee Callee(CGCalleeInfo(), Func, PointerAuth);
12151240

12161241
// And call the block.
12171242
return EmitCall(FnInfo, Callee, ReturnValue, Args, CallOrInvoke);
@@ -1295,14 +1320,15 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
12951320

12961321
bool IsOpenCL = CGM.getLangOpts().OpenCL;
12971322
bool IsWindows = CGM.getTarget().getTriple().isOSWindows();
1323+
auto &CGOPointerAuth = CGM.getCodeGenOpts().PointerAuth;
12981324
if (!IsOpenCL) {
12991325
// isa
13001326
if (IsWindows)
13011327
fields.addNullPointer(CGM.Int8PtrPtrTy);
13021328
else
13031329
fields.addSignedPointer(CGM.getNSConcreteGlobalBlock(),
1304-
CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
1305-
GlobalDecl(), QualType());
1330+
CGOPointerAuth.ObjCIsaPointers, GlobalDecl(),
1331+
QualType());
13061332

13071333
// __flags
13081334
BlockFlags flags = BLOCK_IS_GLOBAL;
@@ -1321,11 +1347,20 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
13211347
}
13221348

13231349
// Function
1324-
fields.add(blockFn);
1350+
if (auto &Schema = CGOPointerAuth.BlockInvocationFunctionPointers) {
1351+
QualType FnType = blockInfo.getBlockExpr()
1352+
->getType()
1353+
->castAs<BlockPointerType>()
1354+
->getPointeeType();
1355+
fields.addSignedPointer(blockFn, Schema, GlobalDecl(), FnType);
1356+
} else
1357+
fields.add(blockFn);
13251358

13261359
if (!IsOpenCL) {
13271360
// Descriptor
1328-
fields.add(buildBlockDescriptor(CGM, blockInfo));
1361+
llvm::Constant *Descriptor = buildBlockDescriptor(CGM, blockInfo);
1362+
fields.addSignedPointer(Descriptor, CGOPointerAuth.BlockDescriptorPointers,
1363+
GlobalDecl(), QualType());
13291364
} else if (auto *Helper =
13301365
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
13311366
for (auto *I : Helper->getCustomFieldValues(CGM, blockInfo)) {
@@ -1995,8 +2030,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
19952030
// it. It's not quite worth the annoyance to avoid creating it in the
19962031
// first place.
19972032
if (!needsEHCleanup(captureType.isDestructedType()))
1998-
if (auto *I =
1999-
cast_or_null<llvm::Instruction>(dstField.getBasePointer()))
2033+
if (auto *I = cast_or_null<llvm::Instruction>(
2034+
dstField.getPointerIfNotSigned()))
20002035
I->eraseFromParent();
20012036
}
20022037
break;
@@ -2730,8 +2765,16 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
27302765
unsigned nextHeaderIndex = 0;
27312766
CharUnits nextHeaderOffset;
27322767
auto storeHeaderField = [&](llvm::Value *value, CharUnits fieldSize,
2733-
const Twine &name) {
2768+
const Twine &name, bool isFunction = false) {
27342769
auto fieldAddr = Builder.CreateStructGEP(addr, nextHeaderIndex, name);
2770+
if (isFunction) {
2771+
if (auto &Schema = CGM.getCodeGenOpts()
2772+
.PointerAuth.BlockByrefHelperFunctionPointers) {
2773+
auto PointerAuth = EmitPointerAuthInfo(
2774+
Schema, fieldAddr.emitRawPointer(*this), GlobalDecl(), QualType());
2775+
value = EmitPointerAuthSign(PointerAuth, value);
2776+
}
2777+
}
27352778
Builder.CreateStore(value, fieldAddr);
27362779

27372780
nextHeaderIndex++;
@@ -2814,10 +2857,10 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
28142857
storeHeaderField(V, getIntSize(), "byref.size");
28152858

28162859
if (helpers) {
2817-
storeHeaderField(helpers->CopyHelper, getPointerSize(),
2818-
"byref.copyHelper");
2860+
storeHeaderField(helpers->CopyHelper, getPointerSize(), "byref.copyHelper",
2861+
/*isFunction=*/true);
28192862
storeHeaderField(helpers->DisposeHelper, getPointerSize(),
2820-
"byref.disposeHelper");
2863+
"byref.disposeHelper", /*isFunction=*/true);
28212864
}
28222865

28232866
if (ByRefHasLifetime && HasByrefExtendedLayout) {

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1752,7 +1752,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
17521752
options::OPT_fno_ptrauth_objc_interface_sel);
17531753
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_class_ro,
17541754
options::OPT_fno_ptrauth_objc_class_ro);
1755-
17561755
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
17571756
handlePAuthABI(Args, CmdArgs);
17581757

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,16 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
15421542
Discrimination::Constant, InitFiniPointerConstantDiscriminator);
15431543
}
15441544

1545+
Opts.BlockInvocationFunctionPointers =
1546+
PointerAuthSchema(Key::ASIA, true, Discrimination::None);
1547+
Opts.BlockHelperFunctionPointers =
1548+
PointerAuthSchema(Key::ASIA, true, Discrimination::None);
1549+
Opts.BlockByrefHelperFunctionPointers =
1550+
PointerAuthSchema(Key::ASIA, true, Discrimination::None);
1551+
Opts.BlockDescriptorPointers =
1552+
PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
1553+
BlockDescriptorConstantDiscriminator);
1554+
15451555
Opts.ObjCMethodListFunctionPointers =
15461556
PointerAuthSchema(Key::ASIA, true, Discrimination::None);
15471557
Opts.ObjCMethodListPointer =
@@ -3621,7 +3631,6 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
36213631
Opts.PointerAuthELFGOT = Args.hasArg(OPT_fptrauth_elf_got);
36223632
Opts.AArch64JumpTableHardening =
36233633
Args.hasArg(OPT_faarch64_jump_table_hardening);
3624-
36253634
Opts.PointerAuthObjcIsa = Args.hasArg(OPT_fptrauth_objc_isa);
36263635
Opts.PointerAuthObjcClassROPointers = Args.hasArg(OPT_fptrauth_objc_class_ro);
36273636
Opts.PointerAuthObjcInterfaceSel =

clang/test/CodeGen/ptrauth-qualifier-blocks.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,15 @@ void test_block_address_byref_capture() {
8282
// CHECK: store i32 33554432,
8383
// CHECK: store i32 48,
8484
// CHECK: [[COPY_HELPER_FIELD:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 4
85-
// CHECK: store ptr @__Block_byref_object_copy_, ptr [[COPY_HELPER_FIELD]], align
85+
// CHECK: [[T0:%.*]] = ptrtoint ptr [[COPY_HELPER_FIELD]] to i64
86+
// CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @__Block_byref_object_copy_ to i64), i32 0, i64 [[T0]])
87+
// CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr
88+
// CHECK: store ptr [[T2]], ptr [[COPY_HELPER_FIELD]], align
8689
// CHECK: [[DISPOSE_HELPER_FIELD:%.*]] = getelementptr inbounds nuw [[BYREF_T]], ptr [[BYREF]], i32 0, i32 5
87-
// CHECK: store ptr @__Block_byref_object_dispose_, ptr [[DISPOSE_HELPER_FIELD]], align
90+
// CHECK: [[T0:%.*]] = ptrtoint ptr [[DISPOSE_HELPER_FIELD]] to i64
91+
// CHECK: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @__Block_byref_object_dispose_ to i64), i32 0, i64 [[T0]])
92+
// CHECK: [[T2:%.*]] = inttoptr i64 [[T1]] to ptr
93+
// CHECK: store ptr [[T2]], ptr [[DISPOSE_HELPER_FIELD]], align
8894
// flags - copy/dispose required
8995
// CHECK: store i32 1107296256, ptr
9096
__block struct A * __ptrauth(1, 1, 60) ptr = createA();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clang_cc1 -fobjc-arc -fblocks -fptrauth-calls -triple arm64e-apple-ios -emit-llvm -o - %s | FileCheck %s
2+
3+
_Static_assert(__has_feature(ptrauth_signed_block_descriptors), "-fptrauth-block-descriptor-pointers should set ptrauth_signed_block_descriptors");
4+
5+
void a() {
6+
// Test out a global block.
7+
void (^blk)(void) = ^{};
8+
}
9+
10+
// CHECK: [[BLOCK_DESCRIPTOR_NAME:@"__block_descriptor_.*"]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr } { i64 0, i64 32, ptr @.str, ptr null }
11+
12+
13+
// CHECK: @__block_literal_global = internal constant { ptr, i32, i32, ptr, ptr } { ptr @_NSConcreteGlobalBlock, i32 1342177280, i32 0, ptr ptrauth (ptr @__a_block_invoke, i32 0, i64 0, ptr getelementptr inbounds ({ ptr, i32, i32, ptr, ptr }, ptr @__block_literal_global, i32 0, i32 3)), ptr ptrauth (ptr @"__block_descriptor_32_e5_v8\01?0l", i32 2, i64 49339, ptr getelementptr inbounds ({ ptr, i32, i32, ptr, ptr }, ptr @__block_literal_global, i32 0, i32 4)) }
14+
15+
void b(int p) {
16+
// CHECK-LABEL: define void @b
17+
18+
// Test out a stack block.
19+
void (^blk)(void) = ^{(void)p;};
20+
21+
// CHECK: [[BLOCK:%.*]] = alloca <{ ptr, i32, i32, ptr, ptr, i32 }>
22+
// CHECK: [[BLOCK_DESCRIPTOR_REF:%.*]] = getelementptr inbounds nuw <{ {{.*}} }>, ptr [[BLOCK]], i32 0, i32 4
23+
// CHECK: [[BLOCK_DESCRIPTOR_REF_INT:%.*]] = ptrtoint ptr [[BLOCK_DESCRIPTOR_REF]] to i64
24+
// CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[BLOCK_DESCRIPTOR_REF_INT]], i64 49339)
25+
// CHECK: [[SIGNED_REF:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @"__block_descriptor_36_e5_v8\01?0l" to i64), i32 2, i64 [[BLENDED]])
26+
// CHECK: [[SIGNED_REF_PTR:%.*]] = inttoptr i64 [[SIGNED_REF]] to ptr
27+
// CHECK: store ptr [[SIGNED_REF_PTR]], ptr [[BLOCK_DESCRIPTOR_REF]]
28+
}

clang/test/CodeGenObjC/ptrauth-block-isa.m

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
// RUN: %clang_cc1 -fptrauth-calls -fptrauth-objc-isa -fobjc-arc -fblocks -triple arm64e -emit-llvm %s -o - | FileCheck %s
1+
// RUN: %clang_cc1 -fptrauth-calls -fptrauth-objc-isa -fobjc-arc -fblocks -triple arm64e -emit-llvm %s -o - | FileCheck %s
22

33
void (^globalblock)(void) = ^{};
4-
// CHECK: [[GLOBAL_BLOCK:@.*]] = internal constant { ptr, i32, i32, ptr, ptr } { ptr ptrauth (ptr @_NSConcreteGlobalBlock, i32 2, i64 27361, ptr [[GLOBAL_BLOCK]]), i32 1342177280, i32 0, ptr @globalblock_block_invoke, ptr @"__block_descriptor_32_e5_v8\01?0l" }, align 8 #0
4+
// CHECK: [[BLOCK_DESCRIPTOR_NAME:@"__block_descriptor_.*"]] = linkonce_odr hidden unnamed_addr constant { i64, i64, ptr, ptr } { i64 0, i64 32, ptr @.str, ptr null }, comdat, align 8
5+
// CHECK: @__block_literal_global = internal constant { ptr, i32, i32, ptr, ptr } { ptr ptrauth (ptr @_NSConcreteGlobalBlock, i32 2, i64 27361, ptr @__block_literal_global), i32 1342177280, i32 0, ptr ptrauth (ptr @globalblock_block_invoke, i32 0, i64 0, ptr getelementptr inbounds ({ ptr, i32, i32, ptr, ptr }, ptr @__block_literal_global, i32 0, i32 3)), ptr ptrauth (ptr [[BLOCK_DESCRIPTOR_NAME]], i32 2, i64 49339, ptr getelementptr inbounds ({ ptr, i32, i32, ptr, ptr }, ptr @__block_literal_global, i32 0, i32 4)) }
56

67
@interface A
78
- (int) count;

0 commit comments

Comments
 (0)