Author: Fangrui Song
Date: 2026-03-22T16:58:31Z
New Revision: 34bc5d580b73c0ca79653bb03e5c50419be2c634

URL: 
https://github.com/llvm/llvm-project/commit/34bc5d580b73c0ca79653bb03e5c50419be2c634
DIFF: 
https://github.com/llvm/llvm-project/commit/34bc5d580b73c0ca79653bb03e5c50419be2c634.diff

LOG: [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

Added: 
    clang/test/Misc/noexecstack.c
    llvm/test/MC/ELF/noexecstack.s

Modified: 
    clang/tools/driver/cc1as_main.cpp
    llvm/lib/MC/MCELFStreamer.cpp
    llvm/tools/llvm-mc/llvm-mc.cpp

Removed: 
    llvm/test/MC/ELF/noexec.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","",@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..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 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());
   }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to