Skip to content

Commit a190f15

Browse files
authored
[AArch64] Add support for SHF_AARCH64_PURECODE ELF section flag (1/3) (#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: #125688 * LLD: #125689
1 parent be82705 commit a190f15

21 files changed

+333
-24
lines changed

llvm/include/llvm/BinaryFormat/ELF.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,8 +1299,11 @@ enum : unsigned {
12991299
// Section data is string data by default.
13001300
SHF_MIPS_STRING = 0x80000000,
13011301

1302-
// Make code section unreadable when in execute-only mode
1303-
SHF_ARM_PURECODE = 0x20000000
1302+
// Section contains only program instructions and no program data.
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: 10 additions & 6 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,8 +559,12 @@ static unsigned getELFSectionFlags(SectionKind K) {
559559
if (K.isText())
560560
Flags |= ELF::SHF_EXECINSTR;
561561

562-
if (K.isExecuteOnly())
563-
Flags |= ELF::SHF_ARM_PURECODE;
562+
if (K.isExecuteOnly()) {
563+
if (T.isAArch64())
564+
Flags |= ELF::SHF_AARCH64_PURECODE;
565+
else if (T.isARM() || T.isThumb())
566+
Flags |= ELF::SHF_ARM_PURECODE;
567+
}
564568

565569
if (K.isWriteable())
566570
Flags |= ELF::SHF_WRITE;
@@ -845,7 +849,7 @@ static MCSection *selectExplicitSectionGlobal(const GlobalObject *GO,
845849
// Infer section flags from the section name if we can.
846850
Kind = getELFKindForNamedSection(SectionName, Kind);
847851

848-
unsigned Flags = getELFSectionFlags(Kind);
852+
unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
849853
auto [Group, IsComdat, ExtraFlags] = getGlobalObjectInfo(GO, TM);
850854
Flags |= ExtraFlags;
851855

@@ -952,7 +956,7 @@ static MCSection *selectELFSectionForGlobal(
952956

953957
MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
954958
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
955-
unsigned Flags = getELFSectionFlags(Kind);
959+
unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
956960

957961
// If we have -ffunction-section or -fdata-section then we should emit the
958962
// global value to a uniqued section specifically for it.
@@ -972,7 +976,7 @@ MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
972976
MCSection *TargetLoweringObjectFileELF::getUniqueSectionForFunction(
973977
const Function &F, const TargetMachine &TM) const {
974978
SectionKind Kind = SectionKind::getText();
975-
unsigned Flags = getELFSectionFlags(Kind);
979+
unsigned Flags = getELFSectionFlags(Kind, TM.getTargetTriple());
976980
// If the function's section names is pre-determined via pragma or a
977981
// section attribute, call selectExplicitSectionGlobal.
978982
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: 17 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,19 @@ 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 a "+execute-only" callee can be inlined into a caller without
299+
// "+execute-only", but not vice versa.
300+
FeatureBitset EffectiveCallerBits = CallerBits ^ InlineInverseFeatures;
301+
FeatureBitset EffectiveCalleeBits = CalleeBits ^ InlineInverseFeatures;
302+
303+
return (EffectiveCallerBits & EffectiveCalleeBits) == EffectiveCalleeBits;
288304
}
289305

290306
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: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; RUN: llc -mtriple=aarch64 -mattr=+execute-only %s -o - | FileCheck %s
2+
3+
$test_comdat = comdat any
4+
5+
; CHECK: .section .text,"axy",@progbits,unique,0
6+
; CHECK-NOT: .section
7+
; CHECK-NOT: .text
8+
; CHECK: .globl test_section_for_global
9+
; CHECK: .type test_section_for_global,@function
10+
define void @test_section_for_global() {
11+
entry:
12+
ret void
13+
}
14+
15+
; CHECK: .section .text.test_comdat,"axGy",@progbits,test_comdat,comdat,unique,0
16+
; CHECK-NOT: .section
17+
; CHECK-NOT: .text
18+
; CHECK: .weak test_comdat
19+
; CHECK: .type test_comdat,@function
20+
define linkonce_odr void @test_comdat() comdat {
21+
entry:
22+
ret void
23+
}
24+
25+
; CHECK: .section .test,"axy",@progbits
26+
; CHECK-NOT: .section
27+
; CHECK-NOT: .text
28+
; CHECK: .globl test_explicit_section_for_global
29+
; CHECK: .type test_explicit_section_for_global,@function
30+
define void @test_explicit_section_for_global() section ".test" {
31+
entry:
32+
ret void
33+
}
34+
35+
; CHECK: .rodata,"a",@progbits
36+
; CHECK-NOT: .section
37+
; CHECK-NOT: .text
38+
; CHECK: .globl test_rodata
39+
@test_rodata = constant i32 0, align 4
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: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
2+
// RUN: | llvm-readobj -S --symbols - | FileCheck %s --check-prefix=READOBJ
3+
// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-linux-gnu %s -o - \
4+
// RUN: | llvm-readelf -S --symbols - | FileCheck %s --check-prefix=READELF
5+
6+
.section .text,"axy",@progbits,unique,0
7+
.globl foo
8+
.p2align 2
9+
.type foo,@function
10+
foo:
11+
.cfi_startproc
12+
ret
13+
.Lfunc_end0:
14+
.size foo, .Lfunc_end0-foo
15+
.cfi_endproc
16+
17+
// READOBJ: Section {
18+
// READOBJ: Name: .text
19+
// READOBJ-NEXT: Type: SHT_PROGBITS (0x1)
20+
// READOBJ-NEXT: Flags [ (0x20000006)
21+
// READOBJ-NEXT: SHF_AARCH64_PURECODE (0x20000000)
22+
// READOBJ-NEXT: SHF_ALLOC (0x2)
23+
// READOBJ-NEXT: SHF_EXECINSTR (0x4)
24+
// READOBJ-NEXT: ]
25+
// READOBJ-NEXT: Address:
26+
// READOBJ-NEXT: Offset:
27+
// READOBJ-NEXT: Size: 0
28+
// READOBJ: }
29+
30+
// READOBJ: Section {
31+
// READOBJ: Name: .text
32+
// READOBJ-NEXT: Type: SHT_PROGBITS (0x1)
33+
// READOBJ-NEXT: Flags [ (0x20000006)
34+
// READOBJ-NEXT: SHF_AARCH64_PURECODE (0x20000000)
35+
// READOBJ-NEXT: SHF_ALLOC (0x2)
36+
// READOBJ-NEXT: SHF_EXECINSTR (0x4)
37+
// READOBJ-NEXT: ]
38+
// READOBJ-NEXT: Address:
39+
// READOBJ-NEXT: Offset:
40+
// READOBJ-NEXT: Size: 4
41+
// READOBJ: }
42+
43+
// READOBJ: Symbol {
44+
// READOBJ: Name: foo
45+
// READOBJ-NEXT: Value:
46+
// READOBJ-NEXT: Size: 4
47+
// READOBJ-NEXT: Binding: Global
48+
// READOBJ-NEXT: Type: Function
49+
// READOBJ-NEXT: Other:
50+
// READOBJ-NEXT: Section: .text
51+
// READOBJ: }
52+
53+
// READELF: Section Headers:
54+
// READELF: .text PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} 000000 {{[0-9a-f]+}} AXy {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
55+
// READELF: .text PROGBITS {{[0-9a-f]+}} {{[0-9a-f]+}} 000004 {{[0-9a-f]+}} AXy {{[0-9]+}} {{[0-9]+}} {{[0-9]+}}
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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
# CHECK: {{.*}}.s:[[# @LINE+1]]:27: error: unknown flag
1212
.section SHF_HEX_GPREL,"s",@progbits
1313

14-
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
15-
.section SHF_ARM_PURECODE,"y",@progbits
14+
## Test SHF_ARM_PURECODE and SHF_AARCH64_PURECODE section flags
15+
# CHECK: {{.*}}.s:[[# @LINE+1]]:22: error: unknown flag
16+
.section purecode,"y",@progbits
1617

1718
# CHECK: {{.*}}.s:[[# @LINE+1]]:30: error: unknown flag
1819
.section SHF_X86_64_LARGE,"l",@progbits

0 commit comments

Comments
 (0)