From 2790df9e6e775f1d3907dda451d51acd0d38c805 Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Wed, 21 Aug 2024 10:22:30 +0300 Subject: [PATCH 1/2] [PAC][CodeGen][ELF][AArch64] Support signed TLSDESC Support the following relocations and assembly operators: - `R_AARCH64_AUTH_TLSDESC_ADR_PAGE21` (`:tlsdesc_auth:` for `adrp`) - `R_AARCH64_AUTH_TLSDESC_LD64_LO12` (`:tlsdesc_auth_lo12:` for `ldr`) - `R_AARCH64_AUTH_TLSDESC_ADD_LO12` (`:tlsdesc_auth_lo12:` for `add`) `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. --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 49 ++++++++ .../Target/AArch64/AArch64ISelLowering.cpp | 18 ++- llvm/lib/Target/AArch64/AArch64ISelLowering.h | 1 + llvm/lib/Target/AArch64/AArch64InstrInfo.td | 14 +++ .../AArch64/ptrauth-arm64-tls-dynamics.ll | 111 ++++++++++++++++++ 5 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 69d07f27fa8e1..e9111f47f7db3 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -2730,6 +2730,55 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, TmpInstSB); return; } + case AArch64::TLSDESC_AUTH_CALLSEQ: { + /// lower this to: + /// 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) + const MachineOperand &MO_Sym = MI->getOperand(0); + MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym); + MCOperand Sym, SymTLSDescLo12, SymTLSDesc; + MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF); + MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE); + MCInstLowering.lowerOperand(MO_Sym, Sym); + MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12); + MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc); + + MCInst Adrp; + Adrp.setOpcode(AArch64::ADRP); + Adrp.addOperand(MCOperand::createReg(AArch64::X0)); + Adrp.addOperand(SymTLSDesc); + EmitToStreamer(*OutStreamer, Adrp); + + MCInst Ldr; + Ldr.setOpcode(AArch64::LDRXui); + Ldr.addOperand(MCOperand::createReg(AArch64::X16)); + Ldr.addOperand(MCOperand::createReg(AArch64::X0)); + Ldr.addOperand(SymTLSDescLo12); + Ldr.addOperand(MCOperand::createImm(0)); + EmitToStreamer(*OutStreamer, Ldr); + + MCInst Add; + Add.setOpcode(AArch64::ADDXri); + Add.addOperand(MCOperand::createReg(AArch64::X0)); + Add.addOperand(MCOperand::createReg(AArch64::X0)); + Add.addOperand(SymTLSDescLo12); + Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0))); + EmitToStreamer(*OutStreamer, Add); + + // Authenticated TLSDESC accesses are not relatex. + // Thus, do not emit .tlsdesccall for AUTH TLSDESC. + + MCInst Blraa; + Blraa.setOpcode(AArch64::BLRAA); + Blraa.addOperand(MCOperand::createReg(AArch64::X16)); + Blraa.addOperand(MCOperand::createReg(AArch64::X0)); + EmitToStreamer(*OutStreamer, Blraa); + + return; + } case AArch64::TLSDESC_CALLSEQ: { /// lower this to: /// adrp x0, :tlsdesc:var diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index a6f8f47f31fa5..6e321db5728e3 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -2669,6 +2669,7 @@ const char *AArch64TargetLowering::getTargetNodeName(unsigned Opcode) const { MAKE_CASE(AArch64ISD::CSINC) MAKE_CASE(AArch64ISD::THREAD_POINTER) MAKE_CASE(AArch64ISD::TLSDESC_CALLSEQ) + MAKE_CASE(AArch64ISD::TLSDESC_AUTH_CALLSEQ) MAKE_CASE(AArch64ISD::PROBED_ALLOCA) MAKE_CASE(AArch64ISD::ABDS_PRED) MAKE_CASE(AArch64ISD::ABDU_PRED) @@ -10123,8 +10124,11 @@ SDValue AArch64TargetLowering::LowerELFTLSDescCallSeq(SDValue SymAddr, SDValue Chain = DAG.getEntryNode(); SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); - Chain = - DAG.getNode(AArch64ISD::TLSDESC_CALLSEQ, DL, NodeTys, {Chain, SymAddr}); + unsigned Opcode = + DAG.getMachineFunction().getInfo()->hasELFSignedGOT() + ? AArch64ISD::TLSDESC_AUTH_CALLSEQ + : AArch64ISD::TLSDESC_CALLSEQ; + Chain = DAG.getNode(Opcode, DL, NodeTys, {Chain, SymAddr}); SDValue Glue = Chain.getValue(1); return DAG.getCopyFromReg(Chain, DL, AArch64::X0, PtrVT, Glue); @@ -10136,8 +10140,14 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op, assert(Subtarget->isTargetELF() && "This function expects an ELF target"); const GlobalAddressSDNode *GA = cast(Op); + AArch64FunctionInfo *MFI = + DAG.getMachineFunction().getInfo(); - TLSModel::Model Model = getTargetMachine().getTLSModel(GA->getGlobal()); + TLSModel::Model Model; + if (MFI->hasELFSignedGOT()) + Model = TLSModel::GeneralDynamic; + else + Model = getTargetMachine().getTLSModel(GA->getGlobal()); if (!EnableAArch64ELFLocalDynamicTLSGeneration) { if (Model == TLSModel::LocalDynamic) @@ -10174,8 +10184,6 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op, // calculation. // These accesses will need deduplicating if there's more than one. - AArch64FunctionInfo *MFI = - DAG.getMachineFunction().getInfo(); MFI->incNumLocalDynamicTLSAccesses(); // The call needs a relocation too for linker relaxation. It doesn't make diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 1b7f328fa729a..85b62be5dd30d 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -83,6 +83,7 @@ enum NodeType : unsigned { // Produces the full sequence of instructions for getting the thread pointer // offset of a variable into X0, using the TLSDesc model. TLSDESC_CALLSEQ, + TLSDESC_AUTH_CALLSEQ, ADRP, // Page address of a TargetGlobalAddress operand. ADR, // ADR ADDlow, // Add the low 12 bits of a TargetGlobalAddress operand. diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 629098cda0c4e..d944af7b03746 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -498,6 +498,8 @@ def SDT_AArch64stnp : SDTypeProfile<0, 3, [SDTCisVT<0, v4i32>, SDTCisSameAs<0, 1 // number of operands (the variable) def SDT_AArch64TLSDescCallSeq : SDTypeProfile<0,1, [SDTCisPtrTy<0>]>; +def SDT_AArch64TLSDescAuthCallSeq : SDTypeProfile<0,1, + [SDTCisPtrTy<0>]>; def SDT_AArch64WrapperLarge : SDTypeProfile<1, 4, [SDTCisVT<0, i64>, SDTCisVT<1, i32>, @@ -883,6 +885,10 @@ def AArch64tlsdesc_callseq : SDNode<"AArch64ISD::TLSDESC_CALLSEQ", SDT_AArch64TLSDescCallSeq, [SDNPOutGlue, SDNPHasChain, SDNPVariadic]>; +def AArch64tlsdesc_auth_callseq : SDNode<"AArch64ISD::TLSDESC_AUTH_CALLSEQ", + SDT_AArch64TLSDescAuthCallSeq, + [SDNPInGlue, SDNPOutGlue, SDNPHasChain, + SDNPVariadic]>; def AArch64WrapperLarge : SDNode<"AArch64ISD::WrapperLarge", SDT_AArch64WrapperLarge>; @@ -3312,8 +3318,16 @@ def TLSDESC_CALLSEQ : Pseudo<(outs), (ins i64imm:$sym), [(AArch64tlsdesc_callseq tglobaltlsaddr:$sym)]>, Sched<[WriteI, WriteLD, WriteI, WriteBrReg]>; +let isCall = 1, Defs = [NZCV, LR, X0, X16], hasSideEffects = 1, Size = 16, + isCodeGenOnly = 1 in +def TLSDESC_AUTH_CALLSEQ + : Pseudo<(outs), (ins i64imm:$sym), + [(AArch64tlsdesc_auth_callseq tglobaltlsaddr:$sym)]>, + Sched<[WriteI, WriteLD, WriteI, WriteBrReg]>; def : Pat<(AArch64tlsdesc_callseq texternalsym:$sym), (TLSDESC_CALLSEQ texternalsym:$sym)>; +def : Pat<(AArch64tlsdesc_auth_callseq texternalsym:$sym), + (TLSDESC_AUTH_CALLSEQ texternalsym:$sym)>; //===----------------------------------------------------------------------===// // Conditional branch (immediate) instruction. diff --git a/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll b/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll new file mode 100644 index 0000000000000..ebb2fa3e6f8d6 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll @@ -0,0 +1,111 @@ +; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \ +; RUN: -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \ +; RUN: -filetype=obj < %s | llvm-readelf -r -s - | FileCheck --check-prefix=CHECK-OBJ %s +; RUN: not --crash llc -mtriple=aarch64-unknown-linux-gnu -mattr=+pauth -relocation-model=pic \ +; RUN: -global-isel=1 < %s 2>&1 | FileCheck --check-prefix=CHECK-ERR %s + +@general_dynamic_var = external thread_local global i32 + +define i32 @test_generaldynamic() { +; CHECK-LABEL: test_generaldynamic: + + %val = load i32, ptr @general_dynamic_var + ret i32 %val + +; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:general_dynamic_var +; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var] +; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var +; CHECK-NEXT: blraa x16, x0 +; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0 +; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0] + +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 +; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL + +; CHECK-ERR: LLVM ERROR: cannot select: %1:gpr64sp(p0) = G_GLOBAL_VALUE @general_dynamic_var (in function: test_generaldynamic) +} + +define ptr @test_generaldynamic_addr() { +; CHECK-LABEL: test_generaldynamic_addr: + + ret ptr @general_dynamic_var + +; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:general_dynamic_var +; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var] +; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:general_dynamic_var +; CHECK-NEXT: blraa x16, x0 +; CHECK-NEXT: mrs [[TP:x[0-9]+]], TPIDR_EL0 +; CHECK-NEXT: add x0, [[TP]], x0 + +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 +; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +} + +@local_dynamic_var = external thread_local(localdynamic) global i32 + +define i32 @test_localdynamic() { +; CHECK-LABEL: test_localdynamic: + + %val = load i32, ptr @local_dynamic_var + ret i32 %val + +; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:local_dynamic_var +; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var] +; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var +; CHECK-NEXT: blraa x16, x0 +; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0 +; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0] + +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 +; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +} + +define ptr @test_localdynamic_addr() { +; CHECK-LABEL: test_localdynamic_addr: + + ret ptr @local_dynamic_var + +; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:local_dynamic_var +; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var] +; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:local_dynamic_var +; CHECK-NEXT: blraa x16, x0 +; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0 +; CHECK-NEXT: add x0, x[[TPIDR]], x0 + +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 +; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +} + +@extern_weak_var = extern_weak thread_local global i32 + +define i32 @test_extern_weak() { +; CHECK-LABEL: test_extern_weak: + + %val = load i32, ptr @extern_weak_var + ret i32 %val + +; CHECK: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc_auth:extern_weak_var +; CHECK-NEXT: ldr x16, [x[[TLSDESC_HI]], :tlsdesc_auth_lo12:extern_weak_var] +; CHECK-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_auth_lo12:extern_weak_var +; CHECK-NEXT: blraa x16, x0 +; CHECK-NEXT: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0 +; CHECK-NEXT: ldr w0, [x[[TPIDR]], x0] + +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADR_PAGE21 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_LD64_LO12 +; CHECK-OBJ: R_AARCH64_AUTH_TLSDESC_ADD_LO12 +; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL +; CHECK-OBJ: 0000000000000000 0 TLS WEAK DEFAULT UND extern_weak_var +} + +!llvm.module.flags = !{!0} +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} From dcdbcdd133b329fa33f64ce5a7f57b8fcf785e4b Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Fri, 27 Dec 2024 15:18:30 +0300 Subject: [PATCH 2/2] Address review comments --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 5 ++--- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 8 +++----- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 7 ++----- llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll | 3 +++ 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index e9111f47f7db3..9bec782ca8ce9 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -2739,10 +2739,9 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { /// (TPIDR_EL0 offset now in x0) const MachineOperand &MO_Sym = MI->getOperand(0); MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym); - MCOperand Sym, SymTLSDescLo12, SymTLSDesc; + MCOperand SymTLSDescLo12, SymTLSDesc; MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF); MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE); - MCInstLowering.lowerOperand(MO_Sym, Sym); MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12); MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc); @@ -2768,7 +2767,7 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0))); EmitToStreamer(*OutStreamer, Add); - // Authenticated TLSDESC accesses are not relatex. + // Authenticated TLSDESC accesses are not relaxed. // Thus, do not emit .tlsdesccall for AUTH TLSDESC. MCInst Blraa; diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 6e321db5728e3..24e1ebd8421fb 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10143,11 +10143,9 @@ AArch64TargetLowering::LowerELFGlobalTLSAddress(SDValue Op, AArch64FunctionInfo *MFI = DAG.getMachineFunction().getInfo(); - TLSModel::Model Model; - if (MFI->hasELFSignedGOT()) - Model = TLSModel::GeneralDynamic; - else - Model = getTargetMachine().getTLSModel(GA->getGlobal()); + TLSModel::Model Model = MFI->hasELFSignedGOT() + ? TLSModel::GeneralDynamic + : getTargetMachine().getTLSModel(GA->getGlobal()); if (!EnableAArch64ELFLocalDynamicTLSGeneration) { if (Model == TLSModel::LocalDynamic) diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index d944af7b03746..ec891ea4bac85 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -498,8 +498,6 @@ def SDT_AArch64stnp : SDTypeProfile<0, 3, [SDTCisVT<0, v4i32>, SDTCisSameAs<0, 1 // number of operands (the variable) def SDT_AArch64TLSDescCallSeq : SDTypeProfile<0,1, [SDTCisPtrTy<0>]>; -def SDT_AArch64TLSDescAuthCallSeq : SDTypeProfile<0,1, - [SDTCisPtrTy<0>]>; def SDT_AArch64WrapperLarge : SDTypeProfile<1, 4, [SDTCisVT<0, i64>, SDTCisVT<1, i32>, @@ -886,9 +884,8 @@ def AArch64tlsdesc_callseq : SDNode<"AArch64ISD::TLSDESC_CALLSEQ", [SDNPOutGlue, SDNPHasChain, SDNPVariadic]>; def AArch64tlsdesc_auth_callseq : SDNode<"AArch64ISD::TLSDESC_AUTH_CALLSEQ", - SDT_AArch64TLSDescAuthCallSeq, - [SDNPInGlue, SDNPOutGlue, SDNPHasChain, - SDNPVariadic]>; + SDT_AArch64TLSDescCallSeq, + [SDNPOutGlue, SDNPHasChain, SDNPVariadic]>; def AArch64WrapperLarge : SDNode<"AArch64ISD::WrapperLarge", SDT_AArch64WrapperLarge>; diff --git a/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll b/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll index ebb2fa3e6f8d6..89731e62dcc1e 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-arm64-tls-dynamics.ll @@ -46,6 +46,9 @@ define ptr @test_generaldynamic_addr() { ; CHECK-OBJ-NOT: R_AARCH64_TLSDESC_CALL } +;; Note: with signed TLSDESC, general dynamic model is always used, +;; even when local dynamic is requested. + @local_dynamic_var = external thread_local(localdynamic) global i32 define i32 @test_localdynamic() {