diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/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,29 @@ int64_t addend = computeAddend(rel, end, sec, expr, sym.isLocal()); if (config->emachine == EM_PPC64) { + // For a call to __tls_get_addr, the instruction needs to be relocated by + // two relocations, R_PPC64_TLSGD/R_PPC64_TLSLD and R_PPC64_REL24[_NOTOC] + 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 preceded + // by a R_PPC64_TLSGD/R_PPC64_TLSLD. + bool err = i - start < 2; + if (!err) { + // 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); + err = prevRel.r_offset != rel.r_offset || + (prevType != R_PPC64_TLSGD && prevType != R_PPC64_TLSLD); + } + + if (err) + 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 +1525,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. diff --git a/lld/test/ELF/ppc64-tls-missing-gdld.s b/lld/test/ELF/ppc64-tls-missing-gdld.s new file mode 100644 --- /dev/null +++ b/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