Skip to content

Commit

Permalink
[ELF] Fix _TLS_MODULE_BASE_ relocations
Browse files Browse the repository at this point in the history
Fixes #421
  • Loading branch information
rui314 committed Apr 8, 2022
1 parent 2fc0231 commit 5feab82
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 13 deletions.
10 changes: 0 additions & 10 deletions elf/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -662,16 +662,6 @@ static int elf_main(int argc, char **argv) {

// At this point, file layout is fixed.

// Some types of TLS relocations are defined relative to the beginning
// or the end of the TLS segment address. Find these addresses now.
for (ElfPhdr<E> phdr : create_phdr(ctx)) {
if (phdr.p_type == PT_TLS) {
ctx.tls_begin = phdr.p_vaddr;
ctx.tls_end = align_to(phdr.p_vaddr + phdr.p_memsz, phdr.p_align);
break;
}
}

t_before_copy.stop();

// Create an output file
Expand Down
9 changes: 8 additions & 1 deletion elf/output-chunks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ std::vector<ElfPhdr<E>> create_phdr(Context<E> &ctx) {
i++;
while (i < ctx.chunks.size() && (ctx.chunks[i]->shdr.sh_flags & SHF_TLS))
append(ctx.chunks[i++]);

// Some types of TLS relocations are defined relative to the TLS
// segment, so save its addresses for easy access.
ElfPhdr<E> &phdr = vec.back();
ctx.tls_begin = phdr.p_vaddr;
ctx.tls_end = align_to(phdr.p_vaddr + phdr.p_memsz, phdr.p_align);
}

// Add PT_DYNAMIC
Expand Down Expand Up @@ -1067,7 +1073,8 @@ std::vector<GotEntry<E>> GotSection<E>::get_entries(Context<E> &ctx) const {

if constexpr (E::supports_tlsdesc)
for (Symbol<E> *sym : tlsdesc_syms)
entries.push_back({sym->get_tlsdesc_idx(ctx), 0, E::R_TLSDESC, sym});
entries.push_back({sym->get_tlsdesc_idx(ctx), 0, E::R_TLSDESC,
sym == ctx._TLS_MODULE_BASE_ ? nullptr : sym});

for (Symbol<E> *sym : gottp_syms) {
i64 idx = sym->get_gottp_idx(ctx);
Expand Down
16 changes: 14 additions & 2 deletions elf/passes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1473,8 +1473,20 @@ void fix_synthetic_symbols(Context<E> &ctx) {
start(ctx._GLOBAL_OFFSET_TABLE_, ctx.got);

// _TLS_MODULE_BASE_
if constexpr (E::supports_tlsdesc)
ctx._TLS_MODULE_BASE_->value = ctx.tls_begin;
if constexpr (E::supports_tlsdesc) {
u64 addr;
if constexpr (std::is_same_v<E, X86_64> || std::is_same_v<E, I386>) {
if (ctx.arg.relax && !ctx.arg.shared)
addr = ctx.tls_end;
else
addr = ctx.tls_begin;
} else {
addr = ctx.tls_begin;
}

ctx._TLS_MODULE_BASE_->shndx = -1;
ctx._TLS_MODULE_BASE_->value = addr;
}

// __GNU_EH_FRAME_HDR
start(ctx.__GNU_EH_FRAME_HDR, ctx.eh_frame_hdr);
Expand Down
57 changes: 57 additions & 0 deletions test/elf/tls-module-base.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash
export LC_ALL=C
set -e
CC="${CC:-cc}"
CXX="${CXX:-c++}"
GCC="${GCC:-gcc}"
GXX="${GXX:-g++}"
OBJDUMP="${OBJDUMP:-objdump}"
MACHINE="${MACHINE:-$(uname -m)}"
testname=$(basename "$0" .sh)
echo -n "Testing $testname ... "
cd "$(dirname "$0")"/../..
mold="$(pwd)/mold"
t=out/test/elf/$testname
mkdir -p $t

[ $MACHINE = x86_64 ] || { echo skipped; exit; }

cat <<EOF | $CC -o $t/a.o -c -xassembler -
.globl get_foo
get_foo:
lea _TLS_MODULE_BASE_@TLSDESC(%rip), %rax
call *_TLS_MODULE_BASE_@TLSCALL(%rax)
lea foo@dtpoff(%rax), %rax
mov %fs:(%rax), %eax
ret
.section .tdata, "awT", @progbits
foo:
.long 20
EOF

cat <<EOF | $CC -o $t/b.o -c -xc -
_Thread_local int bar = 3;
EOF

cat <<EOF | $CC -o $t/c.o -c -xc -
#include <stdio.h>
int get_foo();
extern _Thread_local int bar;
int main() {
printf("%d %d\n", get_foo(), bar);
}
EOF

$CC -B. -o $t/exe1 $t/a.o $t/b.o $t/c.o
$QEMU $t/exe1 | grep -q '^20 3$'

$CC -B. -o $t/exe2 $t/a.o $t/b.o $t/c.o -Wl,-no-relax
$QEMU $t/exe2 | grep -q '^20 3$'

$CC -B. -o $t/d.so $t/a.o -shared
$CC -B. -o $t/exe3 $t/b.o $t/c.o $t/d.so
$QEMU $t/exe3 | grep -q '^20 3$'

echo OK

0 comments on commit 5feab82

Please sign in to comment.