Skip to content

Commit 52bbe20

Browse files
authored
[PAC][CodeGen][ELF][AArch64] Support signed TLSDESC (#113813)
Depends on #120010 `TLSDESC_AUTH_CALLSEQ` pseudo-instruction is introduced which is later expanded to actual instruction sequence like the following. ``` adrp x0, :tlsdesc_auth:var ldr x16, [x0, #:tlsdesc_auth_lo12:var] add x0, x0, #:tlsdesc_auth_lo12:var blraa x16, x0 (TPIDR_EL0 offset now in x0) ``` Only SelectionDAG ISel is supported. Tests starting with 'ptrauth-' have corresponding variants w/o this prefix.
1 parent a21f13b commit 52bbe20

File tree

5 files changed

+185
-5
lines changed

5 files changed

+185
-5
lines changed

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2730,6 +2730,54 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
27302730
EmitToStreamer(*OutStreamer, TmpInstSB);
27312731
return;
27322732
}
2733+
case AArch64::TLSDESC_AUTH_CALLSEQ: {
2734+
/// lower this to:
2735+
/// adrp x0, :tlsdesc_auth:var
2736+
/// ldr x16, [x0, #:tlsdesc_auth_lo12:var]
2737+
/// add x0, x0, #:tlsdesc_auth_lo12:var
2738+
/// blraa x16, x0
2739+
/// (TPIDR_EL0 offset now in x0)
2740+
const MachineOperand &MO_Sym = MI->getOperand(0);
2741+
MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym);
2742+
MCOperand SymTLSDescLo12, SymTLSDesc;
2743+
MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF);
2744+
MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE);
2745+
MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12);
2746+
MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc);
2747+
2748+
MCInst Adrp;
2749+
Adrp.setOpcode(AArch64::ADRP);
2750+
Adrp.addOperand(MCOperand::createReg(AArch64::X0));
2751+
Adrp.addOperand(SymTLSDesc);
2752+
EmitToStreamer(*OutStreamer, Adrp);
2753+
2754+
MCInst Ldr;
2755+
Ldr.setOpcode(AArch64::LDRXui);
2756+
Ldr.addOperand(MCOperand::createReg(AArch64::X16));
2757+
Ldr.addOperand(MCOperand::createReg(AArch64::X0));
2758+
Ldr.addOperand(SymTLSDescLo12);
2759+
Ldr.addOperand(MCOperand::createImm(0));
2760+
EmitToStreamer(*OutStreamer, Ldr);
2761+
2762+
MCInst Add;
2763+
Add.setOpcode(AArch64::ADDXri);
2764+
Add.addOperand(MCOperand::createReg(AArch64::X0));
2765+
Add.addOperand(MCOperand::createReg(AArch64::X0));
2766+
Add.addOperand(SymTLSDescLo12);
2767+
Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0)));
2768+
EmitToStreamer(*OutStreamer, Add);
2769+
2770+
// Authenticated TLSDESC accesses are not relaxed.
2771+
// Thus, do not emit .tlsdesccall for AUTH TLSDESC.
2772+
2773+
MCInst Blraa;
2774+
Blraa.setOpcode(AArch64::BLRAA);
2775+
Blraa.addOperand(MCOperand::createReg(AArch64::X16));
2776+
Blraa.addOperand(MCOperand::createReg(AArch64::X0));
2777+
EmitToStreamer(*OutStreamer, Blraa);
2778+
2779+
return;
2780+
}
27332781
case AArch64::TLSDESC_CALLSEQ: {
27342782
/// lower this to:
27352783
/// adrp x0, :tlsdesc:var

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2669,6 +2669,7 @@ const char *AArch64TargetLowering::getTargetNodeName(unsigned Opcode) const {
26692669
MAKE_CASE(AArch64ISD::CSINC)
26702670
MAKE_CASE(AArch64ISD::THREAD_POINTER)
26712671
MAKE_CASE(AArch64ISD::TLSDESC_CALLSEQ)
2672+
MAKE_CASE(AArch64ISD::TLSDESC_AUTH_CALLSEQ)
26722673
MAKE_CASE(AArch64ISD::PROBED_ALLOCA)
26732674
MAKE_CASE(AArch64ISD::ABDS_PRED)
26742675
MAKE_CASE(AArch64ISD::ABDU_PRED)
@@ -10123,8 +10124,11 @@ SDValue AArch64TargetLowering::LowerELFTLSDescCallSeq(SDValue SymAddr,
1012310124
SDValue Chain = DAG.getEntryNode();
1012410125
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
1012510126

10126-
Chain =
10127-
DAG.getNode(AArch64ISD::TLSDESC_CALLSEQ, DL, NodeTys, {Chain, SymAddr});
10127+
unsigned Opcode =
10128+
DAG.getMachineFunction().getInfo<AArch64FunctionInfo>()->hasELFSignedGOT()
10129+
? AArch64ISD::TLSDESC_AUTH_CALLSEQ
10130+
: AArch64ISD::TLSDESC_CALLSEQ;
10131+
Chain = DAG.getNode(Opcode, DL, NodeTys, {Chain, SymAddr});
1012810132
SDValue Glue = Chain.getValue(1);
1012910133

1013010134
return DAG.getCopyFromReg(Chain, DL, AArch64::X0, PtrVT, Glue);
@@ -10136,8 +10140,12 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op,
1013610140
assert(Subtarget->isTargetELF() && "This function expects an ELF target");
1013710141

1013810142
const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
10143+
AArch64FunctionInfo *MFI =
10144+
DAG.getMachineFunction().getInfo<AArch64FunctionInfo>();
1013910145

10140-
TLSModel::Model Model = getTargetMachine().getTLSModel(GA->getGlobal());
10146+
TLSModel::Model Model = MFI->hasELFSignedGOT()
10147+
? TLSModel::GeneralDynamic
10148+
: getTargetMachine().getTLSModel(GA->getGlobal());
1014110149

1014210150
if (!EnableAArch64ELFLocalDynamicTLSGeneration) {
1014310151
if (Model == TLSModel::LocalDynamic)
@@ -10174,8 +10182,6 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op,
1017410182
// calculation.
1017510183

1017610184
// These accesses will need deduplicating if there's more than one.
10177-
AArch64FunctionInfo *MFI =
10178-
DAG.getMachineFunction().getInfo<AArch64FunctionInfo>();
1017910185
MFI->incNumLocalDynamicTLSAccesses();
1018010186

1018110187
// The call needs a relocation too for linker relaxation. It doesn't make

llvm/lib/Target/AArch64/AArch64ISelLowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ enum NodeType : unsigned {
8383
// Produces the full sequence of instructions for getting the thread pointer
8484
// offset of a variable into X0, using the TLSDesc model.
8585
TLSDESC_CALLSEQ,
86+
TLSDESC_AUTH_CALLSEQ,
8687
ADRP, // Page address of a TargetGlobalAddress operand.
8788
ADR, // ADR
8889
ADDlow, // Add the low 12 bits of a TargetGlobalAddress operand.

llvm/lib/Target/AArch64/AArch64InstrInfo.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,9 @@ def AArch64tlsdesc_callseq : SDNode<"AArch64ISD::TLSDESC_CALLSEQ",
883883
SDT_AArch64TLSDescCallSeq,
884884
[SDNPOutGlue, SDNPHasChain, SDNPVariadic]>;
885885

886+
def AArch64tlsdesc_auth_callseq : SDNode<"AArch64ISD::TLSDESC_AUTH_CALLSEQ",
887+
SDT_AArch64TLSDescCallSeq,
888+
[SDNPOutGlue, SDNPHasChain, SDNPVariadic]>;
886889

887890
def AArch64WrapperLarge : SDNode<"AArch64ISD::WrapperLarge",
888891
SDT_AArch64WrapperLarge>;
@@ -3312,8 +3315,16 @@ def TLSDESC_CALLSEQ
33123315
: Pseudo<(outs), (ins i64imm:$sym),
33133316
[(AArch64tlsdesc_callseq tglobaltlsaddr:$sym)]>,
33143317
Sched<[WriteI, WriteLD, WriteI, WriteBrReg]>;
3318+
let isCall = 1, Defs = [NZCV, LR, X0, X16], hasSideEffects = 1, Size = 16,
3319+
isCodeGenOnly = 1 in
3320+
def TLSDESC_AUTH_CALLSEQ
3321+
: Pseudo<(outs), (ins i64imm:$sym),
3322+
[(AArch64tlsdesc_auth_callseq tglobaltlsaddr:$sym)]>,
3323+
Sched<[WriteI, WriteLD, WriteI, WriteBrReg]>;
33153324
def : Pat<(AArch64tlsdesc_callseq texternalsym:$sym),
33163325
(TLSDESC_CALLSEQ texternalsym:$sym)>;
3326+
def : Pat<(AArch64tlsdesc_auth_callseq texternalsym:$sym),
3327+
(TLSDESC_AUTH_CALLSEQ texternalsym:$sym)>;
33173328

33183329
//===----------------------------------------------------------------------===//
33193330
// Conditional branch (immediate) instruction.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \
2+
; RUN: -verify-machineinstrs < %s | FileCheck %s
3+
; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \
4+
; RUN: -filetype=obj < %s | llvm-readelf -r -s - | FileCheck --check-prefix=CHECK-OBJ %s
5+
; RUN: not --crash llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \
6+
; RUN: -global-isel=1 < %s 2>&1 | FileCheck --check-prefix=CHECK-ERR %s
7+
8+
@general_dynamic_var = external thread_local global i32
9+
10+
define i32 @test_generaldynamic() {
11+
; CHECK-LABEL: test_generaldynamic:
12+
13+
%val = load i32, ptr @general_dynamic_var
14+
ret i32 %val
15+
16+
; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:general_dynamic_var
17+
; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var]
18+
; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var
19+
; CHECK-NEXT: blraa x16, x0
20+
; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0
21+
; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0]
22+
23+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21
24+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12
25+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12
26+
; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL
27+
28+
; CHECK-ERR: LLVM ERROR: cannot select: %1:gpr64sp(p0) = G_GLOBAL_VALUE @general_dynamic_var (in function: test_generaldynamic)
29+
}
30+
31+
define ptr @test_generaldynamic_addr() {
32+
; CHECK-LABEL: test_generaldynamic_addr:
33+
34+
ret ptr @general_dynamic_var
35+
36+
; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:general_dynamic_var
37+
; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var]
38+
; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var
39+
; CHECK-NEXT: blraa x16, x0
40+
; CHECK-NEXT: mrs [[TP:x[0-9]+]], TPIDR_EL0
41+
; CHECK-NEXT: add x0, [[TP]], x0
42+
43+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21
44+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12
45+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12
46+
; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL
47+
}
48+
49+
;; Note: with signed TLSDESC, general dynamic model is always used,
50+
;; even when local dynamic is requested.
51+
52+
@local_dynamic_var = external thread_local(localdynamic) global i32
53+
54+
define i32 @test_localdynamic() {
55+
; CHECK-LABEL: test_localdynamic:
56+
57+
%val = load i32, ptr @local_dynamic_var
58+
ret i32 %val
59+
60+
; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:local_dynamic_var
61+
; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var]
62+
; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var
63+
; CHECK-NEXT: blraa x16, x0
64+
; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0
65+
; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0]
66+
67+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21
68+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12
69+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12
70+
; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL
71+
}
72+
73+
define ptr @test_localdynamic_addr() {
74+
; CHECK-LABEL: test_localdynamic_addr:
75+
76+
ret ptr @local_dynamic_var
77+
78+
; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:local_dynamic_var
79+
; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var]
80+
; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var
81+
; CHECK-NEXT: blraa x16, x0
82+
; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0
83+
; CHECK-NEXT: add x0, x[[TPIDR]], x0
84+
85+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21
86+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12
87+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12
88+
; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL
89+
}
90+
91+
@extern_weak_var = extern_weak thread_local global i32
92+
93+
define i32 @test_extern_weak() {
94+
; CHECK-LABEL: test_extern_weak:
95+
96+
%val = load i32, ptr @extern_weak_var
97+
ret i32 %val
98+
99+
; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:extern_weak_var
100+
; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:extern_weak_var]
101+
; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:extern_weak_var
102+
; CHECK-NEXT: blraa x16, x0
103+
; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0
104+
; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0]
105+
106+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21
107+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12
108+
; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12
109+
; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL
110+
; CHECK-OBJ: 0000000000000000 0 TLS WEAK DEFAULT UND extern_weak_var
111+
}
112+
113+
!llvm.module.flags = !{!0}
114+
!0 = !{i32 8, !"ptrauth-elf-got", i32 1}

0 commit comments

Comments
 (0)