[lld] [llvm] [LLD][ELF][AArch64] Add support for SHF_AARCH64_PURECODE ELF section flag (3/3) (PR #125689)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 4 06:17:04 PST 2025
=?utf-8?q?Csanád_Hajdú?= <csanad.hajdu at arm.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/125689 at github.com>
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Csanád Hajdú (Il-Capitano)
<details>
<summary>Changes</summary>
Add support for the new SHF_AARCH64_PURECODE ELF section flag: https://github.com/ARM-software/abi-aa/pull/304
The general implementation follows the existing one for ARM targets. The output section only has the `SHF_AARCH64_PURECODE` flag set if all input sections have it set.
Depends on https://github.com/llvm/llvm-project/pull/125687. The changes in that PR are included here as well for now, but will be removed once that gets merged.
---
Patch is 25.54 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/125689.diff
23 Files Affected:
- (modified) lld/ELF/Config.h (+1)
- (modified) lld/ELF/Driver.cpp (+44-4)
- (modified) lld/ELF/OutputSections.cpp (+7-3)
- (modified) lld/ELF/ScriptParser.cpp (+1)
- (added) lld/test/ELF/aarch64-execute-only.s (+33)
- (modified) llvm/include/llvm/BinaryFormat/ELF.h (+4-1)
- (modified) llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (+8-5)
- (modified) llvm/lib/MC/MCParser/ELFAsmParser.cpp (+5-2)
- (modified) llvm/lib/MC/MCSectionELF.cpp (+3)
- (modified) llvm/lib/ObjectYAML/ELFYAML.cpp (+3)
- (modified) llvm/lib/Target/AArch64/AArch64Features.td (+5)
- (modified) llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp (+26)
- (modified) llvm/lib/Target/AArch64/AArch64TargetObjectFile.h (+6)
- (modified) llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp (+16-1)
- (modified) llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h (+2)
- (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp (+18)
- (added) llvm/test/CodeGen/AArch64/execute-only-section.ll (+21)
- (added) llvm/test/MC/ELF/AArch64/execute-only-populated-text-section.s (+27)
- (added) llvm/test/MC/ELF/AArch64/execute-only-section.s (+43)
- (added) llvm/test/MC/ELF/AArch64/execute-only-text-section-data.s (+27)
- (modified) llvm/test/MC/ELF/section-flags-unknown.s (+3)
- (modified) llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll (+25)
- (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+8)
``````````diff
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index c2aadb2cef5200f..ecfb492522227bc 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -229,6 +229,7 @@ struct Config {
StringRef zCetReport = "none";
StringRef zPauthReport = "none";
StringRef zGcsReport = "none";
+ StringRef zExecuteOnlyReport = "none";
bool ltoBBAddrMap;
llvm::StringRef ltoBasicBlockSections;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index acbc97b331b0e1c..f9c61584984a8f5 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -459,6 +459,8 @@ static void checkOptions(Ctx &ctx) {
ErrAlways(ctx) << "-z gcs-report only supported on AArch64";
if (ctx.arg.zGcs != GcsPolicy::Implicit)
ErrAlways(ctx) << "-z gcs only supported on AArch64";
+ if (ctx.arg.zExecuteOnlyReport != "none")
+ ErrAlways(ctx) << "-z execute-only-report only supported on AArch64";
}
if (ctx.arg.emachine != EM_386 && ctx.arg.emachine != EM_X86_64 &&
@@ -1557,10 +1559,12 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
ErrAlways(ctx) << errPrefix << pat.takeError() << ": " << kv.first;
}
- auto reports = {std::make_pair("bti-report", &ctx.arg.zBtiReport),
- std::make_pair("cet-report", &ctx.arg.zCetReport),
- std::make_pair("gcs-report", &ctx.arg.zGcsReport),
- std::make_pair("pauth-report", &ctx.arg.zPauthReport)};
+ auto reports = {
+ std::make_pair("bti-report", &ctx.arg.zBtiReport),
+ std::make_pair("cet-report", &ctx.arg.zCetReport),
+ std::make_pair("gcs-report", &ctx.arg.zGcsReport),
+ std::make_pair("pauth-report", &ctx.arg.zPauthReport),
+ std::make_pair("execute-only-report", &ctx.arg.zExecuteOnlyReport)};
for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
StringRef(arg->getValue()).split('=');
@@ -2844,6 +2848,40 @@ static void readSecurityNotes(Ctx &ctx) {
ctx.arg.andFeatures &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
}
+static void checkExecuteOnly(Ctx &ctx) {
+ if (ctx.arg.emachine != EM_AARCH64)
+ return;
+
+ auto report = [&](StringRef config) -> ELFSyncStream {
+ if (config == "error")
+ return {ctx, DiagLevel::Err};
+ if (config == "warning")
+ return {ctx, DiagLevel::Warn};
+ return {ctx, DiagLevel::None};
+ };
+ auto reportUnless = [&](StringRef config, bool cond) -> ELFSyncStream {
+ if (cond)
+ return {ctx, DiagLevel::None};
+ return report(config);
+ };
+
+ for (ELFFileBase *file : ctx.objectFiles) {
+ for (InputSectionBase *section : file->getSections()) {
+ // Only check for executable sections.
+ if (!(section && section->flags & SHF_EXECINSTR))
+ continue;
+
+ OutputSection *outputSection = section->getOutputSection();
+ if (outputSection && outputSection->name == ".text") {
+ reportUnless(ctx.arg.zExecuteOnlyReport,
+ section->flags & SHF_AARCH64_PURECODE)
+ << file << ": -z execute-only-report: section " << section->name
+ << " does not have SHF_AARCH64_PURECODE flag set";
+ }
+ }
+ }
+}
+
static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) {
switch (file->ekind) {
case ELF32LEKind:
@@ -3213,6 +3251,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
ctx.script->addOrphanSections();
}
+ checkExecuteOnly(ctx);
+
{
llvm::TimeTraceScope timeScope("Merge/finalize input sections");
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index a2da5543d58670f..c8dc0e5fe033528 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -42,7 +42,8 @@ using namespace lld::elf;
uint32_t OutputSection::getPhdrFlags() const {
uint32_t ret = 0;
- if (ctx.arg.emachine != EM_ARM || !(flags & SHF_ARM_PURECODE))
+ if ((ctx.arg.emachine != EM_ARM || !(flags & SHF_ARM_PURECODE)) &&
+ (ctx.arg.emachine != EM_AARCH64 || !(flags & SHF_AARCH64_PURECODE)))
ret |= PF_R;
if (flags & SHF_WRITE)
ret |= PF_W;
@@ -161,8 +162,11 @@ void OutputSection::commitSection(InputSection *isec) {
}
isec->parent = this;
- uint64_t andMask =
- ctx.arg.emachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0;
+ uint64_t andMask = 0;
+ if (ctx.arg.emachine == EM_ARM)
+ andMask |= (uint64_t)SHF_ARM_PURECODE;
+ if (ctx.arg.emachine == EM_AARCH64)
+ andMask |= (uint64_t)SHF_AARCH64_PURECODE;
uint64_t orMask = ~andMask;
uint64_t andFlags = (flags & isec->flags) & andMask;
uint64_t orFlags = (flags | isec->flags) & orMask;
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index a10af9565a1d631..671a5ec4deccba3 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -1411,6 +1411,7 @@ static std::optional<uint64_t> parseFlag(StringRef tok) {
.Case(CASE_ENT(SHF_COMPRESSED))
.Case(CASE_ENT(SHF_EXCLUDE))
.Case(CASE_ENT(SHF_ARM_PURECODE))
+ .Case(CASE_ENT(SHF_AARCH64_PURECODE))
.Default(std::nullopt);
#undef CASE_ENT
}
diff --git a/lld/test/ELF/aarch64-execute-only.s b/lld/test/ELF/aarch64-execute-only.s
new file mode 100644
index 000000000000000..e67bbf05ff2e215
--- /dev/null
+++ b/lld/test/ELF/aarch64-execute-only.s
@@ -0,0 +1,33 @@
+// REQUIRES: aarch64
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readelf -l %t.so | FileCheck --implicit-check-not=LOAD %s
+
+// RUN: echo ".section .foo,\"ax\"; \
+// RUN: ret" > %t.s
+// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %t.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t.so -shared
+// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF --implicit-check-not=LOAD %s
+
+// CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x10000
+// CHECK: LOAD 0x000248 0x0000000000010248 0x0000000000010248 0x{{.*}} 0x{{.*}} R E 0x10000
+// CHECK: LOAD 0x00024c 0x000000000002024c 0x000000000002024c 0x{{.*}} 0x{{.*}} E 0x10000
+// CHECK: LOAD 0x000250 0x0000000000030250 0x0000000000030250 0x000070 0x000db0 RW 0x10000
+
+// CHECK: 01 .dynsym .gnu.hash .hash .dynstr
+// CHECK: 02 .text
+// CHECK: 03 .foo
+// CHECK: 04 .dynamic
+
+// DIFF: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00020d 0x00020d R 0x10000
+// DIFF: LOAD 0x000210 0x0000000000010210 0x0000000000010210 0x00000c 0x00000c R E 0x10000
+// DIFF: LOAD 0x000220 0x0000000000020220 0x0000000000020220 0x000070 0x000de0 RW 0x10000
+
+// DIFF: 01 .dynsym .gnu.hash .hash .dynstr
+// DIFF: 02 .text .foo
+// DIFF: 03 .dynamic
+
+ ret
+ .section .foo,"axy"
+ ret
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 8853c4a88b0b593..a5979d029a9eafd 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1300,7 +1300,10 @@ enum : unsigned {
SHF_MIPS_STRING = 0x80000000,
// Make code section unreadable when in execute-only mode
- SHF_ARM_PURECODE = 0x20000000
+ SHF_ARM_PURECODE = 0x20000000,
+
+ // Section contains only program instructions and no program data.
+ SHF_AARCH64_PURECODE = 0x20000000
};
// Section Group Flags
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 3c2c7c8c9fed69a..6cfebca9a4d576e 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -547,7 +547,7 @@ static unsigned getELFSectionType(StringRef Name, SectionKind K) {
return ELF::SHT_PROGBITS;
}
-static unsigned getELFSectionFlags(SectionKind K) {
+static unsigned getELFSectionFlags(SectionKind K, const Triple &T) {
unsigned Flags = 0;
if (!K.isMetadata() && !K.isExclude())
@@ -559,9 +559,12 @@ static unsigned getELFSectionFlags(SectionKind K) {
if (K.isText())
Flags |= ELF::SHF_EXECINSTR;
- if (K.isExecuteOnly())
+ if ((T.isARM() || T.isThumb()) && K.isExecuteOnly())
Flags |= ELF::SHF_ARM_PURECODE;
+ if (T.isAArch64() && K.isExecuteOnly())
+ Flags |= ELF::SHF_AARCH64_PURECODE;
+
if (K.isWriteable())
Flags |= ELF::SHF_WRITE;
@@ -840,7 +843,7 @@ static MCSection *selectExplicitSectionGlobal(const GlobalObject *GO,
// Infer section flags from the section name if we can.
Kind = getELFKindForNamedSection(SectionName, Kind);
- unsigned Flags = getELFSectionFlags(Kind);
+ unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
auto [Group, IsComdat, ExtraFlags] = getGlobalObjectInfo(GO, TM);
Flags |= ExtraFlags;
@@ -947,7 +950,7 @@ static MCSection *selectELFSectionForGlobal(
MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
- unsigned Flags = getELFSectionFlags(Kind);
+ unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
// If we have -ffunction-section or -fdata-section then we should emit the
// global value to a uniqued section specifically for it.
@@ -967,7 +970,7 @@ MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
MCSection *TargetLoweringObjectFileELF::getUniqueSectionForFunction(
const Function &F, const TargetMachine &TM) const {
SectionKind Kind = SectionKind::getText();
- unsigned Flags = getELFSectionFlags(Kind);
+ unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
// If the function's section names is pre-determined via pragma or a
// section attribute, call selectExplicitSectionGlobal.
if (F.hasSection())
diff --git a/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
index b58210b3c268e99..99b13c68a9966c7 100644
--- a/llvm/lib/MC/MCParser/ELFAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
@@ -328,9 +328,12 @@ static unsigned parseSectionFlags(const Triple &TT, StringRef flagsStr,
flags |= ELF::XCORE_SHF_DP_SECTION;
break;
case 'y':
- if (!(TT.isARM() || TT.isThumb()))
+ if (TT.isARM() || TT.isThumb())
+ flags |= ELF::SHF_ARM_PURECODE;
+ else if (TT.isAArch64())
+ flags |= ELF::SHF_AARCH64_PURECODE;
+ else
return -1U;
- flags |= ELF::SHF_ARM_PURECODE;
break;
case 's':
if (TT.getArch() != Triple::hexagon)
diff --git a/llvm/lib/MC/MCSectionELF.cpp b/llvm/lib/MC/MCSectionELF.cpp
index 25e62b70b5e2a0c..72a959b1c920825 100644
--- a/llvm/lib/MC/MCSectionELF.cpp
+++ b/llvm/lib/MC/MCSectionELF.cpp
@@ -118,6 +118,9 @@ void MCSectionELF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
} else if (T.isARM() || T.isThumb()) {
if (Flags & ELF::SHF_ARM_PURECODE)
OS << 'y';
+ } else if (T.isAArch64()) {
+ if (Flags & ELF::SHF_AARCH64_PURECODE)
+ OS << 'y';
} else if (Arch == Triple::hexagon) {
if (Flags & ELF::SHF_HEX_GPREL)
OS << 's';
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 539834fc8d4dbfe..05e4d85b2ea5d24 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -803,6 +803,9 @@ void ScalarBitSetTraits<ELFYAML::ELF_SHF>::bitset(IO &IO,
break;
}
switch (Object->getMachine()) {
+ case ELF::EM_AARCH64:
+ BCase(SHF_AARCH64_PURECODE);
+ break;
case ELF::EM_ARM:
BCase(SHF_ARM_PURECODE);
break;
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index 20db70ee38572f2..7c95ba662938d9f 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -635,6 +635,11 @@ def FeatureStrictAlign : SubtargetFeature<"strict-align",
"Disallow all unaligned memory "
"access">;
+def FeatureExecuteOnly : SubtargetFeature<"execute-only",
+ "GenExecuteOnly", "true",
+ "Enable the generation of "
+ "execute only code.">;
+
foreach i = {1-7,9-15,18,20-28} in
def FeatureReserveX#i : SubtargetFeature<"reserve-x"#i, "ReserveXRegister["#i#"]", "true",
"Reserve X"#i#", making it unavailable "
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
index 8729fd4b802c8eb..434ae32502d484b 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
@@ -148,3 +148,29 @@ MCSymbol *AArch64_MachoTargetObjectFile::getAuthPtrSlotSymbol(
return getAuthPtrSlotSymbolHelper(getContext(), TM, MMI, MachOMMI, RawSym,
Key, Discriminator);
}
+
+static bool isExecuteOnlyFunction(const GlobalObject *GO, SectionKind Kind,
+ const TargetMachine &TM) {
+ if (const Function *F = dyn_cast<Function>(GO))
+ if (TM.getSubtarget<AArch64Subtarget>(*F).genExecuteOnly() && Kind.isText())
+ return true;
+ return false;
+}
+
+MCSection *AArch64_ELFTargetObjectFile::getExplicitSectionGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+ // Set execute-only access for the explicit section
+ if (isExecuteOnlyFunction(GO, Kind, TM))
+ Kind = SectionKind::getExecuteOnly();
+
+ return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, Kind, TM);
+}
+
+MCSection *AArch64_ELFTargetObjectFile::SelectSectionForGlobal(
+ const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+ // Set execute-only access for the explicit section
+ if (isExecuteOnlyFunction(GO, Kind, TM))
+ Kind = SectionKind::getExecuteOnly();
+
+ return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
+}
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
index 0c822ac84f200c7..3e9cd51b742a29c 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
@@ -39,6 +39,12 @@ class AArch64_ELFTargetObjectFile : public TargetLoweringObjectFileELF {
void emitPersonalityValueImpl(MCStreamer &Streamer, const DataLayout &DL,
const MCSymbol *Sym,
const MachineModuleInfo *MMI) const override;
+
+ MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
+ const TargetMachine &TM) const override;
+
+ MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
+ const TargetMachine &TM) const override;
};
/// AArch64_MachoTargetObjectFile - This TLOF implementation is used for Darwin.
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index a6edcf125782b2c..284278e34f8b4d0 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -262,6 +262,10 @@ bool AArch64TTIImpl::isMultiversionedFunction(const Function &F) const {
return F.hasFnAttribute("fmv-features");
}
+const FeatureBitset AArch64TTIImpl::InlineInverseFeatures = {
+ AArch64::FeatureExecuteOnly,
+};
+
bool AArch64TTIImpl::areInlineCompatible(const Function *Caller,
const Function *Callee) const {
SMEAttrs CallerAttrs(*Caller), CalleeAttrs(*Callee);
@@ -284,7 +288,18 @@ bool AArch64TTIImpl::areInlineCompatible(const Function *Caller,
return false;
}
- return BaseT::areInlineCompatible(Caller, Callee);
+ const TargetMachine &TM = getTLI()->getTargetMachine();
+ const FeatureBitset &CallerBits =
+ TM.getSubtargetImpl(*Caller)->getFeatureBits();
+ const FeatureBitset &CalleeBits =
+ TM.getSubtargetImpl(*Callee)->getFeatureBits();
+ // Adjust the feature bitsets by inverting some of the bits. This is needed
+ // for target features that represent restrictions rather than capabilities,
+ // for example "+execute-only".
+ FeatureBitset EffectiveCallerBits = CallerBits ^ InlineInverseFeatures;
+ FeatureBitset EffectiveCalleeBits = CalleeBits ^ InlineInverseFeatures;
+
+ return (EffectiveCallerBits & EffectiveCalleeBits) == EffectiveCalleeBits;
}
bool AArch64TTIImpl::areTypesABICompatible(
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
index b65e3c7a1ab20e5..481cb5511a331b7 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
@@ -48,6 +48,8 @@ class AArch64TTIImpl : public BasicTTIImplBase<AArch64TTIImpl> {
const AArch64Subtarget *ST;
const AArch64TargetLowering *TLI;
+ static const FeatureBitset InlineInverseFeatures;
+
const AArch64Subtarget *getST() const { return ST; }
const AArch64TargetLowering *getTLI() const { return TLI; }
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index 6b5c5f36cbd4b27..d29d383bc231277 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
@@ -27,6 +27,7 @@
#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"
@@ -504,6 +505,23 @@ 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-section.ll b/llvm/test/CodeGen/AArch64/execute-only-section.ll
new file mode 100644
index 000000000000000..15a270b07975e69
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/execute-only-section.ll
@@ -0,0 +1,21 @@
+; RUN: llc -mtriple=aarch64 -mattr=+execute-only %s -o - | FileCheck %s
+
+; CHECK: .section .text,"axy", at progbits,unique,0
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_SectionForGlobal
+; CHECK: .type test_SectionForGlobal, at function
+define void @test_SectionForGlobal() {
+entry:
+ ret void
+}
+
+; CHECK: .section .test,"axy", at progbits
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_ExplicitSectionForGlobal
+; CHECK: .type test_ExplicitSectionForGlobal, at function
+define void @test_ExplicitSectionForGlobal() section ".test" {
+entry:
+ ret void
+}
diff --git a/llvm/test/MC/ELF/AArch64/execute-only-populated-text-section.s b/llvm/test/MC/ELF/AArch64/execute-only-populated-text-section.s
new file mode 100644
index 000000000000000..b0ba8a18d52b386
--- /dev/null
+++ b/llvm/test/MC/ELF/AArch64/execute-only-populated-text-section.s
@@ -0,0 +1,27 @@
+// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
+// RUN: | llvm-readobj -S --symbols - | FileCheck %s
+
+ .text
+ ret
+
+ .section .text.foo,"axy"
+ ret
+
+// CHECK: Section {
+// CHECK: Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT: Flags [ (0x6)
+// CHECK-NEXT: SHF_ALLOC (0x...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/125689
More information about the llvm-commits
mailing list