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 R_PPC64_TLSGD/R_PPC64_TLSLD before it. + if ((i - 1) == start) + errorOrWarn("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-tls-missing-gdld.s =================================================================== --- /dev/null +++ lld/test/ELF/ppc64-tls-missing-gdld.s @@ -0,0 +1,53 @@ +# REQUIRES ppc +# RUN: llvm-mc --triple=powerpc64le %s --filetype=obj -o %t1.o +# RUN: llvm-mc --triple=powerpc64 %s --filetype=obj -o %t2.o +# RUN: not ld.lld --shared %t1.o -o /dev/null 2>&1 | FileCheck %s +# RUN: not ld.lld --shared %t2.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