Skip to content

Commit 6ff1cc4

Browse files
committed
[AArch64] Add support for SHF_AARCH64_PURECODE ELF section flag (1/3)
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.
1 parent 83ff9d4 commit 6ff1cc4

18 files changed

+250
-9
lines changed

llvm/include/llvm/BinaryFormat/ELF.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,10 @@ enum : unsigned {
13001300
SHF_MIPS_STRING = 0x80000000,
13011301

13021302
// Make code section unreadable when in execute-only mode
1303-
SHF_ARM_PURECODE = 0x20000000
1303+
SHF_ARM_PURECODE = 0x20000000,
1304+
1305+
// Section contains only program instructions and no program data.
1306+
SHF_AARCH64_PURECODE = 0x20000000
13041307
};
13051308

13061309
// Section Group Flags

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ static unsigned getELFSectionType(StringRef Name, SectionKind K) {
547547
return ELF::SHT_PROGBITS;
548548
}
549549

550-
static unsigned getELFSectionFlags(SectionKind K) {
550+
static unsigned getELFSectionFlags(SectionKind K, const Triple &T) {
551551
unsigned Flags = 0;
552552

553553
if (!K.isMetadata() && !K.isExclude())
@@ -559,9 +559,12 @@ static unsigned getELFSectionFlags(SectionKind K) {
559559
if (K.isText())
560560
Flags |= ELF::SHF_EXECINSTR;
561561

562-
if (K.isExecuteOnly())
562+
if ((T.isARM() || T.isThumb()) && K.isExecuteOnly())
563563
Flags |= ELF::SHF_ARM_PURECODE;
564564

565+
if (T.isAArch64() && K.isExecuteOnly())
566+
Flags |= ELF::SHF_AARCH64_PURECODE;
567+
565568
if (K.isWriteable())
566569
Flags |= ELF::SHF_WRITE;
567570

@@ -840,7 +843,7 @@ static MCSection *selectExplicitSectionGlobal(const GlobalObject *GO,
840843
// Infer section flags from the section name if we can.
841844
Kind = getELFKindForNamedSection(SectionName, Kind);
842845

843-
unsigned Flags = getELFSectionFlags(Kind);
846+
unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
844847
auto [Group, IsComdat, ExtraFlags] = getGlobalObjectInfo(GO, TM);
845848
Flags |= ExtraFlags;
846849

@@ -947,7 +950,7 @@ static MCSection *selectELFSectionForGlobal(
947950

948951
MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
949952
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
950-
unsigned Flags = getELFSectionFlags(Kind);
953+
unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
951954

952955
// If we have -ffunction-section or -fdata-section then we should emit the
953956
// global value to a uniqued section specifically for it.
@@ -967,7 +970,7 @@ MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
967970
MCSection *TargetLoweringObjectFileELF::getUniqueSectionForFunction(
968971
const Function &F, const TargetMachine &TM) const {
969972
SectionKind Kind = SectionKind::getText();
970-
unsigned Flags = getELFSectionFlags(Kind);
973+
unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
971974
// If the function's section names is pre-determined via pragma or a
972975
// section attribute, call selectExplicitSectionGlobal.
973976
if (F.hasSection())

llvm/lib/MC/MCParser/ELFAsmParser.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,12 @@ static unsigned parseSectionFlags(const Triple &TT, StringRef flagsStr,
328328
flags |= ELF::XCORE_SHF_DP_SECTION;
329329
break;
330330
case 'y':
331-
if (!(TT.isARM() || TT.isThumb()))
331+
if (TT.isARM() || TT.isThumb())
332+
flags |= ELF::SHF_ARM_PURECODE;
333+
else if (TT.isAArch64())
334+
flags |= ELF::SHF_AARCH64_PURECODE;
335+
else
332336
return -1U;
333-
flags |= ELF::SHF_ARM_PURECODE;
334337
break;
335338
case 's':
336339
if (TT.getArch() != Triple::hexagon)

llvm/lib/MC/MCSectionELF.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ void MCSectionELF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
118118
} else if (T.isARM() || T.isThumb()) {
119119
if (Flags & ELF::SHF_ARM_PURECODE)
120120
OS << 'y';
121+
} else if (T.isAArch64()) {
122+
if (Flags & ELF::SHF_AARCH64_PURECODE)
123+
OS << 'y';
121124
} else if (Arch == Triple::hexagon) {
122125
if (Flags & ELF::SHF_HEX_GPREL)
123126
OS << 's';

llvm/lib/ObjectYAML/ELFYAML.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,9 @@ void ScalarBitSetTraits<ELFYAML::ELF_SHF>::bitset(IO &IO,
803803
break;
804804
}
805805
switch (Object->getMachine()) {
806+
case ELF::EM_AARCH64:
807+
BCase(SHF_AARCH64_PURECODE);
808+
break;
806809
case ELF::EM_ARM:
807810
BCase(SHF_ARM_PURECODE);
808811
break;

llvm/lib/Target/AArch64/AArch64Features.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,11 @@ def FeatureStrictAlign : SubtargetFeature<"strict-align",
635635
"Disallow all unaligned memory "
636636
"access">;
637637

638+
def FeatureExecuteOnly : SubtargetFeature<"execute-only",
639+
"GenExecuteOnly", "true",
640+
"Enable the generation of "
641+
"execute only code.">;
642+
638643
foreach i = {1-7,9-15,18,20-28} in
639644
def FeatureReserveX#i : SubtargetFeature<"reserve-x"#i, "ReserveXRegister["#i#"]", "true",
640645
"Reserve X"#i#", making it unavailable "

llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,29 @@ MCSymbol *AArch64_MachoTargetObjectFile::getAuthPtrSlotSymbol(
148148
return getAuthPtrSlotSymbolHelper(getContext(), TM, MMI, MachOMMI, RawSym,
149149
Key, Discriminator);
150150
}
151+
152+
static bool isExecuteOnlyFunction(const GlobalObject *GO, SectionKind Kind,
153+
const TargetMachine &TM) {
154+
if (const Function *F = dyn_cast<Function>(GO))
155+
if (TM.getSubtarget<AArch64Subtarget>(*F).genExecuteOnly() && Kind.isText())
156+
return true;
157+
return false;
158+
}
159+
160+
MCSection *AArch64_ELFTargetObjectFile::getExplicitSectionGlobal(
161+
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
162+
// Set execute-only access for the explicit section
163+
if (isExecuteOnlyFunction(GO, Kind, TM))
164+
Kind = SectionKind::getExecuteOnly();
165+
166+
return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, Kind, TM);
167+
}
168+
169+
MCSection *AArch64_ELFTargetObjectFile::SelectSectionForGlobal(
170+
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
171+
// Set execute-only access for the explicit section
172+
if (isExecuteOnlyFunction(GO, Kind, TM))
173+
Kind = SectionKind::getExecuteOnly();
174+
175+
return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM);
176+
}

llvm/lib/Target/AArch64/AArch64TargetObjectFile.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class AArch64_ELFTargetObjectFile : public TargetLoweringObjectFileELF {
3939
void emitPersonalityValueImpl(MCStreamer &Streamer, const DataLayout &DL,
4040
const MCSymbol *Sym,
4141
const MachineModuleInfo *MMI) const override;
42+
43+
MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
44+
const TargetMachine &TM) const override;
45+
46+
MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
47+
const TargetMachine &TM) const override;
4248
};
4349

4450
/// AArch64_MachoTargetObjectFile - This TLOF implementation is used for Darwin.

llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ bool AArch64TTIImpl::isMultiversionedFunction(const Function &F) const {
262262
return F.hasFnAttribute("fmv-features");
263263
}
264264

265+
const FeatureBitset AArch64TTIImpl::InlineInverseFeatures = {
266+
AArch64::FeatureExecuteOnly,
267+
};
268+
265269
bool AArch64TTIImpl::areInlineCompatible(const Function *Caller,
266270
const Function *Callee) const {
267271
SMEAttrs CallerAttrs(*Caller), CalleeAttrs(*Callee);
@@ -284,7 +288,18 @@ bool AArch64TTIImpl::areInlineCompatible(const Function *Caller,
284288
return false;
285289
}
286290

287-
return BaseT::areInlineCompatible(Caller, Callee);
291+
const TargetMachine &TM = getTLI()->getTargetMachine();
292+
const FeatureBitset &CallerBits =
293+
TM.getSubtargetImpl(*Caller)->getFeatureBits();
294+
const FeatureBitset &CalleeBits =
295+
TM.getSubtargetImpl(*Callee)->getFeatureBits();
296+
// Adjust the feature bitsets by inverting some of the bits. This is needed
297+
// for target features that represent restrictions rather than capabilities,
298+
// for example "+execute-only".
299+
FeatureBitset EffectiveCallerBits = CallerBits ^ InlineInverseFeatures;
300+
FeatureBitset EffectiveCalleeBits = CalleeBits ^ InlineInverseFeatures;
301+
302+
return (EffectiveCallerBits & EffectiveCalleeBits) == EffectiveCalleeBits;
288303
}
289304

290305
bool AArch64TTIImpl::areTypesABICompatible(

llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class AArch64TTIImpl : public BasicTTIImplBase<AArch64TTIImpl> {
4848
const AArch64Subtarget *ST;
4949
const AArch64TargetLowering *TLI;
5050

51+
static const FeatureBitset InlineInverseFeatures;
52+
5153
const AArch64Subtarget *getST() const { return ST; }
5254
const AArch64TargetLowering *getTLI() const { return TLI; }
5355

llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "llvm/MC/MCELFStreamer.h"
2828
#include "llvm/MC/MCExpr.h"
2929
#include "llvm/MC/MCInst.h"
30+
#include "llvm/MC/MCObjectFileInfo.h"
3031
#include "llvm/MC/MCSectionELF.h"
3132
#include "llvm/MC/MCStreamer.h"
3233
#include "llvm/MC/MCSubtargetInfo.h"
@@ -504,6 +505,23 @@ void AArch64TargetELFStreamer::finish() {
504505
}
505506
}
506507

508+
// The mix of execute-only and non-execute-only at link time is
509+
// non-execute-only. To avoid the empty implicitly created .text
510+
// section from making the whole .text section non-execute-only, we
511+
// mark it execute-only if it is empty and there is at least one
512+
// execute-only section in the object.
513+
if (any_of(Asm, [](const MCSection &Sec) {
514+
return cast<MCSectionELF>(Sec).getFlags() & ELF::SHF_AARCH64_PURECODE;
515+
})) {
516+
auto *Text =
517+
static_cast<MCSectionELF *>(Ctx.getObjectFileInfo()->getTextSection());
518+
for (auto &F : *Text)
519+
if (auto *DF = dyn_cast<MCDataFragment>(&F))
520+
if (!DF->getContents().empty())
521+
return;
522+
Text->setFlags(Text->getFlags() | ELF::SHF_AARCH64_PURECODE);
523+
}
524+
507525
MCSectionELF *MemtagSec = nullptr;
508526
for (const MCSymbol &Symbol : Asm.symbols()) {
509527
const auto &Sym = cast<MCSymbolELF>(Symbol);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; RUN: llc -mtriple=aarch64 -mattr=+execute-only %s -o - | FileCheck %s
2+
3+
; CHECK: .section .text,"axy",@progbits,unique,0
4+
; CHECK-NOT: .section
5+
; CHECK-NOT: .text
6+
; CHECK: .globl test_SectionForGlobal
7+
; CHECK: .type test_SectionForGlobal,@function
8+
define void @test_SectionForGlobal() {
9+
entry:
10+
ret void
11+
}
12+
13+
; CHECK: .section .test,"axy",@progbits
14+
; CHECK-NOT: .section
15+
; CHECK-NOT: .text
16+
; CHECK: .globl test_ExplicitSectionForGlobal
17+
; CHECK: .type test_ExplicitSectionForGlobal,@function
18+
define void @test_ExplicitSectionForGlobal() section ".test" {
19+
entry:
20+
ret void
21+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
2+
// RUN: | llvm-readobj -S --symbols - | FileCheck %s
3+
4+
.text
5+
ret
6+
7+
.section .text.foo,"axy"
8+
ret
9+
10+
// CHECK: Section {
11+
// CHECK: Name: .text
12+
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
13+
// CHECK-NEXT: Flags [ (0x6)
14+
// CHECK-NEXT: SHF_ALLOC (0x2)
15+
// CHECK-NEXT: SHF_EXECINSTR (0x4)
16+
// CHECK-NEXT: ]
17+
// CHECK: }
18+
19+
// CHECK: Section {
20+
// CHECK: Name: .text.foo
21+
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
22+
// CHECK-NEXT: Flags [ (0x20000006)
23+
// CHECK-NEXT: SHF_AARCH64_PURECODE (0x20000000)
24+
// CHECK-NEXT: SHF_ALLOC (0x2)
25+
// CHECK-NEXT: SHF_EXECINSTR (0x4)
26+
// CHECK-NEXT: ]
27+
// CHECK: }
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
2+
// RUN: | llvm-readobj -S --symbols - | FileCheck %s
3+
4+
.section .text,"axy",@progbits,unique,0
5+
.globl foo
6+
.p2align 2
7+
.type foo,@function
8+
foo:
9+
.cfi_startproc
10+
ret
11+
.Lfunc_end0:
12+
.size foo, .Lfunc_end0-foo
13+
.cfi_endproc
14+
15+
.section ".note.GNU-stack","",@progbits
16+
17+
18+
// CHECK: Section {
19+
// CHECK: Name: .text
20+
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
21+
// CHECK-NEXT: Flags [ (0x20000006)
22+
// CHECK-NEXT: SHF_AARCH64_PURECODE (0x20000000)
23+
// CHECK-NEXT: SHF_ALLOC (0x2)
24+
// CHECK-NEXT: SHF_EXECINSTR (0x4)
25+
// CHECK-NEXT: ]
26+
// CHECK: Size: 0
27+
// CHECK: }
28+
29+
// CHECK: Section {
30+
// CHECK: Name: .text
31+
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
32+
// CHECK-NEXT: Flags [ (0x20000006)
33+
// CHECK-NEXT: SHF_AARCH64_PURECODE (0x20000000)
34+
// CHECK-NEXT: SHF_ALLOC (0x2)
35+
// CHECK-NEXT: SHF_EXECINSTR (0x4)
36+
// CHECK-NEXT: ]
37+
// CHECK: Size: 2
38+
// CHECK: }
39+
40+
// CHECK: Symbol {
41+
// CHECK: Name: foo
42+
// CHECK: Section: .text (0x3)
43+
// CHECK: }
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
2+
// RUN: | llvm-readobj -S --symbols - | FileCheck %s
3+
4+
.text
5+
.ascii "test"
6+
7+
.section .text.foo,"axy"
8+
ret
9+
10+
// CHECK: Section {
11+
// CHECK: Name: .text
12+
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
13+
// CHECK-NEXT: Flags [ (0x6)
14+
// CHECK-NEXT: SHF_ALLOC (0x2)
15+
// CHECK-NEXT: SHF_EXECINSTR (0x4)
16+
// CHECK-NEXT: ]
17+
// CHECK: }
18+
19+
// CHECK: Section {
20+
// CHECK: Name: .text.foo
21+
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
22+
// CHECK-NEXT: Flags [ (0x20000006)
23+
// CHECK-NEXT: SHF_AARCH64_PURECODE (0x20000000)
24+
// CHECK-NEXT: SHF_ALLOC (0x2)
25+
// CHECK-NEXT: SHF_EXECINSTR (0x4)
26+
// CHECK-NEXT: ]
27+
// CHECK: }

llvm/test/MC/ELF/section-flags-unknown.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,8 @@
1414
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
1515
.section SHF_ARM_PURECODE,"y",@progbits
1616

17+
# CHECK: {{.*}}.s:[[# @LINE+1]]:34: error: unknown flag
18+
.section SHF_AARCH64_PURECODE,"y",@progbits
19+
1720
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
1821
.section SHF_X86_64_LARGE,"l",@progbits

llvm/test/Transforms/Inline/AArch64/inline-target-attr.ll

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ entry:
2727
; CHECK: call i32 @bar()
2828
}
2929

30+
define i32 @quux() #3 {
31+
entry:
32+
%call = call i32 (...) @baz()
33+
ret i32 %call
34+
; CHECK-LABEL: quux
35+
; CHECK: call i32 (...) @baz()
36+
}
37+
3038
define i32 @strict_align() #2 {
3139
entry:
3240
%call = call i32 @foo()
@@ -35,6 +43,23 @@ entry:
3543
; CHECK: call i32 (...) @baz()
3644
}
3745

46+
define i32 @execute_only1() #3 {
47+
entry:
48+
%call = call i32 @foo()
49+
ret i32 %call
50+
; CHECK-LABEL: execute_only1
51+
; CHECK: call i32 @foo()
52+
}
53+
54+
define i32 @execute_only2() #0 {
55+
entry:
56+
%call = call i32 @quux()
57+
ret i32 %call
58+
; CHECK-LABEL: execute_only2
59+
; CHECK: call i32 (...) @baz()
60+
}
61+
3862
attributes #0 = { "target-cpu"="generic" "target-features"="+crc,+neon" }
3963
attributes #1 = { "target-cpu"="generic" "target-features"="+crc,+neon,+crypto" }
4064
attributes #2 = { "target-cpu"="generic" "target-features"="+crc,+neon,+strict-align" }
65+
attributes #3 = { "target-cpu"="generic" "target-features"="+crc,+neon,+execute-only" }

0 commit comments

Comments
 (0)