Skip to content

[AArch64] Always add PURECODE flag to empty .text if "+execute-only" is set #132196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 24, 2025

Conversation

Il-Capitano
Copy link
Contributor

@Il-Capitano Il-Capitano commented Mar 20, 2025

Previously, the SHF_AARCH64_PURECODE section flag wasn't added to the implicitly created .text section if the module didn't contain any functions, because no other section had the flag set.

Now, the SHF_AARCH64_PURECODE is always added if the "+execute-only" target feature is set for the module during compilation.

…is set

The previous approach only added the `SHF_AARCH64_PURECODE` section flag
to the implicitly created `.text` section if there was any other section
containing the flag already. This doesn't work for the case, where the
module doesn't contain any code.

Now, the `SHF_AARCH64_PURECODE` is always added if the "+execute-only"
target feature is set for the module.
@llvmbot
Copy link
Member

llvmbot commented Mar 20, 2025

@llvm/pr-subscribers-backend-aarch64

Author: Csanád Hajdú (Il-Capitano)

Changes

The previous approach only added the SHF_AARCH64_PURECODE section flag to the implicitly created .text section if there was any other section containing the flag already. This doesn't work for the case, where the module doesn't contain any code.

Now, the SHF_AARCH64_PURECODE is always added if the "+execute-only" target feature is set for the module.


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

3 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp (+9)
  • (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp (-18)
  • (added) llvm/test/CodeGen/AArch64/execute-only-empty.ll (+13)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
index 434ae32502d48..b662e75741d38 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
@@ -16,6 +16,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCValue.h"
 using namespace llvm;
@@ -27,6 +28,14 @@ void AArch64_ELFTargetObjectFile::Initialize(MCContext &Ctx,
   // AARCH64 ELF ABI does not define static relocation type for TLS offset
   // within a module.  Do not generate AT_location for TLS variables.
   SupportDebugThreadLocalLocation = false;
+
+  // Make sure the implicitly created empty .text section has the
+  // SHF_AARCH64_PURECODE flag set if the "+execute-only" target feature is
+  // present.
+  if (TM.getMCSubtargetInfo()->hasFeature(AArch64::FeatureExecuteOnly)) {
+    auto *Text = cast<MCSectionELF>(TextSection);
+    Text->setFlags(Text->getFlags() | ELF::SHF_AARCH64_PURECODE);
+  }
 }
 
 void AArch64_ELFTargetObjectFile::emitPersonalityValueImpl(
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index 98bd102d8f4c1..9803129608c4b 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
@@ -27,7 +27,6 @@
 #include "llvm/MC/MCELFStreamer.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCObjectFileInfo.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
@@ -501,23 +500,6 @@ void AArch64TargetELFStreamer::finish() {
     }
   }
 
-  // The mix of execute-only and non-execute-only at link time is
-  // non-execute-only. To avoid the empty implicitly created .text
-  // section from making the whole .text section non-execute-only, we
-  // mark it execute-only if it is empty and there is at least one
-  // execute-only section in the object.
-  if (any_of(Asm, [](const MCSection &Sec) {
-        return cast<MCSectionELF>(Sec).getFlags() & ELF::SHF_AARCH64_PURECODE;
-      })) {
-    auto *Text =
-        static_cast<MCSectionELF *>(Ctx.getObjectFileInfo()->getTextSection());
-    for (auto &F : *Text)
-      if (auto *DF = dyn_cast<MCDataFragment>(&F))
-        if (!DF->getContents().empty())
-          return;
-    Text->setFlags(Text->getFlags() | ELF::SHF_AARCH64_PURECODE);
-  }
-
   MCSectionELF *MemtagSec = nullptr;
   for (const MCSymbol &Symbol : Asm.symbols()) {
     const auto &Sym = cast<MCSymbolELF>(Symbol);
diff --git a/llvm/test/CodeGen/AArch64/execute-only-empty.ll b/llvm/test/CodeGen/AArch64/execute-only-empty.ll
new file mode 100644
index 0000000000000..cdf9b3afe8daf
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/execute-only-empty.ll
@@ -0,0 +1,13 @@
+; RUN: llc -filetype=obj -mtriple=aarch64 -mattr=+execute-only %s -o %t.o
+; RUN: llvm-readobj -S %t.o | FileCheck %s
+
+; CHECK:         Name: .text
+; CHECK-NEXT:    Type: SHT_PROGBITS
+; CHECK-NEXT:    Flags [
+; CHECK-NEXT:      SHF_AARCH64_PURECODE
+; CHECK-NEXT:      SHF_ALLOC
+; CHECK-NEXT:      SHF_EXECINSTR
+; CHECK-NEXT:    ]
+; CHECK-NEXT:    Address:
+; CHECK-NEXT:    Offset:
+; CHECK-NEXT:    Size: 0

Copy link
Collaborator

@smithp35 smithp35 left a comment

Choose a reason for hiding this comment

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

LGTM.

Looking at the ARM backend code https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/ARM/ARMTargetObjectFile.cpp#L46 it does it in a slightly different way, claiming that it can't modify flags on an existing section. It looks like that restriction has been lifted though.

The tests show that it is working and it is simpler to modify, so no objections to doing it that way.

@Il-Capitano
Copy link
Contributor Author

Yeah, I'm not sure why it's that way in the ARM backend. A similar mechanism is needed in Target/ARM/MCTargetDesc/ARMELFStreamer.cpp (and AArch64ELFStreamer.cpp too), where it also modifies the flags on the existing section:

// The mix of execute-only and non-execute-only at link time is
// non-execute-only. To avoid the empty implicitly created .text
// section from making the whole .text section non-execute-only, we
// mark it execute-only if it is empty and there is at least one
// execute-only section in the object.
MCContext &Ctx = getContext();
auto &Asm = getStreamer().getAssembler();
if (any_of(Asm, [](const MCSection &Sec) {
return cast<MCSectionELF>(Sec).getFlags() & ELF::SHF_ARM_PURECODE;
})) {
auto *Text =
static_cast<MCSectionELF *>(Ctx.getObjectFileInfo()->getTextSection());
for (auto &F : *Text)
if (auto *DF = dyn_cast<MCDataFragment>(&F))
if (!DF->getContents().empty())
return;
Text->setFlags(Text->getFlags() | ELF::SHF_ARM_PURECODE);
}
}

@Il-Capitano Il-Capitano merged commit e2e776c into llvm:main Mar 24, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Mar 24, 2025

LLVM Buildbot has detected a new failure on builder lldb-aarch64-ubuntu running on linaro-lldb-aarch64-ubuntu while building llvm at step 6 "test".

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

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: functionalities/data-formatter/data-formatter-stl/libcxx-simulators/string/TestDataFormatterLibcxxStringSimulator.py (498 of 2109)
PASS: lldb-api :: functionalities/inferior-changed/TestInferiorChanged.py (499 of 2109)
PASS: lldb-api :: functionalities/inferior-crashing/TestInferiorCrashing.py (500 of 2109)
PASS: lldb-api :: functionalities/inferior-assert/TestInferiorAssert.py (501 of 2109)
PASS: lldb-api :: functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferiorStep.py (502 of 2109)
PASS: lldb-api :: functionalities/inline-sourcefile/TestInlineSourceFiles.py (503 of 2109)
PASS: lldb-api :: functionalities/inferior-crashing/TestInferiorCrashingStep.py (504 of 2109)
UNSUPPORTED: lldb-api :: functionalities/interactive_scripted_process/TestInteractiveScriptedProcess.py (505 of 2109)
PASS: lldb-api :: functionalities/json/object-file/TestObjectFileJSON.py (506 of 2109)
PASS: lldb-api :: functionalities/json/symbol-file/TestSymbolFileJSON.py (507 of 2109)
FAIL: lldb-api :: functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py (508 of 2109)
******************** TEST 'lldb-api :: functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py' FAILED ********************
Script:
--
/usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --arch aarch64 --build-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/inferior-crashing/recursive-inferior -p TestRecursiveInferior.py
--
Exit Code: -11

Command Output (stdout):
--
lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision e2e776c867c691ec57eb4effc7dcc27d6a5f2c04)
  clang revision e2e776c867c691ec57eb4effc7dcc27d6a5f2c04
  llvm revision e2e776c867c691ec57eb4effc7dcc27d6a5f2c04
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']

--
Command Output (stderr):
--
UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_dsym (TestRecursiveInferior.CrashingRecursiveInferiorTestCase) (test case does not fall in any category of interest for this run) 
PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_dwarf (TestRecursiveInferior.CrashingRecursiveInferiorTestCase)
PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_dwo (TestRecursiveInferior.CrashingRecursiveInferiorTestCase)
UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_expr_dsym (TestRecursiveInferior.CrashingRecursiveInferiorTestCase) (test case does not fall in any category of interest for this run) 
PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_expr_dwarf (TestRecursiveInferior.CrashingRecursiveInferiorTestCase)
PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_expr_dwo (TestRecursiveInferior.CrashingRecursiveInferiorTestCase)
UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_python_dsym (TestRecursiveInferior.CrashingRecursiveInferiorTestCase) (test case does not fall in any category of interest for this run) 
PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_python_dwarf (TestRecursiveInferior.CrashingRecursiveInferiorTestCase)
PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_python_dwo (TestRecursiveInferior.CrashingRecursiveInferiorTestCase)
UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_register_dsym (TestRecursiveInferior.CrashingRecursiveInferiorTestCase) (test case does not fall in any category of interest for this run) 
PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_register_dwarf (TestRecursiveInferior.CrashingRecursiveInferiorTestCase)
PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_recursive_inferior_crashing_register_dwo (TestRecursiveInferior.CrashingRecursiveInferiorTestCase)
----------------------------------------------------------------------
Ran 12 tests in 2.003s

OK (skipped=4)

--

********************
UNSUPPORTED: lldb-api :: functionalities/launch_stop_at_entry/TestStopAtEntry.py (509 of 2109)

@Il-Capitano
Copy link
Contributor Author

Il-Capitano commented Mar 24, 2025

A rebuild fixed the CI failure: https://lab.llvm.org/buildbot/#/builders/59/builds/14823. Probably just a flaky test in LLDB.

@Il-Capitano Il-Capitano deleted the execute-only-empty branch March 24, 2025 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants