Skip to content

Conversation

@ssijaric-nv
Copy link
Contributor

In the presence of trampolines, the .note.GNU-stack section is not emitted. The
absence of .note.GNU-stack results in the stack marked executable by some
linkers. But others require an explict .note.GNU-stack section.

The GNU ld 2.43 on x86 machines, for example, issues the following:

missing .note.GNU-stack section implies executable stack
NOTE: This behaviour is deprecated and will be removed in a future version of the linker

On one of the ARM machines, the absence of .note.GNU-stack results in the stack
marked as non-executable:

STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-

This change just emits the explicit .note.GNU-stack and marks it executable if required.

@ssijaric-nv ssijaric-nv marked this pull request as ready for review August 14, 2025 17:20
@ssijaric-nv ssijaric-nv requested a review from davemgreen August 14, 2025 17:20
@llvmbot
Copy link
Member

llvmbot commented Aug 14, 2025

@llvm/pr-subscribers-mc

@llvm/pr-subscribers-backend-aarch64

Author: None (ssijaric-nv)

Changes

In the presence of trampolines, the .note.GNU-stack section is not emitted. The
absence of .note.GNU-stack results in the stack marked executable by some
linkers. But others require an explict .note.GNU-stack section.

The GNU ld 2.43 on x86 machines, for example, issues the following:

missing .note.GNU-stack section implies executable stack
NOTE: This behaviour is deprecated and will be removed in a future version of the linker

On one of the ARM machines, the absence of .note.GNU-stack results in the stack
marked as non-executable:

STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-

This change just emits the explicit .note.GNU-stack and marks it executable if required.


Full diff: https://github.com/llvm/llvm-project/pull/151754.diff

6 Files Affected:

  • (modified) llvm/include/llvm/MC/MCAsmInfo.h (+6)
  • (modified) llvm/include/llvm/MC/MCAsmInfoELF.h (+1)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+6-2)
  • (modified) llvm/lib/MC/MCAsmInfoELF.cpp (+8)
  • (modified) llvm/test/CodeGen/AArch64/trampoline.ll (+1)
  • (modified) llvm/test/CodeGen/RISCV/rv64-trampoline.ll (+1)
diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h index 6c12cd347901a..1e87ce23b158b 100644 --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -471,6 +471,12 @@ class LLVM_ABI MCAsmInfo { return nullptr; } + /// Targets can implement this method to specify a section to switch to if the + /// translation has trampolines that require an executable stack. + virtual MCSection *getExecutableStackSection(MCContext &Ctx) const { + return nullptr; + } + virtual const MCExpr *getExprForPersonalitySymbol(const MCSymbol *Sym, unsigned Encoding, MCStreamer &Streamer) const; diff --git a/llvm/include/llvm/MC/MCAsmInfoELF.h b/llvm/include/llvm/MC/MCAsmInfoELF.h index c05e4ad78ecd1..c5dff900227fd 100644 --- a/llvm/include/llvm/MC/MCAsmInfoELF.h +++ b/llvm/include/llvm/MC/MCAsmInfoELF.h @@ -16,6 +16,7 @@ namespace llvm { class MCAsmInfoELF : public MCAsmInfo { virtual void anchor(); MCSection *getNonexecutableStackSection(MCContext &Ctx) const final; + MCSection *getExecutableStackSection(MCContext &Ctx) const final; void printSwitchToSection(const MCSection &, uint32_t, const Triple &, raw_ostream &) const final; bool useCodeAlign(const MCSection &Sec) const final; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 1641c3eb535a9..cb697cd64d199 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2840,9 +2840,13 @@ bool AsmPrinter::doFinalization(Module &M) { // If we don't have any trampolines, then we don't require stack memory // to be executable. Some targets have a directive to declare this. Function *InitTrampolineIntrinsic = M.getFunction("llvm.init.trampoline"); + MCSection *S = nullptr; if (!InitTrampolineIntrinsic || InitTrampolineIntrinsic->use_empty()) - if (MCSection *S = MAI->getNonexecutableStackSection(OutContext)) - OutStreamer->switchSection(S); + S = MAI->getNonexecutableStackSection(OutContext); + else + S = MAI->getExecutableStackSection(OutContext); + if (S) + OutStreamer->switchSection(S); if (TM.Options.EmitAddrsig) { // Emit address-significance attributes for all globals. diff --git a/llvm/lib/MC/MCAsmInfoELF.cpp b/llvm/lib/MC/MCAsmInfoELF.cpp index cdae9d7860f33..495343a2c89d2 100644 --- a/llvm/lib/MC/MCAsmInfoELF.cpp +++ b/llvm/lib/MC/MCAsmInfoELF.cpp @@ -35,6 +35,14 @@ MCSection *MCAsmInfoELF::getNonexecutableStackSection(MCContext &Ctx) const { return Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0); } +MCSection *MCAsmInfoELF::getExecutableStackSection(MCContext &Ctx) const { + MCSectionELF *section = + static_cast<MCSectionELF *>(getNonexecutableStackSection(Ctx)); + if (section) + section->setFlags(section->getFlags() | ELF::SHF_EXECINSTR); + return section; +} + bool MCAsmInfoELF::useCodeAlign(const MCSection &Sec) const { return static_cast<const MCSectionELF &>(Sec).getFlags() & ELF::SHF_EXECINSTR; } diff --git a/llvm/test/CodeGen/AArch64/trampoline.ll b/llvm/test/CodeGen/AArch64/trampoline.ll index 0e682704afbf8..6689425bf5832 100644 --- a/llvm/test/CodeGen/AArch64/trampoline.ll +++ b/llvm/test/CodeGen/AArch64/trampoline.ll @@ -263,3 +263,4 @@ define i64 @func2() { %fp = call ptr @llvm.adjust.trampoline(ptr @trampg) ret i64 0 } +; CHECK-LINUX: .section ".note.GNU-stack","x",@progbits diff --git a/llvm/test/CodeGen/RISCV/rv64-trampoline.ll b/llvm/test/CodeGen/RISCV/rv64-trampoline.ll index 34d46579518ea..69c905002032d 100644 --- a/llvm/test/CodeGen/RISCV/rv64-trampoline.ll +++ b/llvm/test/CodeGen/RISCV/rv64-trampoline.ll @@ -71,6 +71,7 @@ define i64 @test0(i64 %n, ptr %p) nounwind { ; RV64-LINUX-NEXT: ld ra, 56(sp) # 8-byte Folded Reload ; RV64-LINUX-NEXT: addi sp, sp, 64 ; RV64-LINUX-NEXT: ret +; RV64-LINUX: .section ".note.GNU-stack","x",@progbits %alloca = alloca [32 x i8], align 8 call void @llvm.init.trampoline(ptr %alloca, ptr @f, ptr %p) %tramp = call ptr @llvm.adjust.trampoline(ptr %alloca) 
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To quote the top of this file:

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 

