summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/SyntheticSections.cpp16
-rw-r--r--lld/test/ELF/mips-tls-64-pic-local-variable.s49
2 files changed, 63 insertions, 2 deletions
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 4195ed9a2e8..efaca97ede7 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -922,9 +922,17 @@ template <class ELFT> void MipsGotSection::build() {
continue;
InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
} else {
- if (!P.first->IsPreemptible)
+ // When building a shared library we still need a dynamic relocation
+ // for the module index. Therefore only checking for
+ // S->IsPreemptible is not sufficient (this happens e.g. for
+ // thread-locals that have been marked as local through a linker script)
+ if (!S->IsPreemptible && !Config->Pic)
continue;
InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ // However, we can skip writing the TLS offset reloc for non-preemptible
+ // symbols since it is known even in shared libraries
+ if (!S->IsPreemptible)
+ continue;
Offset += Config->Wordsize;
InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
}
@@ -1030,7 +1038,11 @@ void MipsGotSection::writeTo(uint8_t *Buf) {
if (P.first == nullptr && !Config->Pic)
Write(P.second, nullptr, 1);
else if (P.first && !P.first->IsPreemptible) {
- Write(P.second, nullptr, 1);
+ // If we are emitting PIC code with relocations we mustn't write
+ // anything to the GOT here. When using Elf_Rel relocations the value
+ // one will be treated as an addend and will cause crashes at runtime
+ if (!Config->Pic)
+ Write(P.second, nullptr, 1);
Write(P.second + 1, P.first, -0x8000);
}
}
diff --git a/lld/test/ELF/mips-tls-64-pic-local-variable.s b/lld/test/ELF/mips-tls-64-pic-local-variable.s
new file mode 100644
index 00000000000..04d916f42c6
--- /dev/null
+++ b/lld/test/ELF/mips-tls-64-pic-local-variable.s
@@ -0,0 +1,49 @@
+# REQUIRES: mips
+# MIPS TLS variables that are marked as local by a version script were previously
+# writing values to the GOT that caused runtime crashes. This was happending when
+# linking jemalloc_tsd.c in FreeBSD libc. Check that we do the right thing now:
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o
+# RUN: echo "{ global: foo; local: *; };" > %t.script
+# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
+# RUN: llvm-objdump --section=.got -s %t.so | FileCheck %s -check-prefix GOT
+# RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix RELOCS
+
+# GOT: Contents of section .got:
+# GOT-NEXT: 20000 00000000 00000000 80000000 00000000
+# GOT-NEXT: 20010 00000000 00000000 00000000 00000000
+# GOT-NEXT: 20020 ffffffff ffff8000
+
+# RELOCS: Section ({{.+}}) .rel.dyn {
+# RELOCS-NEXT: 0x20018 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE
+# RELOCS-NEXT: }
+
+# Test case generated using clang -mcpu=mips4 -target mips64-unknown-freebsd12.0 -fpic -O -G0 -EB -mabi=n64 -msoft-float -std=gnu99 -S %s -o %t.s
+# from the following source:
+#
+# _Thread_local int x;
+# int foo() { return x; }
+#
+ .text
+ .globl foo
+ .p2align 3
+ .type foo,@function
+ .ent foo
+foo:
+ lui $1, %hi(%neg(%gp_rel(foo)))
+ daddu $1, $1, $25
+ daddiu $gp, $1, %lo(%neg(%gp_rel(foo)))
+ ld $25, %call16(__tls_get_addr)($gp)
+ jalr $25
+ daddiu $4, $gp, %tlsgd(x)
+ .end foo
+
+ .type x,@object
+ .section .tbss,"awT",@nobits
+ .globl x
+ .p2align 2
+x:
+ .4byte 0
+ .size x, 4
+
+
OpenPOWER on IntegriCloud