[AArch64] Add support for SHF_AARCH64_PURECODE ELF section flag (1/3) - #125687
Conversation
Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#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.
|
@llvm/pr-subscribers-objectyaml @llvm/pr-subscribers-mc Author: Csanád Hajdú (Il-Capitano) ChangesAdd support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#304 The general implementation follows the existing one for ARM targets. Generating object files with the Full diff: https://github.com/llvm/llvm-project/pull/125687.diff 18 Files Affected:
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 8853c4a88b0b59..a5979d029a9eaf 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 3c2c7c8c9fed69..6cfebca9a4d576 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 b58210b3c268e9..99b13c68a9966c 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 25e62b70b5e2a0..72a959b1c92082 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 539834fc8d4dbf..05e4d85b2ea5d2 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 20db70ee38572f..7c95ba662938d9 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 8729fd4b802c8e..434ae32502d484 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 0c822ac84f200c..3e9cd51b742a29 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 a6edcf125782b2..284278e34f8b4d 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 b65e3c7a1ab20e..481cb5511a331b 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 6b5c5f36cbd4b2..d29d383bc23127 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 00000000000000..15a270b07975e6
--- /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",@progbits,unique,0
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_SectionForGlobal
+; CHECK: .type test_SectionForGlobal,@function
+define void @test_SectionForGlobal() {
+entry:
+ ret void
+}
+
+; CHECK: .section .test,"axy",@progbits
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_ExplicitSectionForGlobal
+; CHECK: .type test_ExplicitSectionForGlobal,@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 00000000000000..b0ba8a18d52b38
--- /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 00000000000000..6fd596376711d6
--- /dev/null
+++ b/llvm/test/MC/ELF/AArch64/execute-only-section.s
@@ -0,0 +1,43 @@
+// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
+// RUN: | llvm-readobj -S --symbols - | FileCheck %s
+
+ .section .text,"axy",@progbits,unique,0
+ .globl foo
+ .p2align 2
+ .type foo,@function
+foo:
+ .cfi_startproc
+ ret
+.Lfunc_end0:
+ .size foo, .Lfunc_end0-foo
+ .cfi_endproc
+
+ .section ".note.GNU-stack","",@progbits
+
+
+// CHECK: Section {
+// CHECK: Name: .text
+// 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: Size: 0
+// CHECK: }
+
+// CHECK: Section {
+// CHECK: Name: .text
+// 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: Size: 2
+// CHECK: }
+
+// CHECK: Symbol {
+// CHECK: Name: foo
+// CHECK: Section: .text (0x3)
+// CHECK: }
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 00000000000000..22bcffae67d0eb
--- /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 90c9185e8bfb10..b172403e34556c 100644
--- a/llvm/test/MC/ELF/section-flags-unknown.s
+++ b/llvm/test/MC/ELF/section-flags-unknown.s
@@ -14,5 +14,8 @@
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
.section SHF_ARM_PURECODE,"y",@progbits
+# CHECK: {{.*}}.s:[[# @LINE+1]]:34: error: unknown flag
+.section SHF_AARCH64_PURECODE,"y",@progbits
+
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
.section SHF_X86_64_LARGE,"l",@progbits
diff --git a/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll b/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll
index 636f3c6600f8d4..433a9c7bdd23b0 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/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index bfca65aad52b44..78aaf79a61c468 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));
|
|
@llvm/pr-subscribers-backend-aarch64 Author: Csanád Hajdú (Il-Capitano) ChangesAdd support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#304 The general implementation follows the existing one for ARM targets. Generating object files with the Full diff: https://github.com/llvm/llvm-project/pull/125687.diff 18 Files Affected:
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",@progbits,unique,0
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_SectionForGlobal
+; CHECK: .type test_SectionForGlobal,@function
+define void @test_SectionForGlobal() {
+entry:
+ ret void
+}
+
+; CHECK: .section .test,"axy",@progbits
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_ExplicitSectionForGlobal
+; CHECK: .type test_ExplicitSectionForGlobal,@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 (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 000000000000000..6fd596376711d6a
--- /dev/null
+++ b/llvm/test/MC/ELF/AArch64/execute-only-section.s
@@ -0,0 +1,43 @@
+// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
+// RUN: | llvm-readobj -S --symbols - | FileCheck %s
+
+ .section .text,"axy",@progbits,unique,0
+ .globl foo
+ .p2align 2
+ .type foo,@function
+foo:
+ .cfi_startproc
+ ret
+.Lfunc_end0:
+ .size foo, .Lfunc_end0-foo
+ .cfi_endproc
+
+ .section ".note.GNU-stack","",@progbits
+
+
+// CHECK: Section {
+// CHECK: Name: .text
+// 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: Size: 0
+// CHECK: }
+
+// CHECK: Section {
+// CHECK: Name: .text
+// 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: Size: 2
+// CHECK: }
+
+// CHECK: Symbol {
+// CHECK: Name: foo
+// CHECK: Section: .text (0x3)
+// CHECK: }
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 000000000000000..22bcffae67d0eb2
--- /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 90c9185e8bfb108..b172403e34556ca 100644
--- a/llvm/test/MC/ELF/section-flags-unknown.s
+++ b/llvm/test/MC/ELF/section-flags-unknown.s
@@ -14,5 +14,8 @@
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
.section SHF_ARM_PURECODE,"y",@progbits
+# CHECK: {{.*}}.s:[[# @LINE+1]]:34: error: unknown flag
+.section SHF_AARCH64_PURECODE,"y",@progbits
+
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
.section SHF_X86_64_LARGE,"l",@progbits
diff --git a/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll b/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll
index 636f3c6600f8d4c..433a9c7bdd23b01 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/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index bfca65aad52b443..78aaf79a61c468e 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));
|
|
@llvm/pr-subscribers-llvm-transforms Author: Csanád Hajdú (Il-Capitano) ChangesAdd support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#304 The general implementation follows the existing one for ARM targets. Generating object files with the Full diff: https://github.com/llvm/llvm-project/pull/125687.diff 18 Files Affected:
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 8853c4a88b0b59..a5979d029a9eaf 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 3c2c7c8c9fed69..6cfebca9a4d576 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 b58210b3c268e9..99b13c68a9966c 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 25e62b70b5e2a0..72a959b1c92082 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 539834fc8d4dbf..05e4d85b2ea5d2 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 20db70ee38572f..7c95ba662938d9 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 8729fd4b802c8e..434ae32502d484 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 0c822ac84f200c..3e9cd51b742a29 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 a6edcf125782b2..284278e34f8b4d 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 b65e3c7a1ab20e..481cb5511a331b 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 6b5c5f36cbd4b2..d29d383bc23127 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 00000000000000..15a270b07975e6
--- /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",@progbits,unique,0
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_SectionForGlobal
+; CHECK: .type test_SectionForGlobal,@function
+define void @test_SectionForGlobal() {
+entry:
+ ret void
+}
+
+; CHECK: .section .test,"axy",@progbits
+; CHECK-NOT: .section
+; CHECK-NOT: .text
+; CHECK: .globl test_ExplicitSectionForGlobal
+; CHECK: .type test_ExplicitSectionForGlobal,@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 00000000000000..b0ba8a18d52b38
--- /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 00000000000000..6fd596376711d6
--- /dev/null
+++ b/llvm/test/MC/ELF/AArch64/execute-only-section.s
@@ -0,0 +1,43 @@
+// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
+// RUN: | llvm-readobj -S --symbols - | FileCheck %s
+
+ .section .text,"axy",@progbits,unique,0
+ .globl foo
+ .p2align 2
+ .type foo,@function
+foo:
+ .cfi_startproc
+ ret
+.Lfunc_end0:
+ .size foo, .Lfunc_end0-foo
+ .cfi_endproc
+
+ .section ".note.GNU-stack","",@progbits
+
+
+// CHECK: Section {
+// CHECK: Name: .text
+// 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: Size: 0
+// CHECK: }
+
+// CHECK: Section {
+// CHECK: Name: .text
+// 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: Size: 2
+// CHECK: }
+
+// CHECK: Symbol {
+// CHECK: Name: foo
+// CHECK: Section: .text (0x3)
+// CHECK: }
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 00000000000000..22bcffae67d0eb
--- /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 90c9185e8bfb10..b172403e34556c 100644
--- a/llvm/test/MC/ELF/section-flags-unknown.s
+++ b/llvm/test/MC/ELF/section-flags-unknown.s
@@ -14,5 +14,8 @@
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
.section SHF_ARM_PURECODE,"y",@progbits
+# CHECK: {{.*}}.s:[[# @LINE+1]]:34: error: unknown flag
+.section SHF_AARCH64_PURECODE,"y",@progbits
+
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
.section SHF_X86_64_LARGE,"l",@progbits
diff --git a/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll b/llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll
index 636f3c6600f8d4..433a9c7bdd23b0 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/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index bfca65aad52b44..78aaf79a61c468 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));
|
de215fd to
f528eb7
Compare
paulwalker-arm
left a comment
There was a problem hiding this comment.
Other than a minor formatting request the PR looks good to me, being consistent with the ARM/THUMB implementation.
That said, this is not my area so please given other reviewers (I'm tagging in @smithp35 who has more experience in this area) a day or so to chip in before merging the PR.
You can test this locally with the following command:git-clang-format --diff 83ff9d4a34b1e579dd809759d13b70b8837f0cde bcb5275221591da01303f6f2e368be4d3679ce0e --extensions h,cpp -- 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/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/tools/llvm-readobj/ELFDumper.cppView the diff from clang-format here.diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index a484a897b8..f569dcf2c6 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -1338,8 +1338,7 @@ const EnumEntry<unsigned> ElfXCoreSectionFlags[] = {
};
const EnumEntry<unsigned> ElfAArch64SectionFlags[] = {
- ENUM_ENT(SHF_AARCH64_PURECODE, "y")
-};
+ ENUM_ENT(SHF_AARCH64_PURECODE, "y")};
const EnumEntry<unsigned> ElfARMSectionFlags[] = {
ENUM_ENT(SHF_ARM_PURECODE, "y")
|
|
No objections from me. I've left a few small comments, but nothing significant. I've checked the implementation against the existing ARM backend. |
|
@smithp35 I can't see any comments made by you. Are you sure you saved/published them? |
Thanks for pointing it out. Looks like I've got a few pending. |
smithp35
left a comment
There was a problem hiding this comment.
Publish pending comments!
jh7370
left a comment
There was a problem hiding this comment.
Tool code and tests LGTM. I haven't reviewed other aspects.
I think this is ready to be merged. Do you have commit access?
|
Thanks for the review!
No, I don't. |
Okay, I'll give this a day before merging, to give other reviewers a final chance to look it over. |
…llvm#125687) Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#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: llvm#125688 * LLD: llvm#125689
…flag (3/3) (#125689) Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#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. Related PRs: * LLVM: #125687 * Clang: #125688
…LF section flag (3/3) (#125689) Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#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. Related PRs: * LLVM: llvm/llvm-project#125687 * Clang: llvm/llvm-project#125688
…llvm#125687) Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#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: llvm#125688 * LLD: llvm#125689
…g (2/3) (#125688) Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#304 The general implementation follows the existing one for ARM targets. Simlarly to ARM targets, generating object files with the `SHF_AARCH64_PURECODE` flag set is enabled by the `-mexecute-only`/`-mpure-code` driver flag. Related PRs: * LLVM: #125687 * LLD: #125689
…section flag (2/3) (#125688) Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#304 The general implementation follows the existing one for ARM targets. Simlarly to ARM targets, generating object files with the `SHF_AARCH64_PURECODE` flag set is enabled by the `-mexecute-only`/`-mpure-code` driver flag. Related PRs: * LLVM: llvm/llvm-project#125687 * LLD: llvm/llvm-project#125689
Support for execute-only code generation (llvm#125687) introduced a bug in the case where the memtag sanitizer is used in a module containing a mix of execute-only and non-execute-only functions. The bug is caused by using `return` instead of `break` to short-circuit a loop, which meant that the rest of the function dealing with memtag sanitizer logic wasn't run.
#133084) Support for execute-only code generation (#125687) introduced a bug in the case where the memtag sanitizer is used in a module containing a mix of execute-only and non-execute-only functions. The bug is caused by using `return` instead of `break` to short-circuit a loop, which meant that the rest of the function dealing with memtag sanitizer logic wasn't run.
…flag (3/3) (#125689) Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#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. Related PRs: * LLVM: llvm/llvm-project#125687 * Clang: llvm/llvm-project#125688
…g (2/3) (#125688) Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#304 The general implementation follows the existing one for ARM targets. Simlarly to ARM targets, generating object files with the `SHF_AARCH64_PURECODE` flag set is enabled by the `-mexecute-only`/`-mpure-code` driver flag. Related PRs: * LLVM: llvm/llvm-project#125687 * LLD: llvm/llvm-project#125689
Add support for the new SHF_AARCH64_PURECODE ELF section flag: ARM-software/abi-aa#304
The general implementation follows the existing one for ARM targets. Generating object files with the
SHF_AARCH64_PURECODEflag set is enabled by the+execute-onlytarget feature.Related PRs: