[ELF][MIPS] Fix TLS GOT entries for local symbols in shared libraries
Summary: Previously LLD would not add any dynamic relocations and write a module index of 1 which is not correct for the shared library case. This can happen when a thread-local global variable is marked as local with a version script. With this change I am now able to link all of the FreeBSD base system for MIPS64 with LLD. Differential Revision: https://reviews.llvm.org/D48002 llvm-svn: 334483
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
49
lld/test/ELF/mips-tls-64-pic-local-variable.s
Normal file
49
lld/test/ELF/mips-tls-64-pic-local-variable.s
Normal file
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user