[llvm] a190f15 - [AArch64] Add support for SHF_AARCH64_PURECODE ELF section flag (1/3) (#125687)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 14 00:56:11 PST 2025
Author: Csanád Hajdú
Date: 2025-02-14T08:56:07Z
New Revision: a190f15d2b84e873ee978d0e6f04bf36e8f17583
URL: https://github.com/llvm/llvm-project/commit/a190f15d2b84e873ee978d0e6f04bf36e8f17583
DIFF: https://github.com/llvm/llvm-project/commit/a190f15d2b84e873ee978d0e6f04bf36e8f17583.diff
LOG: [AArch64] Add support for SHF_AARCH64_PURECODE ELF section flag (1/3) (#125687)
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.
Generating object files with the `SHF_AARCH64_PURECODE` flag set is
enabled by the `+execute-only` target feature.
Related PRs:
* Clang: https://github.com/llvm/llvm-project/pull/125688
* LLD: https://github.com/llvm/llvm-project/pull/125689
Added:
llvm/test/CodeGen/AArch64/execute-only-section.ll
llvm/test/MC/ELF/AArch64/execute-only-populated-text-section.s
llvm/test/MC/ELF/AArch64/execute-only-section.s
llvm/test/MC/ELF/AArch64/execute-only-text-section-data.s
Modified:
llvm/include/llvm/BinaryFormat/ELF.h
llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
llvm/lib/MC/MCParser/ELFAsmParser.cpp
llvm/lib/MC/MCSectionELF.cpp
llvm/lib/ObjectYAML/ELFYAML.cpp
llvm/lib/Target/AArch64/AArch64Features.td
llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
llvm/test/MC/ELF/section-flags-unknown.s
llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll
llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
llvm/test/tools/llvm-readobj/ELF/gnu-sections.test
llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test
llvm/tools/llvm-readobj/ELFDumper.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 4b826bbf58f17..64f643749d6ac 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1299,8 +1299,11 @@ enum : unsigned {
// Section data is string data by default.
SHF_MIPS_STRING = 0x80000000,
- // Make code section unreadable when in execute-only mode
- SHF_ARM_PURECODE = 0x20000000
+ // Section contains only program instructions and no program data.
+ 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 9f44f8b1c0f56..be2f5fb0b4a79 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,8 +559,12 @@ static unsigned getELFSectionFlags(SectionKind K) {
if (K.isText())
Flags |= ELF::SHF_EXECINSTR;
- if (K.isExecuteOnly())
- Flags |= ELF::SHF_ARM_PURECODE;
+ if (K.isExecuteOnly()) {
+ if (T.isAArch64())
+ Flags |= ELF::SHF_AARCH64_PURECODE;
+ else if (T.isARM() || T.isThumb())
+ Flags |= ELF::SHF_ARM_PURECODE;
+ }
if (K.isWriteable())
Flags |= ELF::SHF_WRITE;
@@ -845,7 +849,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;
@@ -952,7 +956,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.
@@ -972,7 +976,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 b58210b3c268e..99b13c68a9966 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 25e62b70b5e2a..72a959b1c9208 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 539834fc8d4db..05e4d85b2ea5d 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 d47dcfe92ff19..357f526d5e308 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 8729fd4b802c8..434ae32502d48 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 0c822ac84f200..3e9cd51b742a2 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 a40e4e563843e..a8cf4aba6186d 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,19 @@ 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 a "+execute-only" callee can be inlined into a caller without
+ // "+execute-only", but not vice versa.
+ 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 b65e3c7a1ab20..481cb5511a331 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 6b5c5f36cbd4b..d29d383bc2312 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 0000000000000..182afd7479e3d
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/execute-only-section.ll
@@ -0,0 +1,39 @@
+; RUN: llc -mtriple=aarch64 -mattr=+execute-only %s -o - | FileCheck %s
+
+$test_comdat = comdat any
+
+; CHECK: .section .text,"axy", at progbits,unique,0
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_section_for_global
+; CHECK: .type test_section_for_global, at function
+define void @test_section_for_global() {
+entry:
+ ret void
+}
+
+; CHECK: .section .text.test_comdat,"axGy", at progbits,test_comdat,comdat,unique,0
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .weak test_comdat
+; CHECK: .type test_comdat, at function
+define linkonce_odr void @test_comdat() comdat {
+entry:
+ ret void
+}
+
+; CHECK: .section .test,"axy", at progbits
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_explicit_section_for_global
+; CHECK: .type test_explicit_section_for_global, at function
+define void @test_explicit_section_for_global() section ".test" {
+entry:
+ ret void
+}
+
+; CHECK: .rodata,"a", at progbits
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_rodata
+ at test_rodata = constant i32 0, align 4
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 0000000000000..b0ba8a18d52b3
--- /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 (0x2)
+// CHECK-NEXT: SHF_EXECINSTR (0x4)
+// CHECK-NEXT: ]
+// CHECK: }
+
+// CHECK: Section {
+// CHECK: Name: .text.foo
+// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT: Flags [ (0x20000006)
+// CHECK-NEXT: SHF_AARCH64_PURECODE (0x20000000)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: SHF_EXECINSTR (0x4)
+// CHECK-NEXT: ]
+// CHECK: }
diff --git a/llvm/test/MC/ELF/AArch64/execute-only-section.s b/llvm/test/MC/ELF/AArch64/execute-only-section.s
new file mode 100644
index 0000000000000..1699a14740c62
--- /dev/null
+++ b/llvm/test/MC/ELF/AArch64/execute-only-section.s
@@ -0,0 +1,55 @@
+// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
+// RUN: | llvm-readobj -S --symbols - | FileCheck %s --check-prefix=READOBJ
+// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
+// RUN: | llvm-readelf -S --symbols - | FileCheck %s --check-prefix=READELF
+
+ .section .text,"axy", at progbits,unique,0
+ .globl foo
+ .p2align 2
+ .type foo, at function
+foo:
+ .cfi_startproc
+ ret
+.Lfunc_end0:
+ .size foo, .Lfunc_end0-foo
+ .cfi_endproc
+
+// READOBJ: Section {
+// READOBJ: Name: .text
+// READOBJ-NEXT: Type: SHT_PROGBITS (0x1)
+// READOBJ-NEXT: Flags [ (0x20000006)
+// READOBJ-NEXT: SHF_AARCH64_PURECODE (0x20000000)
+// READOBJ-NEXT: SHF_ALLOC (0x2)
+// READOBJ-NEXT: SHF_EXECINSTR (0x4)
+// READOBJ-NEXT: ]
+// READOBJ-NEXT: Address:
+// READOBJ-NEXT: Offset:
+// READOBJ-NEXT: Size: 0
+// READOBJ: }
+
+// READOBJ: Section {
+// READOBJ: Name: .text
+// READOBJ-NEXT: Type: SHT_PROGBITS (0x1)
+// READOBJ-NEXT: Flags [ (0x20000006)
+// READOBJ-NEXT: SHF_AARCH64_PURECODE (0x20000000)
+// READOBJ-NEXT: SHF_ALLOC (0x2)
+// READOBJ-NEXT: SHF_EXECINSTR (0x4)
+// READOBJ-NEXT: ]
+// READOBJ-NEXT: Address:
+// READOBJ-NEXT: Offset:
+// READOBJ-NEXT: Size: 4
+// READOBJ: }
+
+// READOBJ: Symbol {
+// READOBJ: Name: foo
+// READOBJ-NEXT: Value:
+// READOBJ-NEXT: Size: 4
+// READOBJ-NEXT: Binding: Global
+// READOBJ-NEXT: Type: Function
+// READOBJ-NEXT: Other:
+// READOBJ-NEXT: Section: .text
+// READOBJ: }
+
+// READELF: Section Headers:
+// READELF: .text PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} 000000 {{[0-9a-f]+}} AXy {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
+// READELF: .text PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} 000004 {{[0-9a-f]+}} AXy {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
diff --git a/llvm/test/MC/ELF/AArch64/execute-only-text-section-data.s b/llvm/test/MC/ELF/AArch64/execute-only-text-section-data.s
new file mode 100644
index 0000000000000..22bcffae67d0e
--- /dev/null
+++ b/llvm/test/MC/ELF/AArch64/execute-only-text-section-data.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
+ .ascii "test"
+
+ .section .text.foo,"axy"
+ ret
+
+// CHECK: Section {
+// CHECK: Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT: Flags [ (0x6)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: SHF_EXECINSTR (0x4)
+// CHECK-NEXT: ]
+// CHECK: }
+
+// CHECK: Section {
+// CHECK: Name: .text.foo
+// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT: Flags [ (0x20000006)
+// CHECK-NEXT: SHF_AARCH64_PURECODE (0x20000000)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: SHF_EXECINSTR (0x4)
+// CHECK-NEXT: ]
+// CHECK: }
diff --git a/llvm/test/MC/ELF/section-flags-unknown.s b/llvm/test/MC/ELF/section-flags-unknown.s
index 90c9185e8bfb1..5dca55f25658c 100644
--- a/llvm/test/MC/ELF/section-flags-unknown.s
+++ b/llvm/test/MC/ELF/section-flags-unknown.s
@@ -11,8 +11,9 @@
# CHECK: {{.*}}.s:[[# @LINE+1]]:27: error: unknown flag
.section SHF_HEX_GPREL,"s", at progbits
-# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
-.section SHF_ARM_PURECODE,"y", at progbits
+## Test SHF_ARM_PURECODE and SHF_AARCH64_PURECODE section flags
+# CHECK: {{.*}}.s:[[# @LINE+1]]:22: error: unknown flag
+.section purecode,"y", at progbits
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
.section SHF_X86_64_LARGE,"l", at progbits
diff --git a/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll b/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll
index 636f3c6600f8d..433a9c7bdd23b 100644
--- a/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll
+++ b/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll
@@ -27,6 +27,14 @@ entry:
; CHECK: call i32 @bar()
}
+define i32 @quux() #3 {
+entry:
+ %call = call i32 (...) @baz()
+ ret i32 %call
+; CHECK-LABEL: quux
+; CHECK: call i32 (...) @baz()
+}
+
define i32 @strict_align() #2 {
entry:
%call = call i32 @foo()
@@ -35,6 +43,23 @@ entry:
; CHECK: call i32 (...) @baz()
}
+define i32 @execute_only1() #3 {
+entry:
+ %call = call i32 @foo()
+ ret i32 %call
+; CHECK-LABEL: execute_only1
+; CHECK: call i32 @foo()
+}
+
+define i32 @execute_only2() #0 {
+entry:
+ %call = call i32 @quux()
+ ret i32 %call
+; CHECK-LABEL: execute_only2
+; CHECK: call i32 (...) @baz()
+}
+
attributes #0 = { "target-cpu"="generic" "target-features"="+crc,+neon" }
attributes #1 = { "target-cpu"="generic" "target-features"="+crc,+neon,+crypto" }
attributes #2 = { "target-cpu"="generic" "target-features"="+crc,+neon,+strict-align" }
+attributes #3 = { "target-cpu"="generic" "target-features"="+crc,+neon,+execute-only" }
diff --git a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
index 6141f797ecd49..51a01f3f6712a 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/rename-section-flag-osproc-mask.test
@@ -121,3 +121,28 @@ Sections:
# ARM-NEXT: SHF_ARM_PURECODE (0x20000000)
# ARM-NEXT: SHF_WRITE (0x1)
# ARM-NEXT: ]
+
+# ===== aarch64 =====
+
+# RUN: yaml2obj --docnum=5 %s -o %t-aarch64.o
+# RUN: llvm-objcopy --rename-section=.foo=.bar,alloc %t-aarch64.o
+# RUN: llvm-readobj --sections %t-aarch64.o | FileCheck %s --check-prefix=AARCH64
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_AARCH64
+Sections:
+ - Name: .foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_AARCH64_PURECODE ]
+
+# AARCH64: Name: .bar
+# AARCH64-NEXT: Type: SHT_PROGBITS
+# AARCH64-NEXT: Flags [
+# AARCH64-NEXT: SHF_AARCH64_PURECODE (0x20000000)
+# AARCH64-NEXT: SHF_ALLOC (0x2)
+# AARCH64-NEXT: SHF_WRITE (0x1)
+# AARCH64-NEXT: ]
diff --git a/llvm/test/tools/llvm-readobj/ELF/gnu-sections.test b/llvm/test/tools/llvm-readobj/ELF/gnu-sections.test
index 02d082329c3d8..25eeee5a95919 100644
--- a/llvm/test/tools/llvm-readobj/ELF/gnu-sections.test
+++ b/llvm/test/tools/llvm-readobj/ELF/gnu-sections.test
@@ -99,14 +99,16 @@ Symbols:
# ELF64-NEXT: C (compressed), x (unknown), o (OS specific), E (exclude),
# ELF64-NEXT: R (retain), l (large), p (processor specific)
-## For an EM_ARM target we print "y" for the SHF_ARM_PURECODE section flag.
+## For an EM_ARM or EM_AARCH64 target we print "y" for the PURECODE section flag.
## Check we mention it in the flag key.
# RUN: yaml2obj -DMACHINE=EM_ARM %s -o %t-arm.o
-# RUN: llvm-readelf -S %t-arm.o | FileCheck %s --check-prefix=ARM --strict-whitespace --match-full-lines
+# RUN: llvm-readelf -S %t-arm.o | FileCheck %s --check-prefix=PURECODE --strict-whitespace --match-full-lines
+# RUN: yaml2obj -DMACHINE=EM_AARCH64 %s -o %t-aarch64.o
+# RUN: llvm-readelf -S %t-aarch64.o | FileCheck %s --check-prefix=PURECODE --strict-whitespace --match-full-lines
-# ARM:Key to Flags:
-# ARM-NEXT: W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
-# ARM-NEXT: L (link order), O (extra OS processing required), G (group), T (TLS),
-# ARM-NEXT: C (compressed), x (unknown), o (OS specific), E (exclude),
-# ARM-NEXT: R (retain), y (purecode), p (processor specific)
+# PURECODE:Key to Flags:
+# PURECODE-NEXT: W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
+# PURECODE-NEXT: L (link order), O (extra OS processing required), G (group), T (TLS),
+# PURECODE-NEXT: C (compressed), x (unknown), o (OS specific), E (exclude),
+# PURECODE-NEXT: R (retain), y (purecode), p (processor specific)
diff --git a/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test b/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test
index f6c74a6a44177..f546a378f32ae 100644
--- a/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test
+++ b/llvm/test/tools/llvm-readobj/ELF/section-arch-flags.test
@@ -117,7 +117,7 @@ Sections:
Type: SHT_PROGBITS
Flags: [ SHF_X86_64_LARGE, SHF_EXCLUDE ]
-# RUN: yaml2obj --docnum 5 %s -o %t-arm.o
+# RUN: yaml2obj --docnum 5 -DARCH=ARM %s -o %t-arm.o
# RUN: llvm-readobj -S %t-arm.o | FileCheck --check-prefix=ARM-LLVM %s
# RUN: llvm-readelf -S %t-arm.o | FileCheck --check-prefix=ARM-GNU %s
@@ -128,13 +128,24 @@ Sections:
# ARM-GNU: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
# ARM-GNU: [ 1] foo PROGBITS 0000000000000000 000040 000000 00 y 0 0 0
+# RUN: yaml2obj --docnum 5 -DARCH=AARCH64 %s -o %t-aarch64.o
+# RUN: llvm-readobj -S %t-aarch64.o | FileCheck --check-prefix=AARCH64-LLVM %s
+# RUN: llvm-readelf -S %t-aarch64.o | FileCheck --check-prefix=AARCH64-GNU %s
+
+# AARCH64-LLVM: Flags [ (0x20000000)
+# AARCH64-LLVM-NEXT: SHF_AARCH64_PURECODE (0x20000000)
+# AARCH64-LLVM-NEXT: ]
+
+# AARCH64-GNU: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
+# AARCH64-GNU: [ 1] foo PROGBITS 0000000000000000 000040 000000 00 y 0 0 0
+
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
- Machine: EM_ARM
+ Machine: EM_[[ARCH]]
Sections:
- Name: foo
Type: SHT_PROGBITS
- Flags: [ SHF_ARM_PURECODE ]
+ Flags: [ SHF_[[ARCH]]_PURECODE ]
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 2128a95510f22..2da08127f20a8 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -1337,6 +1337,10 @@ const EnumEntry<unsigned> ElfXCoreSectionFlags[] = {
ENUM_ENT(XCORE_SHF_DP_SECTION, "")
};
+const EnumEntry<unsigned> ElfAArch64SectionFlags[] = {
+ ENUM_ENT(SHF_AARCH64_PURECODE, "y")
+};
+
const EnumEntry<unsigned> ElfARMSectionFlags[] = {
ENUM_ENT(SHF_ARM_PURECODE, "y")
};
@@ -1375,6 +1379,10 @@ getSectionFlagsForTarget(unsigned EOSAbi, unsigned EMachine) {
break;
}
switch (EMachine) {
+ case EM_AARCH64:
+ Ret.insert(Ret.end(), std::begin(ElfAArch64SectionFlags),
+ std::end(ElfAArch64SectionFlags));
+ break;
case EM_ARM:
Ret.insert(Ret.end(), std::begin(ElfARMSectionFlags),
std::end(ElfARMSectionFlags));
@@ -4104,7 +4112,7 @@ static void printSectionDescription(formatted_raw_ostream &OS,
if (EMachine == EM_X86_64)
OS << ", l (large)";
- else if (EMachine == EM_ARM)
+ else if (EMachine == EM_ARM || EMachine == EM_AARCH64)
OS << ", y (purecode)";
OS << ", p (processor specific)\n";
More information about the llvm-commits
mailing list