为什么数据段寄存器在gdb中始终为空?

时间:2015-01-29 07:57:31

标签: gdb x86-64 glibc

为什么数据段寄存器(ds / es / fs / gs)似乎总是在GDB中显示为0x0?例如,无论我看到什么过程或线程,“info reg”似乎总是给我这样的输出:

cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0

我正在尝试调试glibc代码,我在我正在拆解的函数中看到fs段前缀:

(gdb) disas __lll_lock_wait
Dump of assembler code for function __lll_lock_wait:
0x000000302800e240 <+0>:     push   %r10
0x000000302800e242 <+2>:     push   %rdx
0x000000302800e243 <+3>:     xor    %r10,%r10
0x000000302800e246 <+6>:     mov    $0x2,%edx
0x000000302800e24b <+11>:    xor    $0x80,%esi
0x000000302800e251 <+17>:    and    %fs:0x48,%esi
0x000000302800e259 <+25>:    cmp    %edx,%eax
0x000000302800e25b <+27>:    jne    0x302800e264 <__lll_lock_wait+36>
0x000000302800e25d <+29>:    mov    $0xca,%eax

我知道这就是glibc将如何为TLS和其他重要内容引用线程的TCB(tcbhead_t)。那么这是不是意味着每个线程都需要才能拥有唯一的描述符条目?每个线程不应该具有fs寄存器的唯一值吗?我甚至不相信0x0是一个有效的选择器,因为TI(表指示符)位将指示GDT,我认为没有有效的0 GDT条目。

我知道我必须遗漏一些明显的东西,任何人都知道它是什么?

环境:CentOS 6.6,x86_64

3 个答案:

答案 0 :(得分:2)

  

每个线程的fs寄存器都没有唯一的值吗?

否,每个线程都需要一个唯一的FS段基,但对于每个可能的基都不需要LDT或GDT条目,内核有一种机制可以直接在内部段描述符中直接设置FS基地址,而无需使用较慢的mov fs, eax指令来加载整个段说明,包括权限和内容。

标准机制是编写MSR(特定于模型的寄存器);参见Detail about MSR_GS_BASE in linux x86 64

Intel自IvyBridge支持FSGSBASE功能以来,但显然Linux仅在最近才利用the wrfsbase instruction,它比WRMSR方法要快。参见https://lwn.net/Articles/769355/

wrmsr除了比wrfsbase更快之外,还具有内核可以让用户空间执行它的附加功能,因此,用户空间中的VM(例如Java)可以代替使用需要对始终特权的WRMSR指令进行系统调用的方法。

答案 1 :(得分:1)

  

那么这不意味着每个线程都需要一个唯一的描述符条目吗?

  

每个线程不应该有fs寄存器的唯一值吗?

没有。 fs寄存器的值是相同的,但它指向的内存在每个线程中都是不同的。请参阅arch_prctl(2) man page和代码,以便在GLIBC source中进行设置。

答案 2 :(得分:1)

我认为它是由内核完成的: 检查函数start_thread_common(),然后会发现以下内容:

    loadsegment(fs, 0); 
    loadsegment(es, _ds);
    loadsegment(ds, _ds);
    load_gs_index(0);

对于x86 64,_ds为0。为什么_ds为0,因为它完全没有用。以下是来自英特尔SDM v3的信息。

  

3.2.4在IA-32e模式下进行细分

     

在Intel 64架构的IA-32e模式下,分段的效果取决于是否   处理器以兼容模式或64位模式运行。在   兼容模式,分段功能与使用   传统的16位或32位保护模式语义。在64位模式下,   细分通常(但不是完全)禁用,从而创建了   平面64位线性地址空间。处理器对待段   CS,DS,ES,SS的基数为零,创建一个线性地址   等于有效地址。 FS和GS段是例外。   这些段寄存器(保存段基)可以用作   线性地址计算中的其他基址寄存器。他们   有助于处理本地数据和某些操作系统数据   结构。