[llvm-branch-commits] [clang] [llvm] [MC, clang] Fix -Wa, --noexecstack not emitting .note.GNU-stack (PR #188541)
Jackson Schuster via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Mar 25 09:56:20 PDT 2026
https://github.com/jtschuster created https://github.com/llvm/llvm-project/pull/188541
Backport of #187880 to release/22.x
>From the original PR:
AsmPrinter (clang -c a.c) and AsmParser (clang -c a.s, llvm-mc -filetype=obj a.s) have different ways to emit .note.GNU-stack section.
913c5b4d1fff removed a redundant initSections call from cc1as, but that was the only place where NoExecStack was consumed for the assembler path.
Unify the .note.GNU-stack emission in MCELFStreamer::finishImpl, making the `initSections` parameter redundant.
Add a -filetype=obj test for Solaris (see
https://reviews.llvm.org/D159179), which doesn't use .note.GNU-stack
`initSections` has 20+ uses. The parameter cleanup will be deferred to a subsequent change.
Fixes https://github.com/llvm/llvm-project/issues/186004
>From 2a39b1ea7e837f108a397fe97bb6b158a9d94ff6 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 22 Mar 2026 09:58:31 -0700
Subject: [PATCH] [MC,clang] Fix -Wa,--noexecstack not emitting .note.GNU-stack
(#187880)
AsmPrinter (clang -c a.c) and AsmParser (clang -c a.s, llvm-mc
-filetype=obj a.s) have different ways to emit .note.GNU-stack section.
913c5b4d1fff removed a redundant initSections call from cc1as, but
that was the only place where NoExecStack was consumed for the
assembler path.
Unify the .note.GNU-stack emission in MCELFStreamer::finishImpl,
making the `initSections` parameter redundant.
Add a -filetype=obj test for Solaris (see
https://reviews.llvm.org/D159179), which doesn't use .note.GNU-stack
`initSections` has 20+ uses. The parameter cleanup will be deferred to a
subsequent change.
Fixes https://github.com/llvm/llvm-project/issues/186004
---
clang/test/Misc/noexecstack.c | 22 ++++++++++++++++++++++
clang/tools/driver/cc1as_main.cpp | 1 +
llvm/lib/MC/MCELFStreamer.cpp | 15 +++++++++++----
llvm/test/MC/ELF/noexec.s | 17 -----------------
llvm/test/MC/ELF/noexecstack.s | 11 +++++++++++
llvm/tools/llvm-mc/llvm-mc.cpp | 4 +---
6 files changed, 46 insertions(+), 24 deletions(-)
create mode 100644 clang/test/Misc/noexecstack.c
delete mode 100644 llvm/test/MC/ELF/noexec.s
create mode 100644 llvm/test/MC/ELF/noexecstack.s
diff --git a/clang/test/Misc/noexecstack.c b/clang/test/Misc/noexecstack.c
new file mode 100644
index 0000000000000..1af0c76d0207e
--- /dev/null
+++ b/clang/test/Misc/noexecstack.c
@@ -0,0 +1,22 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang -cc1 -triple x86_64 %s -emit-obj -o %t.o -mnoexecstack
+// RUN: llvm-readelf -S %t.o | FileCheck %s
+
+// RUN: %clang -cc1 -triple x86_64 %s -S -o %t.s
+// RUN: FileCheck --check-prefix=ASM %s < %t.s
+// RUN: %clang -cc1as -triple x86_64 %t.s -filetype obj -mnoexecstack -o %t.o
+// RUN: llvm-readelf -S %t.o | FileCheck %s
+/// Without -mnoexecstack on a .s that lacks .note.GNU-stack, the section should be absent.
+// RUN: echo "nop" | %clang -cc1as -triple x86_64 - -filetype obj -o %t.o
+// RUN: llvm-readelf -S %t.o | FileCheck --check-prefix=NOSTACK %s
+
+// CHECK: .text PROGBITS 0000000000000000 {{[0-9a-f]+}} 000001 00 AX 0 0 16
+// CHECK: .note.GNU-stack PROGBITS 0000000000000000 {{[0-9a-f]+}} 000000 00 0 0 1
+
+// NOSTACK-NOT: .note.GNU-stack
+
+// ASM: .text
+// ASM: .section ".note.GNU-stack","", at progbits
+// ASM-NOT: ".note.GNU-stack"
+
+void f() {}
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index ccc48a77891d7..339693e70996e 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -464,6 +464,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
MCOptions.ImplicitMapSyms = Opts.ImplicitMapsyms;
MCOptions.X86RelaxRelocations = Opts.X86RelaxRelocations;
MCOptions.X86Sse2Avx = Opts.X86Sse2Avx;
+ MCOptions.MCNoExecStack = Opts.NoExecStack;
MCOptions.CompressDebugSections = Opts.CompressDebugSections;
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp
index ac5568f00df48..2adb8901d69df 100644
--- a/llvm/lib/MC/MCELFStreamer.cpp
+++ b/llvm/lib/MC/MCELFStreamer.cpp
@@ -29,6 +29,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"
@@ -48,14 +49,11 @@ ELFObjectWriter &MCELFStreamer::getWriter() {
return static_cast<ELFObjectWriter &>(getAssembler().getWriter());
}
-void MCELFStreamer::initSections(bool NoExecStack, const MCSubtargetInfo &STI) {
+void MCELFStreamer::initSections(bool, const MCSubtargetInfo &STI) {
MCContext &Ctx = getContext();
switchSection(Ctx.getObjectFileInfo()->getTextSection());
emitCodeAlignment(Align(Ctx.getObjectFileInfo()->getTextSectionAlignment()),
&STI);
-
- if (NoExecStack)
- switchSection(Ctx.getAsmInfo()->getStackSection(Ctx, /*Exec=*/false));
}
void MCELFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
@@ -359,6 +357,15 @@ void MCELFStreamer::finalizeCGProfile() {
}
void MCELFStreamer::finishImpl() {
+ // Emit .note.GNU-stack, similar to AsmPrinter::doFinalization.
+ MCContext &Ctx = getContext();
+ if (const MCTargetOptions *TO = Ctx.getTargetOptions()) {
+ auto *StackSec = Ctx.getAsmInfo()->getStackSection(Ctx,
+ /*Exec=*/false);
+ if (StackSec && TO->MCNoExecStack)
+ switchSection(StackSec);
+ }
+
// Emit the .gnu attributes section if any attributes have been added.
if (!GNUAttributes.empty()) {
MCSection *DummyAttributeSection = nullptr;
diff --git a/llvm/test/MC/ELF/noexec.s b/llvm/test/MC/ELF/noexec.s
deleted file mode 100644
index a9ae5b24b4291..0000000000000
--- a/llvm/test/MC/ELF/noexec.s
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: llvm-mc -no-exec-stack -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -S - | FileCheck %s
-
-// CHECK: Section {
-// CHECK: Index:
-// CHECK: Name: .note.GNU-stack
-// CHECK-NEXT: Type: SHT_PROGBITS
-// CHECK-NEXT: Flags [
-// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x0
-// CHECK-NEXT: Offset: 0x40
-// CHECK-NEXT: Size: 0
-// CHECK-NEXT: Link: 0
-// CHECK-NEXT: Info: 0
-// CHECK-NEXT: AddressAlignment: 1
-// CHECK-NEXT: EntrySize: 0
-// CHECK-NEXT: }
-nop
diff --git a/llvm/test/MC/ELF/noexecstack.s b/llvm/test/MC/ELF/noexecstack.s
new file mode 100644
index 0000000000000..08fecb7bec780
--- /dev/null
+++ b/llvm/test/MC/ELF/noexecstack.s
@@ -0,0 +1,11 @@
+# RUN: llvm-mc -filetype=obj -triple x86_64 %s -no-exec-stack | llvm-readelf -S - | FileCheck %s
+# RUN: llvm-mc -filetype=obj -triple x86_64 %s | llvm-readelf -S - | FileCheck %s --check-prefix=NOSTACK
+
+## Solaris doesn't use .note.GNU-stack at all.
+# RUN: llvm-mc -filetype=obj -triple x86_64-solaris %s | llvm-readelf -S - | FileCheck %s --check-prefix=NOSTACK
+
+# CHECK: .text PROGBITS 0000000000000000 {{[0-9a-f]+}} 000001 00 AX 0 0 4
+# CHECK: .note.GNU-stack PROGBITS 0000000000000000 {{[0-9a-f]+}} 000000 00 0 0 1
+
+# NOSTACK-NOT: .note.GNU-stack
+nop
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index baf3b5536138b..436d1d02efa5b 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -409,6 +409,7 @@ int main(int argc, char **argv) {
MCOptions.CompressDebugSections = CompressDebugSections.getValue();
MCOptions.ShowMCInst = ShowInst;
MCOptions.AsmVerbose = true;
+ MCOptions.MCNoExecStack = NoExecStack;
MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory;
MCOptions.InstPrinterOptions = InstPrinterOptions;
@@ -643,9 +644,6 @@ int main(int argc, char **argv) {
DwoOut ? MAB->createDwoObjectWriter(*OS, DwoOut->os())
: MAB->createObjectWriter(*OS),
std::unique_ptr<MCCodeEmitter>(CE), *STI));
- if (NoExecStack)
- Str->switchSection(
- Ctx.getAsmInfo()->getStackSection(Ctx, /*Exec=*/false));
Str->emitVersionForTarget(TheTriple, VersionTuple(), nullptr,
VersionTuple());
}
More information about the llvm-branch-commits
mailing list