Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -160,12 +160,15 @@ public: AArch64TargetInfo(); uint32_t getDynRel(uint32_t Type) const override; - bool isTlsGlobalDynamicRel(uint32_t Type) const override; + bool isTlsDescRel(uint32_t Type) const override; bool isTlsInitialExecRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override; void writePltZero(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; + void writePltTlsDescEntry(uint8_t *Buf, uint64_t PltEntryAddr, + uint64_t GotTlsDescEntryAddr, + uint64_t GotPltVA) const override; uint32_t getTlsGotRel(uint32_t Type) const override; bool isRelRelative(uint32_t Type) const override; bool needsCopyRelImpl(uint32_t Type) const override; @@ -1242,12 +1245,14 @@ IRelativeRel = R_AARCH64_IRELATIVE; GotRel = R_AARCH64_GLOB_DAT; PltRel = R_AARCH64_JUMP_SLOT; + TlsDescRel = R_AARCH64_TLSDESC; TlsGotRel = R_AARCH64_TLS_TPREL64; TlsModuleIndexRel = R_AARCH64_TLS_DTPMOD64; TlsOffsetRel = R_AARCH64_TLS_DTPREL64; UseLazyBinding = true; PltEntrySize = 16; PltZeroSize = 32; + PltTlsDescSize = 32; } bool AArch64TargetInfo::isRelRelative(uint32_t Type) const { @@ -1277,7 +1282,7 @@ } } -bool AArch64TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const { +bool AArch64TargetInfo::isTlsDescRel(uint32_t Type) const { return Type == R_AARCH64_TLSDESC_ADR_PAGE21 || Type == R_AARCH64_TLSDESC_LD64_LO12_NC || Type == R_AARCH64_TLSDESC_ADD_LO12_NC || @@ -1290,6 +1295,11 @@ } uint32_t AArch64TargetInfo::getDynRel(uint32_t Type) const { + if (Type == R_AARCH64_TLSDESC_ADR_PAGE21 || + Type == R_AARCH64_TLSDESC_LD64_LO12_NC || + Type == R_AARCH64_TLSDESC_ADD_LO12_NC || + Type == R_AARCH64_TLSDESC_CALL) + return R_AARCH64_TLSDESC; if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64) return Type; StringRef S = getELFRelocationTypeName(EM_AARCH64, Type); @@ -1344,6 +1354,32 @@ GotEntryAddr); } +void AArch64TargetInfo::writePltTlsDescEntry(uint8_t *Buf, + uint64_t PltEntryAddr, + uint64_t GotTlsDescEntryAddr, + uint64_t GotPltVA) const { + const uint8_t Inst[] = { + 0xe2, 0x0f, 0xbf, 0xa9, // stp x2, x3, [sp, #-16]! + 0x02, 0x00, 0x00, 0x90, // adrp x2, Page(DT_TLSDESC_GOT) + 0x03, 0x00, 0x00, 0x90, // adrp x3, Page(&.got.plt[0]) + 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2, #0] + 0x63, 0x00, 0x00, 0x91, // add x3, x3, 0 + 0x40, 0x00, 0x1f, 0xd6, // br x2 + 0x1f, 0x20, 0x03, 0xd5, // nop + 0x1f, 0x20, 0x03, 0xd5 // nop + }; + memcpy(Buf, Inst, sizeof(Inst)); + + relocateOne(Buf + 4, Buf + 8, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr + 4, + GotTlsDescEntryAddr); + relocateOne(Buf + 8, Buf + 12, R_AARCH64_ADR_PREL_PG_HI21, PltEntryAddr + 8, + GotPltVA); + relocateOne(Buf + 12, Buf + 16, R_AARCH64_LDST64_ABS_LO12_NC, + PltEntryAddr + 12, GotTlsDescEntryAddr); + relocateOne(Buf + 16, Buf + 20, R_AARCH64_ADD_ABS_LO12_NC, PltEntryAddr + 16, + GotPltVA); +} + uint32_t AArch64TargetInfo::getTlsGotRel(uint32_t Type) const { assert(Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC); @@ -1447,7 +1483,8 @@ break; } case R_AARCH64_ADR_PREL_PG_HI21: - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: { + case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case R_AARCH64_TLSDESC_ADR_PAGE21: { uint64_t X = getAArch64Page(SA) - getAArch64Page(P); checkInt<33>(X, Type); updateAArch64Addr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12] @@ -1468,6 +1505,7 @@ } case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12_NC: checkAlignment<8>(SA, Type); or32le(Loc, (SA & 0xFF8) << 7); break; @@ -1478,6 +1516,7 @@ or32le(Loc, (SA & 0x0FFC) << 9); break; case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12_NC: or32le(Loc, (SA & 0xFFF) << 10); break; case R_AARCH64_LDST32_ABS_LO12_NC: @@ -1514,6 +1553,11 @@ updateAArch64Add(Loc, V & 0xFFF); break; } + case R_AARCH64_TLSDESC_CALL: + // For relaxation only. Must be used to identify a + // BLR instruction which performs an indirect call + // to the TLS descriptor function for S + A. + break; default: fatal("unrecognized reloc " + Twine(Type)); } @@ -1532,6 +1576,10 @@ // movk x0, #0x10 // nop // nop + + // AArch64 uses Variant I of TLS data structures. Thread Control Block is + // placed before data. Read "ELF Handling For Thread-Local Storage, 3. Run + // Time Handling of TLS" by Ulrich Drepper for details. uint64_t TPOff = llvm::alignTo(TcbSize, Out::TlsPhdr->p_align); uint64_t X = SA + TPOff; checkUInt<32>(X, Type); Index: test/ELF/aarch64-tls-desc.s =================================================================== --- /dev/null +++ test/ELF/aarch64-tls-desc.s @@ -0,0 +1,164 @@ +# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o +# RUN: ld.lld %tmain.o -shared -o %tout +# RUN: llvm-objdump -d %tout | FileCheck %s +# RUN: llvm-readobj -s -r -dynamic-table %tout | FileCheck -check-prefix=READOBJ %s +# REQUIRES: aarch64 + +#READOBJ: Section { +#READOBJ: Index: +#READOBJ: Name: .plt +#READOBJ-NEXT: Type: SHT_PROGBITS +#READOBJ-NEXT: Flags [ +#READOBJ-NEXT: SHF_ALLOC +#READOBJ-NEXT: SHF_EXECINSTR +#READOBJ-NEXT: ] +#READOBJ-NEXT: Address: 0x1030 +#READOBJ-NEXT: Offset: +#READOBJ-NEXT: Size: 80 +#READOBJ-NEXT: Link: +#READOBJ-NEXT: Info: +#READOBJ-NEXT: AddressAlignment: +#READOBJ-NEXT: EntrySize: +#READOBJ-NEXT: } +#READOBJ: Section { +#READOBJ: Index: +#READOBJ: Name: .got +#READOBJ-NEXT: Type: SHT_PROGBITS +#READOBJ-NEXT: Flags [ +#READOBJ-NEXT: SHF_ALLOC +#READOBJ-NEXT: SHF_WRITE +#READOBJ-NEXT: ] +#READOBJ-NEXT: Address: 0x20C8 +#READOBJ-NEXT: Offset: +#READOBJ-NEXT: Size: 8 +#READOBJ-NEXT: Link: +#READOBJ-NEXT: Info: +#READOBJ-NEXT: AddressAlignment: +#READOBJ-NEXT: EntrySize: +#READOBJ-NEXT: } +#READOBJ: Section { +#READOBJ: Index: +#READOBJ: Name: .got.plt +#READOBJ-NEXT: Type: SHT_PROGBITS +#READOBJ-NEXT: Flags [ +#READOBJ-NEXT: SHF_ALLOC +#READOBJ-NEXT: SHF_WRITE +#READOBJ-NEXT: ] +#READOBJ-NEXT: Address: 0x3000 +#READOBJ-NEXT: Offset: 0x3000 +#READOBJ-NEXT: Size: 64 +#READOBJ-NEXT: Link: 0 +#READOBJ-NEXT: Info: 0 +#READOBJ-NEXT: AddressAlignment: 8 +#READOBJ-NEXT: EntrySize: 0 +#READOBJ-NEXT: } +#READOBJ: Relocations [ +#READOBJ-NEXT: Section ({{.*}}) .rela.plt { +## This also checks that SLOT relocations are placed vefore TLSDESC +## 0x3018 = .got.plt + 0x18 (reserved 3 entries) +## 0x3020 = next entry (first was single, 8 bytes) +## 0x3030 = 0x3018 + double entry size (16) +#READOBJ-NEXT: 0x3018 R_AARCH64_JUMP_SLOT slot 0x0 +#READOBJ-NEXT: 0x3020 R_AARCH64_TLSDESC foo 0x0 +#READOBJ-NEXT: 0x3030 R_AARCH64_TLSDESC bar 0x0 +#READOBJ-NEXT: } +#READOBJ-NEXT:] +#READOBJ: DynamicSection [ +#READOBJ-NEXT: Tag Type Name/Value +#READOBJ-NEXT: 0x0000000000000017 JMPREL 0x2C0 +#READOBJ-NEXT: 0x0000000000000002 PLTRELSZ 72 (bytes) +#READOBJ-NEXT: 0x0000000000000003 PLTGOT 0x3000 +#READOBJ-NEXT: 0x0000000000000014 PLTREL RELA +## 0x20A8 = Location of GOT entry used by TLS descriptor resolver PLT entry +#READOBJ-NEXT: 0x000000006FFFFEF7 TLSDESC_GOT 0x20C8 +## 0x1040 = Location of PLT entry for TLS descriptor resolver calls. +#READOBJ-NEXT: 0x000000006FFFFEF6 TLSDESC_PLT 0x1060 +#READOBJ-NEXT: 0x0000000000000006 SYMTAB 0x200 +#READOBJ-NEXT: 0x000000000000000B SYMENT 24 (bytes) +#READOBJ-NEXT: 0x0000000000000005 STRTAB 0x2A8 +#READOBJ-NEXT: 0x000000000000000A STRSZ 21 (bytes) +#READOBJ-NEXT: 0x0000000000000004 HASH 0x278 +#READOBJ-NEXT: 0x0000000000000000 NULL 0x0 +#READOBJ-NEXT: ] + +#CHECK: Disassembly of section .text: +#CHECK-NEXT: _start: +#CHECK-NEXT: 1000: 80 02 00 54 b.eq #80 +#CHECK-NEXT: 1004: 00 00 00 d0 adrp x0, #8192 +## Page(.got.plt[N]) - Page(0x1000) = Page(0x3020) - 0x1000 = +## 0x3000 - 0x1000 = 0x2000 = 8192 +## 0x20 = 32 +#CHECK-NEXT: 1008: 02 10 40 f9 ldr x2, [x0, #32] +#CHECK-NEXT: 100c: 00 80 00 91 add x0, x0, #32 +#CHECK-NEXT: 1010: 40 00 3f d6 blr x2 +## Page(.got.plt[N]) - Page(0x1000) = Page(0x3030) - 0x1000 = +## 0x3000 - 0x1000 = 0x2000 = 8192 +## 0x30 = 48 +#CHECK-NEXT: 1014: 00 00 00 d0 adrp x0, #8192 +#CHECK-NEXT: 1018: 02 18 40 f9 ldr x2, [x0, #48] +#CHECK-NEXT: 101c: 00 c0 00 91 add x0, x0, #48 +#CHECK-NEXT: 1020: 40 00 3f d6 blr x2 +#CHECK-NEXT: Disassembly of section .plt: +#CHECK-NEXT: .plt: +#CHECK-NEXT: 1030: f0 7b bf a9 stp x16, x30, [sp, #-16]! +#CHECK-NEXT: 1034: 10 00 00 d0 adrp x16, #8192 +#CHECK-NEXT: 1038: 11 0a 40 f9 ldr x17, [x16, #16] +#CHECK-NEXT: 103c: 10 42 00 91 add x16, x16, #16 +#CHECK-NEXT: 1040: 20 02 1f d6 br x17 +#CHECK-NEXT: 1044: 1f 20 03 d5 nop +#CHECK-NEXT: 1048: 1f 20 03 d5 nop +#CHECK-NEXT: 104c: 1f 20 03 d5 nop +#CHECK-NEXT: 1050: 10 00 00 d0 adrp x16, #8192 +#CHECK-NEXT: 1054: 11 0e 40 f9 ldr x17, [x16, #24] +#CHECK-NEXT: 1058: 10 62 00 91 add x16, x16, #24 +#CHECK-NEXT: 105c: 20 02 1f d6 br x17 +## Page(.got[N]) - Page(P) = Page(0x20C8) - Page(0x1044) = +## 0x2000 - 0x1000 = 4096 +## Page(.got.plt) - Page(P) = Page(0x3000) - Page(0x1048) = +## 0x3000 - 0x1000 = 8192 +## 0xC8 = 200 +## 0x0 = 0 +#CHECK-NEXT: 1060: {{.*}} stp x2, x3, [sp, #-16]! +#CHECK-NEXT: 1064: {{.*}} adrp x2, #4096 +#CHECK-NEXT: 1068: {{.*}} adrp x3, #8192 +#CHECK-NEXT: 106c: {{.*}} ldr x2, [x2, #200] +#CHECK-NEXT: 1070: {{.*}} add x3, x3, #0 +#CHECK-NEXT: 1074: {{.*}} br x2 +#CHECK-NEXT: 1078: {{.*}} nop +#CHECK-NEXT: 107c: {{.*}} nop + +.text + .global foo + .section .tdata,"awT",%progbits + .align 2 + .type foo, %object + .size foo, 4 +foo: + .word 5 + .text + +.text + .global bar + .section .tdata,"awT",%progbits + .align 2 + .type bar, %object + .size bar, 4 +bar: + .word 5 + .text + +.globl _start +_start: + b.eq slot + + adrp x0, :tlsdesc:foo + ldr x2, [x0, #:tlsdesc_lo12:foo] + add x0, x0, :tlsdesc_lo12:foo + .tlsdesccall foo + blr x2 + + adrp x0, :tlsdesc:bar + ldr x2, [x0, #:tlsdesc_lo12:bar] + add x0, x0, :tlsdesc_lo12:bar + .tlsdesccall bar + blr x2