The*_*mad 0 assembly linker gdb glibc thread-local-storage
我glibc-2.27使用GDB. 在178in行sysdeps/unix/sysv/linux/getsysstats.c,存在一个thread local storage访问,如下图:
while (l < re && isspace (*l))
Run Code Online (Sandbox Code Playgroud)
IIUC,isspace()似乎访问了一个将字符映射到符号类型的表 ,以快速确定当前字符是否为空格。这张桌子似乎是一个. 相关拆解如下: ASCIITLS
0x7f8f9ef480de <__GI___get_nprocs+318> mov 0x2cbd1b(%rip),%rax # 0x7f8f9f213e00
0x7f8f9ef480e5 <__GI___get_nprocs+325> mov %fs:(%rax),%rdi
Run Code Online (Sandbox Code Playgroud)
rax包含0xffffffffffffff98,其中,IIUC,表示表的地址,对于每个线程,使用以下等式计算:$fs_base + 0xffffffffffffff98。当我使用这个等式来查找每个线程的表地址时,它们都返回相同的值0x00007f8f9732b82c。这如下所示:
(gdb) thread apply all x/2x $fs_base + 0xffffffffffffff98
Thread 47 (Thread 22457.22471):
0x7f8f75dfc698: 0x9732b82c 0x00007f8f
Thread 46 (Thread 22457.22470):
0x7f8f768fd698: 0x9732b82c 0x00007f8f
Thread 45 (Thread 22457.22469):
0x7f8f773fe698: 0x9732b82c 0x00007f8f
Thread 44 (Thread 22457.22468):
0x7f8f77eff698: 0x9732b82c 0x00007f8f
Thread 43 (Thread 22457.22467):
0x7f8f80a53698: 0x9732b82c 0x00007f8f
Thread 37 (Thread 22457.22465):
0x7f8f81c55698: 0x9732b82c 0x00007f8f
Thread 36 (Thread 22457.22464):
0x7f8f82456698: 0x9732b82c 0x00007f8f
Thread 35 (Thread 22457.22463):
0x7f8f8e6b0698: 0x9732b82c 0x00007f8f
Thread 34 (Thread 22457.22461):
0x7f8f8f480698: 0x9732b82c 0x00007f8f
Thread 33 (Thread 22457.22460):
0x7f8f94824698: 0x9732b82c 0x00007f8f
Thread 32 (Thread 22457.22459):
0x7f8f9649f698: 0x9732b82c 0x00007f8f
Thread 31 (Thread 22457.22458):
0x7f8f96ea0698: 0x9732b82c 0x00007f8f
Thread 30 (Thread 22457.22457):
0x7f8fa2570a18: 0x9732b82c 0x00007f8f
Thread 29 (Thread 22457.22466):
0x7f8f81454698: 0x9732b82c 0x00007f8f
Run Code Online (Sandbox Code Playgroud)
我以为TLS是独家给每个线程,但是,在这里,所有线程使用相同的变量0x00007f8f9732b82c。为什么会这样?似乎链接器识别了变量 isread-only并节省了一些空间?
您已经展示了每个线程在vs.等的TLS 存储中都有一个不同的指针变量。
0x7f8f75dfc698
0x7f8f768fd698
它们都指向同一个表的事实是完全正常的,除非您曾经uselocale(3)在不同的线程中使用不同的语言环境。
我认为 glibc 具有.section .rodata用于不同语言环境的静态常量 ( ) 字符映射表,并且它根据语言环境设置了一个指向正确表的指针。为每个线程复制整个表将非常低效,浪费更多 L3 缓存占用空间。如果要这样做,您会期望整个表就在那里,而没有间接级别。
看看 glibc 如何实现这样的功能isupper()- 通过索引字符属性标志数组,并检查该数组元素中的某个位。(即每个数组元素都是一个标志位图)。
https://code.woboq.org/userspace/glibc/ctype/ctype.h.html以及同一目录下的相关 .c 文件。