Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion llvm/include/llvm/BinaryFormat/ELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 8 additions & 5 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand All @@ -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())
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/MC/MCParser/ELFAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/MC/MCSectionELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/ObjectYAML/ELFYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/AArch64/AArch64Features.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down
26 changes: 26 additions & 0 deletions llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
6 changes: 6 additions & 0 deletions llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
17 changes: 16 additions & 1 deletion llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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(
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
39 changes: 39 additions & 0 deletions llvm/test/CodeGen/AArch64/execute-only-section.ll
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions llvm/test/MC/ELF/AArch64/execute-only-populated-text-section.s
Original file line number Diff line number Diff line change
@@ -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: }
55 changes: 55 additions & 0 deletions llvm/test/MC/ELF/AArch64/execute-only-section.s
Original file line number Diff line number Diff line change
@@ -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]+}}
27 changes: 27 additions & 0 deletions llvm/test/MC/ELF/AArch64/execute-only-text-section-data.s
Original file line number Diff line number Diff line change
@@ -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: }
5 changes: 3 additions & 2 deletions llvm/test/MC/ELF/section-flags-unknown.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading