Index: lld/ELF/Relocations.cpp =================================================================== --- lld/ELF/Relocations.cpp +++ lld/ELF/Relocations.cpp @@ -1263,7 +1263,7 @@ template static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, - RelTy *end) { + RelTy *start, RelTy *end) { const RelTy &rel = *i; uint32_t symIndex = rel.getSymbol(config->isMips64EL); Symbol &sym = sec.getFile()->getSymbol(symIndex); @@ -1308,6 +1308,35 @@ int64_t addend = computeAddend(rel, end, sec, expr, sym.isLocal()); if (config->emachine == EM_PPC64) { + // When computing the address of a TLS symbol for the General Dynamic + // and Local Dynamic models a call is made to __tls_get_addr. This function + // requires two relocations on it. The first is for the symbol marked with + // R_PPC64_TLSGD or R_PPC64_TLSLD. The second is for the function call + // itself and is marked with R_PPC64_REL24 or R_PPC64_REL24_NOTOC. + // The following code checks that the TLSGD/LD relocations are not missing. + if ((type == R_PPC64_REL24 || type == R_PPC64_REL24_NOTOC) && + sym.getName() == "__tls_get_addr") { + // Check if the R_PPC64_REL24/R_PPC64_REL24_NOTOC relocation is the + // first relocation. It shound't ever be first because that means + // there is no TLSGD/TLSLD before it. + if ((i - 1) == start) + error("Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD " + "relocation." + + getLocation(sec, sym, offset)); + else { + // Subtract 2 to get the previous iterator because we have already done + // ++i above. This is now safe because we know that i-1 is not the + // start. + const RelTy &prevRel = *(i - 2); + RelType prevType = prevRel.getType(config->isMips64EL); + if (prevRel.r_offset != rel.r_offset || + (prevType != R_PPC64_TLSGD && prevType != R_PPC64_TLSLD)) + errorOrWarn("Call to __tls_get_addr is missing a " + "R_PPC64_TLSGD/R_PPC64_TLSLD relocation." + + getLocation(sec, sym, offset)); + } + } + // We can separate the small code model relocations into 2 categories: // 1) Those that access the compiler generated .toc sections. // 2) Those that access the linker allocated got entries. @@ -1502,7 +1531,7 @@ sec.relocations.reserve(rels.size()); for (auto i = rels.begin(), end = rels.end(); i != end;) - scanReloc(sec, getOffset, i, end); + scanReloc(sec, getOffset, i, rels.begin(), end); // Sort relocations by offset for more efficient searching for // R_RISCV_PCREL_HI20 and R_PPC64_ADDR64. Index: lld/test/ELF/ppc64-error-missing-tlsgdld.s =================================================================== --- /dev/null +++ lld/test/ELF/ppc64-error-missing-tlsgdld.s @@ -0,0 +1,53 @@ +# REQUIRES ppc +# RUN: llvm-mc %s --filetype=obj -o %t.o +# RUN: not ld.lld --shared %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK-NEXT: defined in {{.*}}.o +# CHECK-NEXT: referenced by {{.*}}.o:(.text+0x8) + +# CHECK: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK-NEXT: defined in {{.*}}.o +# CHECK-NEXT: referenced by {{.*}}.o:(.text+0x18) + +# CHECK: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK-NEXT: defined in {{.*}}.o +# CHECK-NEXT: referenced by {{.*}}.o:(.text+0x28) + +# CHECK: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK-NEXT: defined in {{.*}}.o +# CHECK-NEXT: referenced by {{.*}}.o:(.text+0x38) + +# CHECK: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK-NEXT: defined in {{.*}}.o +# CHECK-NEXT: referenced by {{.*}}.o:(.text+0x40) + +GeneralDynamic: + addis 3, 2, x@got@tlsgd@ha + addi 3, 3, x@got@tlsgd@l + bl __tls_get_addr + blr + + +GeneralDynamic_NOTOC: + addis 3, 2, x@got@tlsgd@ha + addi 3, 3, x@got@tlsgd@l + bl __tls_get_addr@notoc + blr + +LocalDynamic: + addis 3, 2, x@got@tlsld@ha + addi 3, 3, x@got@tlsld@l + bl __tls_get_addr + blr + + +LocalDynamic_NOTOC: + addis 3, 2, x@got@tlsld@ha + addi 3, 3, x@got@tlsld@l + bl __tls_get_addr@notoc + blr + +CallOnly: + bl __tls_get_addr + blr Index: lld/test/ELF/ppc64-error-missing-tlsgdld.test =================================================================== --- /dev/null +++ lld/test/ELF/ppc64-error-missing-tlsgdld.test @@ -0,0 +1,164 @@ +# REQUIRES: ppc +# RUN: yaml2obj --docnum=1 %s -o %t1.o -D CALL=R_PPC64_REL24 -D FUNC=LocalDynamic +# RUN: not ld.lld --shared %t1.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK1 +# RUN: yaml2obj --docnum=1 %s -o %t2.o -D CALL=R_PPC64_REL24_NOTOC -D FUNC=LocalDynamic_NOTOC +# RUN: not ld.lld --shared %t2.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK2 +# RUN: yaml2obj --docnum=2 %s -o %t3.o -D CALL=R_PPC64_REL24 -D FUNC=GeneralDynamic +# RUN: not ld.lld --shared %t3.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK3 +# RUN: yaml2obj --docnum=2 %s -o %t4.o -D CALL=R_PPC64_REL24_NOTOC -D FUNC=GeneralDynamic_NOTOC +# RUN: not ld.lld --shared %t4.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK4 +# RUN: yaml2obj --docnum=3 %s -o %t5.o +# RUN: not ld.lld --shared %t5.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK5 + + +# CHECK1: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK1-NEXT: defined in {{.*}}1.o +# CHECK1-NEXT: referenced by LocalDynamic.c +# CHECK1-NEXT: {{.*}}1.o:(LocalDynamic) + +# CHECK2: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK2-NEXT: defined in {{.*}}2.o +# CHECK2-NEXT: referenced by LocalDynamic_NOTOC.c +# CHECK2-NEXT: {{.*}}2.o:(LocalDynamic_NOTOC) +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_PPC64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000010 + Content: 00004C3C00004238A602087C100001F8E1FF21F80000623C0000633801000048000000600000633C0000803800006338010000480000006020002138100001E8A603087C2000804E000000000000000000000000 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .text + Relocations: + - Offset: 0x0000000000000014 + Symbol: x + Type: R_PPC64_GOT_TLSLD16_HA + - Offset: 0x0000000000000018 + Symbol: x + Type: R_PPC64_GOT_TLSLD16_LO + - Offset: 0x000000000000001C + Symbol: __tls_get_addr + Type: [[CALL]] + - Name: .tbss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ] + AddressAlign: 0x0000000000000004 + Size: 0x0000000000000004 +Symbols: + - Name: [[FUNC]].c + Type: STT_FILE + Index: SHN_ABS + - Name: x + Type: STT_TLS + Section: .tbss + Size: 0x0000000000000004 + - Name: [[FUNC]] + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Size: 0x0000000000000054 + Other: [ 96 ] + - Name: __tls_get_addr + Binding: STB_GLOBAL +... + +# CHECK3: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK3-NEXT: defined in {{.*}}3.o +# CHECK3-NEXT: referenced by GeneralDynamic.c +# CHECK3-NEXT: {{.*}}3.o:(GeneralDynamic) + +# CHECK4: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK4-NEXT: defined in {{.*}}4.o +# CHECK4-NEXT: referenced by GeneralDynamic_NOTOC.c +# CHECK4-NEXT: {{.*}}4.o:(GeneralDynamic_NOTOC) +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_PPC64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000010 + Content: 00004C3C00004238A602087C100001F8E1FF21F80000623C000063380100004800000060020063E820002138100001E8A603087C2000804E000000000000000000000000 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .text + Relocations: + - Offset: 0x0000000000000014 + Symbol: x + Type: R_PPC64_GOT_TLSGD16_HA + - Offset: 0x0000000000000018 + Symbol: x + Type: R_PPC64_GOT_TLSGD16_LO + - Offset: 0x000000000000001C + Symbol: __tls_get_addr + Type: [[CALL]] +Symbols: + - Name: [[FUNC]].c + Type: STT_FILE + Index: SHN_ABS + - Name: [[FUNC]] + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Size: 0x0000000000000044 + Other: [ 96 ] + - Name: __tls_get_addr + Binding: STB_GLOBAL + - Name: x + Type: STT_TLS + Binding: STB_GLOBAL +... + +# CHECK5: ld.lld: error: Call to __tls_get_addr is missing a R_PPC64_TLSGD/R_PPC64_TLSLD relocation. +# CHECK5-NEXT: defined in {{.*}}5.o +# CHECK5-NEXT: referenced by CallOnly.c +# CHECK5-NEXT: {{.*}}5.o:(CallOnly) +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_PPC64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000010 + Content: 00004C3C00004238A602087C100001F8E1FF21F80000623C0000633801000048000000600000633C0000803800006338010000480000006020002138100001E8A603087C2000804E000000000000000000000000 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .text + Relocations: + - Offset: 0x000000000000001C + Symbol: __tls_get_addr + Type: R_PPC64_REL24 +Symbols: + - Name: CallOnly.c + Type: STT_FILE + Index: SHN_ABS + Size: 0x0000000000000004 + - Name: CallOnly + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Size: 0x0000000000000054 + Other: [ 96 ] + - Name: __tls_get_addr + Binding: STB_GLOBAL +...