Page MenuHomeFreeBSD

rtld-elf/aarch64: Avoid checks for UND symbols when processing TPREL64
ClosedPublic

Authored by markj on Jul 5 2021, 8:39 PM.
Tags
None
Referenced Files
F83129862: D31069.diff
Mon, May 6, 5:42 PM
F83110219: D31069.diff
Mon, May 6, 10:14 AM
Unknown Object (File)
Jan 15 2024, 11:04 AM
Unknown Object (File)
Jan 14 2024, 4:40 AM
Unknown Object (File)
Dec 23 2023, 7:26 PM
Unknown Object (File)
Dec 20 2023, 8:07 AM
Unknown Object (File)
Oct 31 2023, 12:03 AM
Unknown Object (File)
Oct 31 2023, 12:03 AM

Details

Summary

lld emits several such relocations against the GOT in libc.so when
compiled with -ftls-model=initial-exec. They reference the null symbol,
not weak symbols. The warnings emitted by rtld make the system
unusable.

I don't see any reason to have special handling for relocations
referencing undefined weak thread-local symbols, as we don't do anything
special on other platforms.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

markj requested review of this revision.Jul 5 2021, 8:39 PM

I clearly miss something. If the symbol is undefined, what is def->st_value, isn't it undefined?

And what are these symbols?

In D31069#698774, @kib wrote:

I clearly miss something. If the symbol is undefined, what is def->st_value, isn't it undefined?

And what are these symbols?

This is like R_FOO_RELATIVE; relocations with r_sym 0 will be against the null symbol (NOTYPE, LOCAL, DEFAULT, UND) with an addend, for code like:

static __thread x;

where you know at link time the offset of x within your static TLS section and just want to add on at load time the offset of the module's static TLS section within the whole static TLS block.

jrtc4@zeno:~/cheri/cheribsd$ echo 'static __thread int x, y; int foo(void) { return x + y; }' | cheri-llvm clang -target aarch64-unknown-freebsd --sysroot ~/cheri/output/rootfs-aarch64 -x c - -o - -ftls-model=initial-exec -fPIC -shared | cheri-llvm llvm-readelf -Wr - | grep TPREL
0000000000020808  0000000000000406 R_AARCH64_TLS_TPREL64             0
0000000000020810  0000000000000406 R_AARCH64_TLS_TPREL64             4
This revision is now accepted and ready to land.Jul 5 2021, 9:51 PM

So what is the value of this symbol (st_value)? Zero?

In D31069#698795, @kib wrote:

So what is the value of this symbol (st_value)? Zero?

Right, the first symbol table entry is required by the ELF spec to be undefined and have value zero.

However, the ELF definition also requires that the address of the undefined weak thread local symbol be translated to NULL. Additionally, I have seen code that relied on this. Unfortunately, because of aarch64's "unique" way of accessing TLS variables, I haven't found a way to implement this.
Wouldn't it be better to narrow down the cases where a message is printed, rather than allowing invalid and unreported behavior?

For clarification, I meant this:

#include <stdio.h>
extern __thread int foo __attribute__((weak));

int main(void)
{
 printf("address is: %p\n", &foo);
 return(0);
}

IE (and LE) TLS are fundamentally incompatible with weak undef symbols. This is not an AArch64 problem; TLSDESC is only concerned with dynamic TLS, not static TLS, as a way to optimise dynamic TLS at load time in the common case (and, incidentally, does exist for amd64, i386 and arm for you to enable in the compiler). The static TLS model is tp + static_offset, and there is no way to make the computation be zero in every thread; you can have at most one.

If you wanted to give an error here you could (ELF_R_SYM(rela->r_info) != 0 && def->st_shndx == SHN_UNDEF, or abuse sym_zero like powerpc(64) already do and just do def == &sym_zero), but all other architectures would be equally deserving of one, there is no reason to single AArch64 out here.

For TLSDESC you want to do what's already done and map r_sym != 0 undef symbols to a special resolver.

jrtc4@zeno:~/cheri/cheribsd$ clang -x c -
#include <stdio.h>
extern __thread int foo __attribute__((weak));

int main(void)
{
 printf("address is: %p\n", &foo);
 return(0);
}
jrtc4@zeno:~/cheri/cheribsd$ ./a.out 
address is: 0x8002458d0
jrtc4@zeno:~/cheri/cheribsd$ file a.out 
a.out: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, for FreeBSD 12.2, FreeBSD-style, with debug_info, not stripped

That code is broken everywhere, it's never been supported on any architecture.

And on Linux with glibc to prove it's not a FreeBSD bug:

burn:tmp jrtc4% gcc -x c -
#include <stdio.h>
extern __thread int foo __attribute__((weak));

int main(void)
{
 printf("address is: %p\n", &foo);
 return(0);
}
burn:tmp jrtc4% file a.out                                                     
a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=e1f183a895640f4f3d52d9481df88caaa08816aa, not stripped
burn:tmp jrtc4% ./a.out                                                                                                                 
address is: 0x7fed139d64c0