diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 02865f8a29c67..ace73776bdbeb 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -8670,6 +8670,23 @@ denoting if the type contains a pointer. !0 = !{!"", i1 } +'``stack-protector``' Metadata +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``stack-protector`` metadata may be attached to alloca instructions. An +alloca instruction with this metadata will be skipped when deciding whether +a given function requires a stack protector. The function may still use +a stack protector, if other criteria determine it needs one. + +The metadata contains an integer, where a 0 value opts the given alloca out +of requiring a stack protector. + +.. code-block:: none + + %a = alloca [1000 x i8], align 1, !stack-protector !0 + + !0 = !{i32 0} + Module Flags Metadata ===================== diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp index 5fd5d6cce23df..9ddd61b0f20ef 100644 --- a/llvm/lib/CodeGen/StackProtector.cpp +++ b/llvm/lib/CodeGen/StackProtector.cpp @@ -431,6 +431,11 @@ bool SSPLayoutAnalysis::requiresStackProtector(Function *F, for (const BasicBlock &BB : *F) { for (const Instruction &I : BB) { if (const AllocaInst *AI = dyn_cast(&I)) { + if (const MDNode *MD = AI->getMetadata("stack-protector")) { + const auto *CI = mdconst::dyn_extract(MD->getOperand(0)); + if (CI->isZero()) + continue; + } if (AI->isArrayAllocation()) { auto RemarkBuilder = [&]() { return OptimizationRemark(DEBUG_TYPE, "StackProtectorAllocaOrArray", diff --git a/llvm/test/CodeGen/AArch64/stack-protector-metadata.ll b/llvm/test/CodeGen/AArch64/stack-protector-metadata.ll new file mode 100644 index 0000000000000..a0aa8859b1887 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/stack-protector-metadata.ll @@ -0,0 +1,58 @@ +; RUN: llc -mtriple=aarch64-apple-darwin < %s -o - | FileCheck %s + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" +target triple = "arm64-apple-darwin25.1.0" + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; CHECK-LABEL: test1: +; CHECK-NOT: ___stack_chk_guard + +; Function Attrs: noinline nounwind optnone +define void @test1(ptr noundef %msg) #0 { +entry: + %msg.addr = alloca ptr, align 8 + %a = alloca [1000 x i8], align 1, !stack-protector !2 + store ptr %msg, ptr %msg.addr, align 8 + %arraydecay = getelementptr inbounds [1000 x i8], ptr %a, i64 0, i64 0 + %0 = load ptr, ptr %msg.addr, align 8 + %call = call ptr @strcpy(ptr noundef %arraydecay, ptr noundef %0) #3 + %arraydecay1 = getelementptr inbounds [1000 x i8], ptr %a, i64 0, i64 0 + %call2 = call i32 (ptr, ...) @printf(ptr noundef @.str, ptr noundef %arraydecay1) + ret void +} + + +; CHECK-LABEL: test2: +; CHECK: ___stack_chk_guard + +; Function Attrs: noinline nounwind optnone +define void @test2(ptr noundef %msg) #0 { +entry: + %msg.addr = alloca ptr, align 8 + %b = alloca [1000 x i8], align 1 + store ptr %msg, ptr %msg.addr, align 8 + %arraydecay = getelementptr inbounds [1000 x i8], ptr %b, i64 0, i64 0 + %0 = load ptr, ptr %msg.addr, align 8 + %call = call ptr @strcpy(ptr noundef %arraydecay, ptr noundef %0) #3 + %arraydecay1 = getelementptr inbounds [1000 x i8], ptr %b, i64 0, i64 0 + %call2 = call i32 (ptr, ...) @printf(ptr noundef @.str, ptr noundef %arraydecay1) + ret void +} + +; Function Attrs: nounwind +declare ptr @strcpy(ptr noundef, ptr noundef) #1 + +declare i32 @printf(ptr noundef, ...) #2 + +attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" ssp } +attributes #1 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #3 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 22.0.0"} +!2 = !{i32 0}