Skip to content

Commit 6e457c2

Browse files
authored
[LLD][ELF][AArch64] Add support for SHF_AARCH64_PURECODE ELF 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: #125687 * Clang: #125688
1 parent cf50936 commit 6e457c2

7 files changed

+187
-6
lines changed

lld/ELF/OutputSections.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ using namespace lld::elf;
4242

4343
uint32_t OutputSection::getPhdrFlags() const {
4444
uint32_t ret = 0;
45-
if (ctx.arg.emachine != EM_ARM || !(flags & SHF_ARM_PURECODE))
45+
bool purecode =
46+
(ctx.arg.emachine == EM_ARM && (flags & SHF_ARM_PURECODE)) ||
47+
(ctx.arg.emachine == EM_AARCH64 && (flags & SHF_AARCH64_PURECODE));
48+
if (!purecode)
4649
ret |= PF_R;
4750
if (flags & SHF_WRITE)
4851
ret |= PF_W;
@@ -161,8 +164,11 @@ void OutputSection::commitSection(InputSection *isec) {
161164
}
162165

163166
isec->parent = this;
164-
uint64_t andMask =
165-
ctx.arg.emachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0;
167+
uint64_t andMask = 0;
168+
if (ctx.arg.emachine == EM_ARM)
169+
andMask |= (uint64_t)SHF_ARM_PURECODE;
170+
if (ctx.arg.emachine == EM_AARCH64)
171+
andMask |= (uint64_t)SHF_AARCH64_PURECODE;
166172
uint64_t orMask = ~andMask;
167173
uint64_t andFlags = (flags & isec->flags) & andMask;
168174
uint64_t orFlags = (flags | isec->flags) & orMask;

lld/ELF/ScriptParser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,7 @@ static std::optional<uint64_t> parseFlag(StringRef tok) {
14111411
.Case(CASE_ENT(SHF_COMPRESSED))
14121412
.Case(CASE_ENT(SHF_EXCLUDE))
14131413
.Case(CASE_ENT(SHF_ARM_PURECODE))
1414+
.Case(CASE_ENT(SHF_AARCH64_PURECODE))
14141415
.Default(std::nullopt);
14151416
#undef CASE_ENT
14161417
}

lld/ELF/Thunks.cpp

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ class AArch64ABSLongThunk final : public AArch64Thunk {
9191
ThunkSection *tsec = nullptr;
9292
};
9393

94+
// AArch64 long range Thunks compatible with execute-only code.
95+
class AArch64ABSXOLongThunk final : public AArch64Thunk {
96+
public:
97+
AArch64ABSXOLongThunk(Ctx &ctx, Symbol &dest, int64_t addend,
98+
bool mayNeedLandingPad)
99+
: AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
100+
uint32_t size() override { return getMayUseShortThunk() ? 4 : 20; }
101+
void addSymbols(ThunkSection &sec) override;
102+
103+
private:
104+
void writeLong(uint8_t *buf) override;
105+
};
106+
94107
class AArch64ADRPThunk final : public AArch64Thunk {
95108
public:
96109
AArch64ADRPThunk(Ctx &ctx, Symbol &dest, int64_t addend,
@@ -663,6 +676,33 @@ void AArch64ABSLongThunk::addLongMapSyms() {
663676
addSymbol("$d", STT_NOTYPE, 8, *tsec);
664677
}
665678

679+
void AArch64ABSXOLongThunk::writeLong(uint8_t *buf) {
680+
const uint8_t data[] = {
681+
0x10, 0x00, 0x80, 0xd2, // movz x16, :abs_g0_nc:S, lsl #0
682+
0x10, 0x00, 0xa0, 0xf2, // movk x16, :abs_g1_nc:S, lsl #16
683+
0x10, 0x00, 0xc0, 0xf2, // movk x16, :abs_g2_nc:S, lsl #32
684+
0x10, 0x00, 0xe0, 0xf2, // movk x16, :abs_g3:S, lsl #48
685+
0x00, 0x02, 0x1f, 0xd6, // br x16
686+
};
687+
// If mayNeedLandingPad is true then destination is an
688+
// AArch64BTILandingPadThunk that defines landingPad.
689+
assert(!mayNeedLandingPad || landingPad != nullptr);
690+
uint64_t s = mayNeedLandingPad
691+
? landingPad->getVA(ctx, 0)
692+
: getAArch64ThunkDestVA(ctx, destination, addend);
693+
memcpy(buf, data, sizeof(data));
694+
ctx.target->relocateNoSym(buf + 0, R_AARCH64_MOVW_UABS_G0_NC, s);
695+
ctx.target->relocateNoSym(buf + 4, R_AARCH64_MOVW_UABS_G1_NC, s);
696+
ctx.target->relocateNoSym(buf + 8, R_AARCH64_MOVW_UABS_G2_NC, s);
697+
ctx.target->relocateNoSym(buf + 12, R_AARCH64_MOVW_UABS_G3, s);
698+
}
699+
700+
void AArch64ABSXOLongThunk::addSymbols(ThunkSection &sec) {
701+
addSymbol(ctx.saver.save("__AArch64AbsXOLongThunk_" + destination.getName()),
702+
STT_FUNC, 0, sec);
703+
addSymbol("$x", STT_NOTYPE, 0, sec);
704+
}
705+
666706
// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
667707
// using the small code model, including pc-relative ones. At time of writing
668708
// clang and gcc do not support the large code model for position independent
@@ -1482,7 +1522,8 @@ Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
14821522

14831523
Thunk::~Thunk() = default;
14841524

1485-
static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, RelType type, Symbol &s,
1525+
static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, const InputSection &sec,
1526+
RelType type, Symbol &s,
14861527
int64_t a) {
14871528
assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
14881529
type));
@@ -1491,6 +1532,9 @@ static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, RelType type, Symbol &s,
14911532
!isAArch64BTILandingPad(ctx, s, a);
14921533
if (ctx.arg.picThunk)
14931534
return std::make_unique<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad);
1535+
if (sec.getParent()->flags & SHF_AARCH64_PURECODE)
1536+
return std::make_unique<AArch64ABSXOLongThunk>(ctx, s, a,
1537+
mayNeedLandingPad);
14941538
return std::make_unique<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad);
14951539
}
14961540

