tls
线程本地存储
Linux的glibc使用GS寄存器来访问TLS,GS指向TEB,gs寄存器在线程切换时并不改变,而是采用更改相应偏移中内容,来切换。
另外对于线程来说,他的栈是有限的,是用过mmap创建的。
这是我修改过用来测试的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <stdlib.h> #include <stdio.h> #include <malloc.h> #include <string.h> #include <pthread.h> __thread int var = 0; // var定义为线程变量,每个数线拥有一份,这玩意不初始化在tbss,初始化在tdata
void* worker(void* arg);
int main(){ pthread_t pid1,pid2;
pthread_create(&pid1,NULL,worker,(void *)0); pthread_create(&pid2,NULL,worker,(void *)1);
pthread_join(pid1,NULL); pthread_join(pid2,NULL);
return 0; } void* worker(void* arg){ int idx = (int)arg; int i=0; int j=0; int e=0; while(1) { i++; j++;
e++; var++; asm volatile("mov %fs:0,%rax;"); } }
|
TLS如下
1 2 3 4 5 6 7 8 9 10 11
| 线程2的tls如下 0x7ffff77ef700是fs:[0]可以看到他指向自己,在栈底(这个偏移是固定的,如果找不到地址,那么从栈底往上找一下就好) 0x7ffff77ef6f0: 0x0000000000000000 0x0003cb0300000000 0x7ffff77ef700: 0x00007ffff77ef700 0x0000000000602020 0x7ffff77ef710: 0x00007ffff77ef700 0x0000000000000001 0x7ffff77ef720: 0x0000000000000000 0x3388f717cab24000 0x7ffff77ef730: 0x86ad80d7b8682fb4 0x0000000000000000 0x7ffff77ef740: 0x0000000000000000 0x0000000000000000 0x7ffff77ef750: 0x0000000000000000 0x0000000000000000 0x7ffff77ef760: 0x0000000000000000 0x0000000000000000 0x7ffff77ef770: 0x0000000000000000 0x0000000000000000
|
创建线程后的栈
1 2 3 4 5 6 7 8
| 主线程 RBP 0x7fffffffded0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15 RSP 0x7fffffffdeb0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
thread1 *RBP 0x7ffff77eef50 ◂— 0x0 *RSP 0x7ffff77eef50 ◂— 0x0
|
内存如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 0x400000 0x401000 r-xp 1000 0 /home/j/2 0x600000 0x601000 r--p 1000 0 /home/j/2 0x601000 0x602000 rw-p 1000 1000 /home/j/2 0x602000 0x623000 rw-p 21000 0 [heap] 0x7ffff6fef000 0x7ffff6ff0000 ---p 1000 0 0x7ffff6ff0000 0x7ffff77f0000 rw-p 800000 0 0x7ffff77f0000 0x7ffff79b0000 r-xp 1c0000 0 /lib/x86_64-linux-gnu/libc-2.23.so 0x7ffff79b0000 0x7ffff7bb0000 ---p 200000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so 0x7ffff7bb0000 0x7ffff7bb4000 r--p 4000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so 0x7ffff7bb4000 0x7ffff7bb6000 rw-p 2000 1c4000 /lib/x86_64-linux-gnu/libc-2.23.so 0x7ffff7bb6000 0x7ffff7bba000 rw-p 4000 0 0x7ffff7bba000 0x7ffff7bd2000 r-xp 18000 0 /lib/x86_64-linux-gnu/libpthread-2.23.so 0x7ffff7bd2000 0x7ffff7dd1000 ---p 1ff000 18000 /lib/x86_64-linux-gnu/libpthread-2.23.so 0x7ffff7dd1000 0x7ffff7dd2000 r--p 1000 17000 /lib/x86_64-linux-gnu/libpthread-2.23.so 0x7ffff7dd2000 0x7ffff7dd3000 rw-p 1000 18000 /lib/x86_64-linux-gnu/libpthread-2.23.so 0x7ffff7dd3000 0x7ffff7dd7000 rw-p 4000 0 0x7ffff7dd7000 0x7ffff7dfd000 r-xp 26000 0 /lib/x86_64-linux-gnu/ld-2.23.so 0x7ffff7fdb000 0x7ffff7fdf000 rw-p 4000 0 0x7ffff7ff8000 0x7ffff7ffa000 r--p 2000 0 [vvar] 0x7ffff7ffa000 0x7ffff7ffc000 r-xp 2000 0 [vdso] 0x7ffff7ffc000 0x7ffff7ffd000 r--p 1000 25000 /lib/x86_64-linux-gnu/ld-2.23.so 0x7ffff7ffd000 0x7ffff7ffe000 rw-p 1000 26000 /lib/x86_64-linux-gnu/ld-2.23.so 0x7ffff7ffe000 0x7ffff7fff000 rw-p 1000 0 0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack] 0xffffffffff600000 0xffffffffff601000 r-xp 1000 0 [vsyscall]
|
worker代码,可以看到,对于thread类的变量,使用fs来存储的,
1 2 3
| mov eax, dword ptr fs:[0xfffffffffffffffc] ► 0x4007e4 <worker+36> add eax, 1 0x4007e7 <worker+39> mov dword ptr fs:[0xfffffffffffffffc], eax
|