一 什么是TLS
TLS英文全称Thread local Storage,准确的定义是 a computer programming method that uses static or global memory local to a thread。在线程中使用的全局或者static变量,在线程中本地复制一份。最常见的使用场景是errno。每个线程有一份本地的errno,线程间彼此不影响。在bionic中errno的定义:
int* __errno(void) __attribute_const__;
#define errno (*__errno())
attribute_const const 告诉编译器某个函数是无状态的(也就是说,它使用传递给它的参数生成要返回的结果)。The const function attribute specifies that a function examines only its arguments, and has no effect except for the return value. That is, the function does not read or modify any global memory.// attribute((const)) functions do not read or modify any global memory。
// attribute((const)) functions do not read or modify any global memory
还有就是使用
__thread int number;
thread_local int tls_var;
二 TLS的位置
在elf中,tls变量存储在elf的tbss和tdata段

像其他变量一样,TLS也可以动态链接,如果这样的话,TLS变量将会出现在符号表,相关的type类型为STT_TLS,存储位置:

在ARM运行时相关的tls的加载地址为:

DTV为dynmic thread vector,向量保存着tls的存储位置。
三 bionic中的TLS处理
目前bionic不支持ELF TLS,因此在编译时使用了-emulated-tls,相关的soong代码如下:
// Work around bug in Clang that doesn't pass correct emulated
// TLS option to target. See b/72706604 or
// https://github.com/android-ndk/ndk/issues/498.
flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls")
libc中相关的处理,对于tls的
if (ELF_ST_TYPE(s->st_info) == STT_TLS) {
DL_ERR("unsupported ELF TLS symbol \"%s\" referenced by \"%s\"",
sym_name, get_realpath());
return false;
}
if (!relocating_linker) {
if (d->d_tag == DT_TLSDESC_GOT || d->d_tag == DT_TLSDESC_PLT) {
DL_ERR("unsupported ELF TLS DT entry in \"%s\"", get_realpath());
return false;
}
对于errno处理比较特殊,专门放到了tcb中,相关的代码如下:
// Well-known TLS slots. What data goes in which slot is arbitrary unless otherwise noted.
enum {
TLS_SLOT_SELF = 0, // The kernel requires this specific slot for x86.
TLS_SLOT_THREAD_ID,
TLS_SLOT_ERRNO,
// These two aren't used by bionic itself, but allow the graphics code to
// access TLS directly rather than using the pthread API.
TLS_SLOT_OPENGL_API = 3,
TLS_SLOT_OPENGL = 4,
// This slot is only used to pass information from the dynamic linker to
// libc.so when the C library is loaded in to memory. The C runtime init
// function will then clear it. Since its use is extremely temporary,
// we reuse an existing location that isn't needed during libc startup.
TLS_SLOT_BIONIC_PREINIT = TLS_SLOT_OPENGL_API,
TLS_SLOT_STACK_GUARD = 5, // GCC requires this specific slot for x86.
TLS_SLOT_DLERROR,
// Fast storage for Thread::Current() in ART.
TLS_SLOT_ART_THREAD_SELF,
// Lets TSAN avoid using pthread_getspecific for finding the current thread
// state.
TLS_SLOT_TSAN,
BIONIC_TLS_SLOTS // Must come last!
};
int* __errno() {
return reinterpret_cast<int*>(&(__get_tls()[TLS_SLOT_ERRNO]));
}
但是从android 10.0的最新代码看,ELF TLS支持已经添加进去。
网友评论