@@ -1702,7 +1746,7 @@ std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
17021746

17031747
switch (ctx.arg.emachine) {
17041748
case EM_AARCH64:
1705-
return addThunkAArch64(ctx, rel.type, s, a);
1749+
return addThunkAArch64(ctx, isec, rel.type, s, a);
17061750
case EM_ARM:
17071751
return addThunkArm(ctx, isec, rel.type, s, a);
17081752
case EM_AVR:

lld/test/ELF/aarch64-execute-only.s

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// REQUIRES: aarch64
2+
3+
// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
4+
// RUN: ld.lld %t.o -o %t.so -shared
5+
// RUN: llvm-readelf -l %t.so | FileCheck --implicit-check-not=LOAD %s
6+
7+
// RUN: echo ".section .foo,\"ax\"; ret" > %t.s
8+
// RUN: llvm-mc -filetype=obj -triple=aarch64 %t.s -o %t2.o
9+
// RUN: ld.lld %t.o %t2.o -o %t.so -shared
10+
// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF --implicit-check-not=LOAD %s
11+
12+
// CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x10000
13+
// CHECK-NEXT: LOAD 0x000248 0x0000000000010248 0x0000000000010248 0x{{.*}} 0x{{.*}} R E 0x10000
14+
// CHECK-NEXT: LOAD 0x00024c 0x000000000002024c 0x000000000002024c 0x{{.*}} 0x{{.*}} E 0x10000
15+
// CHECK-NEXT: LOAD 0x000250 0x0000000000030250 0x0000000000030250 0x000070 0x000db0 RW 0x10000
16+
17+
// CHECK: 01 .dynsym .gnu.hash .hash .dynstr
18+
// CHECK-NEXT: 02 .text
19+
// CHECK-NEXT: 03 .foo
20+
// CHECK-NEXT: 04 .dynamic
21+
22+
// DIFF: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00020d 0x00020d R 0x10000
23+
// DIFF-NEXT: LOAD 0x000210 0x0000000000010210 0x0000000000010210 0x00000c 0x00000c R E 0x10000
24+
// DIFF-NEXT: LOAD 0x000220 0x0000000000020220 0x0000000000020220 0x000070 0x000de0 RW 0x10000
25+
26+
// DIFF: 01 .dynsym .gnu.hash .hash .dynstr
27+
// DIFF-NEXT: 02 .text .foo
28+
// DIFF-NEXT: 03 .dynamic
29+
30+
ret
31+
.section .foo,"axy"
32+
ret
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// REQUIRES: aarch64
2+
// RUN: rm -rf %t && split-file %s %t && cd %t
3+
// RUN: llvm-mc -filetype=obj -triple=aarch64 asm -o a.o
4+
// RUN: ld.lld --script=lds a.o -o exe --defsym absolute=0xf0000000
5+
// RUN: llvm-objdump -d --no-show-raw-insn exe | FileCheck %s
6+
7+
//--- asm
8+
.section ".note.gnu.property", "a"
9+
.p2align 3
10+
.long 4
11+
.long 0x10
12+
.long 0x5
13+
.asciz "GNU"
14+
15+
/// Enable BTI.
16+
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND.
17+
.long 4
18+
.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI.
19+
.long 0
20+
21+
.section .text.0,"axy",@progbits
22+
.global _start
23+
.type _start,@function
24+
_start:
25+
/// Expect thunk to target a linker generated entry point with BTI landing pad.
26+
/// Two calls to make sure only one landing pad is created.
27+
bl fn1
28+
b fn1
29+
/// No BTI landing pad is added for absolute symbols.
30+
bl absolute
31+
32+
/// This function does not have a BTI compatible landing pad. Expect a linker
33+
/// generated landing pad for indirect branch thunks.
34+
.section .text.1,"axy",@progbits
35+
.hidden fn1
36+
.type fn1,@function
37+
fn1:
38+
ret
39+
40+
// CHECK-LABEL: <_start>:
41+
// CHECK-NEXT: 18001000: bl 0x1800100c <__AArch64AbsXOLongThunk_>
42+
// CHECK-NEXT: b 0x1800100c <__AArch64AbsXOLongThunk_>
43+
// CHECK-NEXT: bl 0x18001020 <__AArch64AbsXOLongThunk_absolute>
44+
45+
// CHECK-LABEL: <__AArch64AbsXOLongThunk_>:
46+
// CHECK-NEXT: 1800100c: mov x16, #0x0
47+
// CHECK-NEXT: movk x16, #0x3000, lsl #16
48+
// CHECK-NEXT: movk x16, #0x0, lsl #32
49+
// CHECK-NEXT: movk x16, #0x0, lsl #48
50+
// CHECK-NEXT: br x16
51+
52+
// CHECK-LABEL: <__AArch64AbsXOLongThunk_absolute>:
53+
// CHECK-NEXT: 18001020: mov x16, #0x0
54+
// CHECK-NEXT: movk x16, #0xf000, lsl #16
55+
// CHECK-NEXT: movk x16, #0x0, lsl #32
56+
// CHECK-NEXT: movk x16, #0x0, lsl #48
57+
// CHECK-NEXT: br x16
58+
59+
// CHECK-LABEL: <__AArch64BTIThunk_>:
60+
// CHECK-NEXT: 30000000: bti c
61+
62+
// CHECK-LABEL: <fn1>:
63+
// CHECK-NEXT: 30000004: ret
64+
65+
//--- lds
66+
PHDRS {
67+
low PT_LOAD FLAGS(0x1 | 0x4);
68+
mid PT_LOAD FLAGS(0x1 | 0x4);
69+
high PT_LOAD FLAGS(0x1 | 0x4);
70+
}
71+
SECTIONS {
72+
.rodata 0x10000000 : { *(.note.gnu.property) } :low
73+
.text 0x18001000 : { *(.text.0) } :mid
74+
.text_high 0x30000000 : { *(.text.*) } :high
75+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// REQUIRES: aarch64
2+
// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
3+
// RUN: ld.lld %t.o --defsym big=0x1111222233334444 -o %t
4+
// RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
5+
6+
.section .text,"axy",@progbits,unique,0
7+
.globl _start
8+
_start:
9+
bl big
10+
b big
11+
12+
// CHECK: Disassembly of section .text:
13+
// CHECK-EMPTY:
14+
// CHECK-LABEL: <_start>:
15+
// CHECK-NEXT: bl {{.*}} <__AArch64AbsXOLongThunk_big>
16+
// CHECK-NEXT: b {{.*}} <__AArch64AbsXOLongThunk_big>
17+
// CHECK-LABEL: <__AArch64AbsXOLongThunk_big>:
18+
// CHECK-NEXT: mov x16, #0x4444
19+
// CHECK-NEXT: movk x16, #0x3333, lsl #16
20+
// CHECK-NEXT: movk x16, #0x2222, lsl #32
21+
// CHECK-NEXT: movk x16, #0x1111, lsl #48
22+
// CHECK-NEXT: br x16

lld/test/ELF/input-section-flags.s

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
# RUN: .outsec3 : { INPUT_SECTION_FLAGS(SHF_WRITE) *(.sec.*) } \
1616
# RUN: .outsec4 : { INPUT_SECTION_FLAGS(SHF_MERGE & !SHF_STRINGS) *(.sec.*) } \
1717
# RUN: .outsec5 : { INPUT_SECTION_FLAGS(SHF_STRINGS) *(.sec.*) } \
18-
# RUN: .outsec6 : { INPUT_SECTION_FLAGS(!SHF_TLS & !SHF_EXCLUDE & !SHF_COMPRESSED & !SHF_ARM_PURECODE) *(.sec.*) } \
18+
# RUN: .outsec6 : { INPUT_SECTION_FLAGS(!SHF_TLS & !SHF_EXCLUDE & !SHF_COMPRESSED & \
19+
# RUN: !SHF_ARM_PURECODE & !SHF_AARCH64_PURECODE) *(.sec.*) } \
1920
# RUN: } " > %t.script
2021
# RUN: ld.lld -o %t1 --script %t.script %t.o
2122
# RUN: llvm-readobj --symbols %t1 | FileCheck %s

0 commit comments

Comments
 (0)