diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 8853c4a88b0b5..d4c3c21078ea6 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 3c2c7c8c9fed6..ea5df42ccc7d9 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; @@ -840,7 +844,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 +951,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 +971,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::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 20db70ee38572..7c95ba662938d 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(GO)) + if (TM.getSubtarget(*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 a6edcf125782b..cb566c773a064 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 { 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(Sec).getFlags() & ELF::SHF_AARCH64_PURECODE; + })) { + auto *Text = + static_cast(Ctx.getObjectFileInfo()->getTextSection()); + for (auto &F : *Text) + if (auto *DF = dyn_cast(&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(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",@progbits,unique,0 +; CHECK-NOT: .section +; CHECK-NOT: .text +; CHECK: .globl test_section_for_global +; CHECK: .type test_section_for_global,@function +define void @test_section_for_global() { +entry: + ret void +} + +; CHECK: .section .text.test_comdat,"axGy",@progbits,test_comdat,comdat,unique,0 +; CHECK-NOT: .section +; CHECK-NOT: .text +; CHECK: .weak test_comdat +; CHECK: .type test_comdat,@function +define linkonce_odr void @test_comdat() comdat { +entry: + ret void +} + +; CHECK: .section .test,"axy",@progbits +; CHECK-NOT: .section +; CHECK-NOT: .text +; CHECK: .globl test_explicit_section_for_global +; CHECK: .type test_explicit_section_for_global,@function +define void @test_explicit_section_for_global() section ".test" { +entry: + ret void +} + +; CHECK: .rodata,"a",@progbits +; CHECK-NOT: .section +; CHECK-NOT: .text +; CHECK: .globl test_rodata +@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",@progbits,unique,0 + .globl foo + .p2align 2 + .type foo,@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",@progbits -# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag -.section SHF_ARM_PURECODE,"y",@progbits +## Test SHF_ARM_PURECODE and SHF_AARCH64_PURECODE section flags +# CHECK: {{.*}}.s:[[# @LINE+1]]:22: error: unknown flag +.section 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 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 bfca65aad52b4..a484a897b8df4 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1337,6 +1337,10 @@ const EnumEntry ElfXCoreSectionFlags[] = { ENUM_ENT(XCORE_SHF_DP_SECTION, "") }; +const EnumEntry ElfAArch64SectionFlags[] = { + ENUM_ENT(SHF_AARCH64_PURECODE, "y") +}; + const EnumEntry 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";