[clang] [llvm] [MC,clang] Fix -Wa,--noexecstack not emitting .note.GNU-stack (PR #187880)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Mar 21 12:26:59 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/187880
>From 679ac726c8deb258ff87b182101671f4b37eebf7 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 21 Mar 2026 12:05:18 -0700
Subject: [PATCH 1/2] [MC,clang] Fix -Wa,--noexecstack not emitting
.note.GNU-stack
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.
`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 | 17 +++++++++++++++++
clang/tools/driver/cc1as_main.cpp | 1 +
llvm/lib/MC/MCELFStreamer.cpp | 12 ++++++++----
llvm/test/MC/ELF/noexec.s | 17 -----------------
llvm/test/MC/ELF/noexecstack.s | 5 +++++
llvm/tools/llvm-mc/llvm-mc.cpp | 8 ++------
6 files changed, 33 insertions(+), 27 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..ced0f6bd4611c
--- /dev/null
+++ b/clang/test/Misc/noexecstack.c
@@ -0,0 +1,17 @@
+// 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
+
+// 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
+
+// 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 c6cdd46a41f37..d6911e46b57e1 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -473,6 +473,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..d9b934dddc326 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,12 @@ void MCELFStreamer::finalizeCGProfile() {
}
void MCELFStreamer::finishImpl() {
+ // Emit .note.GNU-stack, similar to AsmPrinter::doFinalization.
+ if (const MCTargetOptions *TO = getContext().getTargetOptions())
+ if (TO->MCNoExecStack)
+ switchSection(getContext().getAsmInfo()->getStackSection(getContext(),
+ /*Exec=*/false));
+
// 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..43dc9b8d62c73
--- /dev/null
+++ b/llvm/test/MC/ELF/noexecstack.s
@@ -0,0 +1,5 @@
+# RUN: llvm-mc -filetype=obj -triple x86_64 %s -no-exec-stack -o - | llvm-readelf -S - | FileCheck %s
+
+# 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
+nop
diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp
index be5d524886978..3763ce0ea974c 100644
--- a/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -410,6 +410,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;
@@ -631,10 +632,8 @@ int main(int argc, char **argv) {
std::move(CE), std::move(MAB)));
Triple T(TripleName);
- if (T.isLFI()) {
- Str->initSections(NoExecStack, *STI);
+ if (T.isLFI())
initializeLFIMCStreamer(*Str.get(), Ctx, T);
- }
} else if (FileType == OFT_Null) {
Str.reset(TheTarget->createNullStreamer(Ctx));
} else {
@@ -652,9 +651,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());
}
>From 8a4cfb5f3b402a35cb86ad0985d3fb62cda4b77a Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 21 Mar 2026 12:26:48 -0700
Subject: [PATCH 2/2] test
---
clang/test/Misc/noexecstack.c | 5 +++++
llvm/test/MC/ELF/noexecstack.s | 5 ++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/clang/test/Misc/noexecstack.c b/clang/test/Misc/noexecstack.c
index ced0f6bd4611c..1af0c76d0207e 100644
--- a/clang/test/Misc/noexecstack.c
+++ b/clang/test/Misc/noexecstack.c
@@ -6,10 +6,15 @@
// 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"
diff --git a/llvm/test/MC/ELF/noexecstack.s b/llvm/test/MC/ELF/noexecstack.s
index 43dc9b8d62c73..ce3da8ffe8157 100644
--- a/llvm/test/MC/ELF/noexecstack.s
+++ b/llvm/test/MC/ELF/noexecstack.s
@@ -1,5 +1,8 @@
-# RUN: llvm-mc -filetype=obj -triple x86_64 %s -no-exec-stack -o - | llvm-readelf -S - | FileCheck %s
+# 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 --check-prefix=NOSTACK %s
# 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
More information about the llvm-commits
mailing list