Skip to content

Commit d8850ee

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

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
@@ -155,6 +155,7 @@ FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtr
155155
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
156156
FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
157157
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
158+
FEATURE(ptrauth_signed_block_descriptors, LangOpts.PointerAuthCalls)
158159
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
159160
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
160161
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() ||
@@ -568,9 +569,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
568569
llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true);
569570
info.CanBeGlobal = true;
570571
return;
571-
}
572-
else if (C.getLangOpts().ObjC &&
573-
CGM.getLangOpts().getGC() == LangOptions::NonGC)
572+
} else if (C.getLangOpts().ObjC &&
573+
CGM.getLangOpts().getGC() == LangOptions::NonGC)
574574
info.HasCapturedVariableLayout = true;
575575

576576
if (block->doesNotEscape())
@@ -784,7 +784,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
784784

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

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

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

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

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

@@ -1186,7 +1203,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
11861203
if (!isa<ParmVarDecl>(E->getCalleeDecl()))
11871204
Func = CGM.getOpenCLRuntime().getInvokeFunction(E->getCallee());
11881205
else {
1189-
llvm::Value *FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 2);
1206+
FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 2);
11901207
Func = Builder.CreateAlignedLoad(GenericVoidPtrTy, FuncPtr,
11911208
getPointerAlign());
11921209
}
@@ -1195,7 +1212,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
11951212
BlockPtr =
11961213
Builder.CreatePointerCast(BlockPtr, UnqualPtrTy, "block.literal");
11971214
// Get pointer to the block invoke function
1198-
llvm::Value *FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 3);
1215+
FuncPtr = Builder.CreateStructGEP(GenBlockTy, BlockPtr, 3);
11991216

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

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

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

12971322
bool IsOpenCL = CGM.getLangOpts().OpenCL;
12981323
bool IsWindows = CGM.getTarget().getTriple().isOSWindows();
1324+
auto &CGOPointerAuth = CGM.getCodeGenOpts().PointerAuth;
12991325
if (!IsOpenCL) {
13001326
// isa
13011327
if (IsWindows)
13021328
fields.addNullPointer(CGM.Int8PtrPtrTy);
13031329
else
13041330
fields.addSignedPointer(CGM.getNSConcreteGlobalBlock(),
1305-
CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
1306-
GlobalDecl(), QualType());
1331+
CGOPointerAuth.ObjCIsaPointers, GlobalDecl(),
1332+
QualType());
13071333

13081334
// __flags
13091335
BlockFlags flags = BLOCK_IS_GLOBAL;
@@ -1322,11 +1348,20 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
13221348
}
13231349

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

13271360
if (!IsOpenCL) {
13281361
// Descriptor
1329-
fields.add(buildBlockDescriptor(CGM, blockInfo));
1362+
llvm::Constant *Descriptor = buildBlockDescriptor(CGM, blockInfo);
1363+
fields.addSignedPointer(Descriptor, CGOPointerAuth.BlockDescriptorPointers,
1364+
GlobalDecl(), QualType());
13301365
} else if (auto *Helper =
13311366
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
13321367
for (auto *I : Helper->getCustomFieldValues(CGM, blockInfo)) {
@@ -1996,8 +2031,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
19962031
// it. It's not quite worth the annoyance to avoid creating it in the
19972032
// first place.
19982033
if (!needsEHCleanup(captureType.isDestructedType()))
1999-
if (auto *I =
2000-
cast_or_null<llvm::Instruction>(dstField.getBasePointer()))
2034+
if (auto *I = cast_or_null<llvm::Instruction>(
2035+
dstField.getPointerIfNotSigned()))
20012036
I->eraseFromParent();
20022037
}
20032038
break;
@@ -2731,8 +2766,16 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
27312766
unsigned nextHeaderIndex = 0;
27322767
CharUnits nextHeaderOffset;
27332768
auto storeHeaderField = [&](llvm::Value *value, CharUnits fieldSize,
2734-
const Twine &name) {
2769+
const Twine &name, bool isFunction = false) {
27352770
auto fieldAddr = Builder.CreateStructGEP(addr, nextHeaderIndex, name);
2771+
if (isFunction) {
2772+
if (auto &Schema = CGM.getCodeGenOpts()
2773+
.PointerAuth.BlockByrefHelperFunctionPointers) {
2774+
auto PointerAuth = EmitPointerAuthInfo(
2775+
Schema, fieldAddr.emitRawPointer(*this), GlobalDecl(), QualType());
2776+
value = EmitPointerAuthSign(PointerAuth, value);
2777+
}
2778+
}
27362779
Builder.CreateStore(value, fieldAddr);
27372780

27382781
nextHeaderIndex++;
@@ -2815,10 +2858,10 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
28152858
storeHeaderField(V, getIntSize(), "byref.size");
28162859

28172860
if (helpers) {
2818-
storeHeaderField(helpers->CopyHelper, getPointerSize(),
2819-
"byref.copyHelper");
2861+
storeHeaderField(helpers->CopyHelper, getPointerSize(), "byref.copyHelper",
2862+
/*isFunction=*/true);
28202863
storeHeaderField(helpers->DisposeHelper, getPointerSize(),
2821-
"byref.disposeHelper");
2864+
"byref.disposeHelper", /*isFunction=*/true);
28222865
}
28232866

28242867
if (ByRefHasLifetime && HasByrefExtendedLayout) {

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1736,7 +1736,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
17361736
options::OPT_fno_ptrauth_objc_interface_sel);
17371737
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_objc_class_ro,
17381738
options::OPT_fno_ptrauth_objc_class_ro);
1739-
17401739
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
17411740
handlePAuthABI(Args, CmdArgs);
17421741

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)