You need ; UTC_ARGS: --disable before this to mark a region that UTC should not be managing. Maybe also best to put an enable back after it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @jrtc27. I'll update the test cases.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Same as AArch64, this is a UTC file
  2. This belongs outside the function
  3. Does non-Linux not need this too?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @jrtc27. I updated the test cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a bool parameter to getNonexecutableStackSection and rename it to getStackSection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @MaskRay. I renamed the getNonexecutableStackSection.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Canonical way (preferred by clang-tidy) /*Exec=*/false. ditto above

In the presence of trampolines, the .note.GNU-stack section is not emitted. The absence of .note.GNU-stack results in the stack marked executable by some linkers. But others require an explict .note.GNU-stack section. The GNU ld 2.43 on x86 machines, for example, issues the following: missing .note.GNU-stack section implies executable stack NOTE: This behaviour is deprecated and will be removed in a future version of the linker On one of the ARM machines, the absence of .note.GNU-stack results in the stack marked as non-executable: STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4 filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw- This change just emits the explicit .note.GNU-stack and marks it executable.
@ssijaric-nv ssijaric-nv force-pushed the trampoline_exec_stack branch from 5f5a54b to 1309d6a Compare October 4, 2025 15:57
@ssijaric-nv ssijaric-nv merged commit 24c1bb6 into llvm:main Oct 4, 2025
9 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 4, 2025

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building llvm at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/16788

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: test (failure) ******************** TEST 'libomp :: tasking/issue-94260-2.c' FAILED ******************** Exit Code: -11 Command Output (stdout): -- # RUN: at line 1 /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic && /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp # executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic # executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp # note: command had no output on stdout or stderr # error: command failed with exit status: -11 -- ******************** 
@arsenm
Copy link
Contributor

arsenm commented Oct 6, 2025

This is breaking the Mac build:

Undefined symbols for architecture arm64: "llvm::MCAsmInfoELF::getNonexecutableStackSection(llvm::MCContext&) const", referenced from: vtable for llvm::AVRMCAsmInfo in libLLVMAVRDesc.a[6](AVRMCAsmInfo.cpp.o) vtable for llvm::LoongArchMCAsmInfo in libLLVMLoongArchDesc.a[7](LoongArchMCAsmInfo.cpp.o) vtable for llvm::SparcELFMCAsmInfo in libLLVMSparcDesc.a[5](SparcMCAsmInfo.cpp.o) vtable for llvm::VEELFMCAsmInfo in libLLVMVEDesc.a[5](VEMCAsmInfo.cpp.o) 
@ssijaric-nv
Copy link
Contributor Author

Thank you for letting me know, @arsenm. Is there a link to the buildbot log? I thought I removed all the traces of 'getNonexecutableStackSection'. I can revert while I investigate.

aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 6, 2025
In the presence of trampolines, the .note.GNU-stack section is not emitted. The absence of .note.GNU-stack results in the stack marked executable by some linkers. But others require an explict .note.GNU-stack section. The GNU ld 2.43 on x86 machines, for example, issues the following: missing .note.GNU-stack section implies executable stack NOTE: This behaviour is deprecated and will be removed in a future version of the linker On one of the ARM machines, the absence of .note.GNU-stack results in the stack marked as non-executable: STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4 filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw- This change just emits the explicit .note.GNU-stack and marks it executable if required.
@arsenm
Copy link
Contributor

arsenm commented Oct 6, 2025

Thank you for letting me know, @arsenm. Is there a link to the buildbot log? I thought I removed all the traces of 'getNonexecutableStackSection'. I can revert while I investigate.

Not sure there' a bot, we have fairly poor macOS bot coverage. touching those targets MCTargetDesc seems to have worked, so maybe there's a cmake issue somewhere?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment