diff --git a/arch-x86-64.cc b/arch-x86-64.cc index 938f519c..4873adbc 100644 --- a/arch-x86-64.cc +++ b/arch-x86-64.cc @@ -410,7 +410,7 @@ void InputSection::apply_reloc_alloc(Context &ctx, u8 *base) { write(sym.esym().st_size + A); continue; case R_X86_64_TLSDESC_CALL: - if (ctx.arg.relax && !ctx.arg.shared) { + if (ctx.arg.is_static || (ctx.arg.relax && !ctx.arg.shared)) { // call *(%rax) -> nop loc[0] = 0x66; loc[1] = 0x90; @@ -644,7 +644,10 @@ void InputSection::scan_relocations(Context &ctx) { Fatal(ctx) << *this << ": GOTPC32_TLSDESC relocation is used" << " against an invalid code sequence"; - if (!ctx.arg.relax || ctx.arg.shared) + // TLSDESC relocs must be relaxed for a statically-linked executable + // even if -no-relax is given. It is because a statically-linked + // executable doesn't contain a tranpoline function needed for TLSDESC. + if (!ctx.arg.is_static && (!ctx.arg.relax || ctx.arg.shared)) sym.flags |= NEEDS_TLSDESC; break; case R_X86_64_TPOFF32: diff --git a/test/tlsdesc-static.sh b/test/tlsdesc-static.sh new file mode 100755 index 00000000..eb084913 --- /dev/null +++ b/test/tlsdesc-static.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -e +cd $(dirname $0) +mold=`pwd`/../mold +echo -n "Testing $(basename -s .sh $0) ... " +t=$(pwd)/tmp/$(basename -s .sh $0) +mkdir -p $t + +if [ $(uname -m) = x86_64 ]; then + dialect=gnu2 +elif [ $(uname -m) = aarch64 ]; then + dialect=desc +else + echo skipped + exit 0 +fi + +cat < + +extern _Thread_local int foo; + +int main() { + foo = 42; + printf("%d\n", foo); +} +EOF + +cat <