mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 21:06:50 +00:00
[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: https://github.com/ARM-software/abi-aa/pull/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: https://github.com/llvm/llvm-project/pull/125687 * Clang: https://github.com/llvm/llvm-project/pull/125688
This commit is contained in:
parent
cf50936b23
commit
6e457c2001
@ -42,7 +42,10 @@ using namespace lld::elf;
|
||||
|
||||
uint32_t OutputSection::getPhdrFlags() const {
|
||||
uint32_t ret = 0;
|
||||
if (ctx.arg.emachine != EM_ARM || !(flags & SHF_ARM_PURECODE))
|
||||
bool purecode =
|
||||
(ctx.arg.emachine == EM_ARM && (flags & SHF_ARM_PURECODE)) ||
|
||||
(ctx.arg.emachine == EM_AARCH64 && (flags & SHF_AARCH64_PURECODE));
|
||||
if (!purecode)
|
||||
ret |= PF_R;
|
||||
if (flags & SHF_WRITE)
|
||||
ret |= PF_W;
|
||||
@ -161,8 +164,11 @@ void OutputSection::commitSection(InputSection *isec) {
|
||||
}
|
||||
|
||||
isec->parent = this;
|
||||
uint64_t andMask =
|
||||
ctx.arg.emachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0;
|
||||
uint64_t andMask = 0;
|
||||
if (ctx.arg.emachine == EM_ARM)
|
||||
andMask |= (uint64_t)SHF_ARM_PURECODE;
|
||||
if (ctx.arg.emachine == EM_AARCH64)
|
||||
andMask |= (uint64_t)SHF_AARCH64_PURECODE;
|
||||
uint64_t orMask = ~andMask;
|
||||
uint64_t andFlags = (flags & isec->flags) & andMask;
|
||||
uint64_t orFlags = (flags | isec->flags) & orMask;
|
||||
|
@ -1411,6 +1411,7 @@ static std::optional<uint64_t> parseFlag(StringRef tok) {
|
||||
.Case(CASE_ENT(SHF_COMPRESSED))
|
||||
.Case(CASE_ENT(SHF_EXCLUDE))
|
||||
.Case(CASE_ENT(SHF_ARM_PURECODE))
|
||||
.Case(CASE_ENT(SHF_AARCH64_PURECODE))
|
||||
.Default(std::nullopt);
|
||||
#undef CASE_ENT
|
||||
}
|
||||
|
@ -91,6 +91,19 @@ private:
|
||||
ThunkSection *tsec = nullptr;
|
||||
};
|
||||
|
||||
// AArch64 long range Thunks compatible with execute-only code.
|
||||
class AArch64ABSXOLongThunk final : public AArch64Thunk {
|
||||
public:
|
||||
AArch64ABSXOLongThunk(Ctx &ctx, Symbol &dest, int64_t addend,
|
||||
bool mayNeedLandingPad)
|
||||
: AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
|
||||
uint32_t size() override { return getMayUseShortThunk() ? 4 : 20; }
|
||||
void addSymbols(ThunkSection &sec) override;
|
||||
|
||||
private:
|
||||
void writeLong(uint8_t *buf) override;
|
||||
};
|
||||
|
||||
class AArch64ADRPThunk final : public AArch64Thunk {
|
||||
public:
|
||||
AArch64ADRPThunk(Ctx &ctx, Symbol &dest, int64_t addend,
|
||||
@ -663,6 +676,33 @@ void AArch64ABSLongThunk::addLongMapSyms() {
|
||||
addSymbol("$d", STT_NOTYPE, 8, *tsec);
|
||||
}
|
||||
|
||||
void AArch64ABSXOLongThunk::writeLong(uint8_t *buf) {
|
||||
const uint8_t data[] = {
|
||||
0x10, 0x00, 0x80, 0xd2, // movz x16, :abs_g0_nc:S, lsl #0
|
||||
0x10, 0x00, 0xa0, 0xf2, // movk x16, :abs_g1_nc:S, lsl #16
|
||||
0x10, 0x00, 0xc0, 0xf2, // movk x16, :abs_g2_nc:S, lsl #32
|
||||
0x10, 0x00, 0xe0, 0xf2, // movk x16, :abs_g3:S, lsl #48
|
||||
0x00, 0x02, 0x1f, 0xd6, // br x16
|
||||
};
|
||||
// If mayNeedLandingPad is true then destination is an
|
||||
// AArch64BTILandingPadThunk that defines landingPad.
|
||||
assert(!mayNeedLandingPad || landingPad != nullptr);
|
||||
uint64_t s = mayNeedLandingPad
|
||||
? landingPad->getVA(ctx, 0)
|
||||
: getAArch64ThunkDestVA(ctx, destination, addend);
|
||||
memcpy(buf, data, sizeof(data));
|
||||
ctx.target->relocateNoSym(buf + 0, R_AARCH64_MOVW_UABS_G0_NC, s);
|
||||
ctx.target->relocateNoSym(buf + 4, R_AARCH64_MOVW_UABS_G1_NC, s);
|
||||
ctx.target->relocateNoSym(buf + 8, R_AARCH64_MOVW_UABS_G2_NC, s);
|
||||
ctx.target->relocateNoSym(buf + 12, R_AARCH64_MOVW_UABS_G3, s);
|
||||
}
|
||||
|
||||
void AArch64ABSXOLongThunk::addSymbols(ThunkSection &sec) {
|
||||
addSymbol(ctx.saver.save("__AArch64AbsXOLongThunk_" + destination.getName()),
|
||||
STT_FUNC, 0, sec);
|
||||
addSymbol("$x", STT_NOTYPE, 0, sec);
|
||||
}
|
||||
|
||||
// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
|
||||
// using the small code model, including pc-relative ones. At time of writing
|
||||
// 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)
|
||||
|
||||
Thunk::~Thunk() = default;
|
||||
|
||||
static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, RelType type, Symbol &s,
|
||||
static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, const InputSection &sec,
|
||||
RelType type, Symbol &s,
|
||||
int64_t a) {
|
||||
assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
|
||||
type));
|
||||
@ -1491,6 +1532,9 @@ static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, RelType type, Symbol &s,
|
||||
!isAArch64BTILandingPad(ctx, s, a);
|
||||
if (ctx.arg.picThunk)
|
||||
return std::make_unique<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad);
|
||||
if (sec.getParent()->flags & SHF_AARCH64_PURECODE)
|
||||
return std::make_unique<AArch64ABSXOLongThunk>(ctx, s, a,
|
||||
mayNeedLandingPad);
|
||||
return std::make_unique<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad);
|
||||
}
|
||||
|
||||
@ -1702,7 +1746,7 @@ std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
|
||||
|
||||
switch (ctx.arg.emachine) {
|
||||
case EM_AARCH64:
|
||||
return addThunkAArch64(ctx, rel.type, s, a);
|
||||
return addThunkAArch64(ctx, isec, rel.type, s, a);
|
||||
case EM_ARM:
|
||||
return addThunkArm(ctx, isec, rel.type, s, a);
|
||||
case EM_AVR:
|
||||
|
32
lld/test/ELF/aarch64-execute-only.s
Normal file
32
lld/test/ELF/aarch64-execute-only.s
Normal file
@ -0,0 +1,32 @@
|
||||
// REQUIRES: aarch64
|
||||
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
|
||||
// RUN: ld.lld %t.o -o %t.so -shared
|
||||
// RUN: llvm-readelf -l %t.so | FileCheck --implicit-check-not=LOAD %s
|
||||
|
||||
// RUN: echo ".section .foo,\"ax\"; ret" > %t.s
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64 %t.s -o %t2.o
|
||||
// RUN: ld.lld %t.o %t2.o -o %t.so -shared
|
||||
// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF --implicit-check-not=LOAD %s
|
||||
|
||||
// CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x10000
|
||||
// CHECK-NEXT: LOAD 0x000248 0x0000000000010248 0x0000000000010248 0x{{.*}} 0x{{.*}} R E 0x10000
|
||||
// CHECK-NEXT: LOAD 0x00024c 0x000000000002024c 0x000000000002024c 0x{{.*}} 0x{{.*}} E 0x10000
|
||||
// CHECK-NEXT: LOAD 0x000250 0x0000000000030250 0x0000000000030250 0x000070 0x000db0 RW 0x10000
|
||||
|
||||
// CHECK: 01 .dynsym .gnu.hash .hash .dynstr
|
||||
// CHECK-NEXT: 02 .text
|
||||
// CHECK-NEXT: 03 .foo
|
||||
// CHECK-NEXT: 04 .dynamic
|
||||
|
||||
// DIFF: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00020d 0x00020d R 0x10000
|
||||
// DIFF-NEXT: LOAD 0x000210 0x0000000000010210 0x0000000000010210 0x00000c 0x00000c R E 0x10000
|
||||
// DIFF-NEXT: LOAD 0x000220 0x0000000000020220 0x0000000000020220 0x000070 0x000de0 RW 0x10000
|
||||
|
||||
// DIFF: 01 .dynsym .gnu.hash .hash .dynstr
|
||||
// DIFF-NEXT: 02 .text .foo
|
||||
// DIFF-NEXT: 03 .dynamic
|
||||
|
||||
ret
|
||||
.section .foo,"axy"
|
||||
ret
|
75
lld/test/ELF/aarch64-thunk-bti-execute-only.s
Normal file
75
lld/test/ELF/aarch64-thunk-bti-execute-only.s
Normal file
@ -0,0 +1,75 @@
|
||||
// REQUIRES: aarch64
|
||||
// RUN: rm -rf %t && split-file %s %t && cd %t
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64 asm -o a.o
|
||||
// RUN: ld.lld --script=lds a.o -o exe --defsym absolute=0xf0000000
|
||||
// RUN: llvm-objdump -d --no-show-raw-insn exe | FileCheck %s
|
||||
|
||||
//--- asm
|
||||
.section ".note.gnu.property", "a"
|
||||
.p2align 3
|
||||
.long 4
|
||||
.long 0x10
|
||||
.long 0x5
|
||||
.asciz "GNU"
|
||||
|
||||
/// Enable BTI.
|
||||
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND.
|
||||
.long 4
|
||||
.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI.
|
||||
.long 0
|
||||
|
||||
.section .text.0,"axy",@progbits
|
||||
.global _start
|
||||
.type _start,@function
|
||||
_start:
|
||||
/// Expect thunk to target a linker generated entry point with BTI landing pad.
|
||||
/// Two calls to make sure only one landing pad is created.
|
||||
bl fn1
|
||||
b fn1
|
||||
/// No BTI landing pad is added for absolute symbols.
|
||||
bl absolute
|
||||
|
||||
/// This function does not have a BTI compatible landing pad. Expect a linker
|
||||
/// generated landing pad for indirect branch thunks.
|
||||
.section .text.1,"axy",@progbits
|
||||
.hidden fn1
|
||||
.type fn1,@function
|
||||
fn1:
|
||||
ret
|
||||
|
||||
// CHECK-LABEL: <_start>:
|
||||
// CHECK-NEXT: 18001000: bl 0x1800100c <__AArch64AbsXOLongThunk_>
|
||||
// CHECK-NEXT: b 0x1800100c <__AArch64AbsXOLongThunk_>
|
||||
// CHECK-NEXT: bl 0x18001020 <__AArch64AbsXOLongThunk_absolute>
|
||||
|
||||
// CHECK-LABEL: <__AArch64AbsXOLongThunk_>:
|
||||
// CHECK-NEXT: 1800100c: mov x16, #0x0
|
||||
// CHECK-NEXT: movk x16, #0x3000, lsl #16
|
||||
// CHECK-NEXT: movk x16, #0x0, lsl #32
|
||||
// CHECK-NEXT: movk x16, #0x0, lsl #48
|
||||
// CHECK-NEXT: br x16
|
||||
|
||||
// CHECK-LABEL: <__AArch64AbsXOLongThunk_absolute>:
|
||||
// CHECK-NEXT: 18001020: mov x16, #0x0
|
||||
// CHECK-NEXT: movk x16, #0xf000, lsl #16
|
||||
// CHECK-NEXT: movk x16, #0x0, lsl #32
|
||||
// CHECK-NEXT: movk x16, #0x0, lsl #48
|
||||
// CHECK-NEXT: br x16
|
||||
|
||||
// CHECK-LABEL: <__AArch64BTIThunk_>:
|
||||
// CHECK-NEXT: 30000000: bti c
|
||||
|
||||
// CHECK-LABEL: <fn1>:
|
||||
// CHECK-NEXT: 30000004: ret
|
||||
|
||||
//--- lds
|
||||
PHDRS {
|
||||
low PT_LOAD FLAGS(0x1 | 0x4);
|
||||
mid PT_LOAD FLAGS(0x1 | 0x4);
|
||||
high PT_LOAD FLAGS(0x1 | 0x4);
|
||||
}
|
||||
SECTIONS {
|
||||
.rodata 0x10000000 : { *(.note.gnu.property) } :low
|
||||
.text 0x18001000 : { *(.text.0) } :mid
|
||||
.text_high 0x30000000 : { *(.text.*) } :high
|
||||
}
|
22
lld/test/ELF/aarch64-thunk-execute-only.s
Normal file
22
lld/test/ELF/aarch64-thunk-execute-only.s
Normal file
@ -0,0 +1,22 @@
|
||||
// REQUIRES: aarch64
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
|
||||
// RUN: ld.lld %t.o --defsym big=0x1111222233334444 -o %t
|
||||
// RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
|
||||
|
||||
.section .text,"axy",@progbits,unique,0
|
||||
.globl _start
|
||||
_start:
|
||||
bl big
|
||||
b big
|
||||
|
||||
// CHECK: Disassembly of section .text:
|
||||
// CHECK-EMPTY:
|
||||
// CHECK-LABEL: <_start>:
|
||||
// CHECK-NEXT: bl {{.*}} <__AArch64AbsXOLongThunk_big>
|
||||
// CHECK-NEXT: b {{.*}} <__AArch64AbsXOLongThunk_big>
|
||||
// CHECK-LABEL: <__AArch64AbsXOLongThunk_big>:
|
||||
// CHECK-NEXT: mov x16, #0x4444
|
||||
// CHECK-NEXT: movk x16, #0x3333, lsl #16
|
||||
// CHECK-NEXT: movk x16, #0x2222, lsl #32
|
||||
// CHECK-NEXT: movk x16, #0x1111, lsl #48
|
||||
// CHECK-NEXT: br x16
|
@ -15,7 +15,8 @@
|
||||
# RUN: .outsec3 : { INPUT_SECTION_FLAGS(SHF_WRITE) *(.sec.*) } \
|
||||
# RUN: .outsec4 : { INPUT_SECTION_FLAGS(SHF_MERGE & !SHF_STRINGS) *(.sec.*) } \
|
||||
# RUN: .outsec5 : { INPUT_SECTION_FLAGS(SHF_STRINGS) *(.sec.*) } \
|
||||
# RUN: .outsec6 : { INPUT_SECTION_FLAGS(!SHF_TLS & !SHF_EXCLUDE & !SHF_COMPRESSED & !SHF_ARM_PURECODE) *(.sec.*) } \
|
||||
# RUN: .outsec6 : { INPUT_SECTION_FLAGS(!SHF_TLS & !SHF_EXCLUDE & !SHF_COMPRESSED & \
|
||||
# RUN: !SHF_ARM_PURECODE & !SHF_AARCH64_PURECODE) *(.sec.*) } \
|
||||
# RUN: } " > %t.script
|
||||
# RUN: ld.lld -o %t1 --script %t.script %t.o
|
||||
# RUN: llvm-readobj --symbols %t1 | FileCheck %s
|
||||
|
Loading…
x
Reference in New Issue
Block a user