当前位置: 首页 > 知识库问答 >
问题:

为什么gdb中的数据段寄存器总是空的?

慕乐语
2023-03-14

为什么数据段寄存器(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将如何引用线程的TCB(tcbhead_t)来获取TLS和其他重要内容。所以这不是意味着每个线程都需要一个唯一的描述符条目吗?每个线程不应该对fs寄存器有一个唯一的值吗?我甚至不相信0x0是一个有效的选择器,因为TI(表指示符)位将指示GDT,我认为没有有效的0 GDT条目。

我知道我一定错过了一些明显的东西,有人知道是什么吗?

环境: CentOS 6.6,x86_64

共有3个答案

洪富
2023-03-14

我认为这是由内核完成的:检查函数start\u thread\u common(),然后您将发现以下内容:

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

对于x86 64,\u ds为0。为什么\u ds是0,因为它完全无用。以下内容摘自Intel SDM v3。

3.2.4 IA-32e模式下的分割

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

宋俊民
2023-03-14

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

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

否。fs寄存器的值是相同的,但它指向的内存在每个线程中都不同。请参阅手册页和在GLIBC source中设置此选项的代码。

刘曾琪
2023-03-14

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

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

标准机制是编写MSR(模型特定寄存器);请参阅有关linux x86 64中MSR\U GS\U BASE的详细信息。

英特尔自IvyBridge以来一直支持FSGSBASE功能,但显然Linux只是最近才利用wrfsbase指令,它比WRMSR方法更快。看见https://lwn.net/Articles/769355/.

除了比wrmsr更快之外,wrfsbase还增加了内核可以让用户空间执行它的功能,因此用户空间中的VM(如Java)可能会利用它,而不需要为始终具有特权的WRMSR指令进行系统调用

 类似资料:
  • 我已经彻底研究了所有的问题,但没有一个直接适用于我的问题。我正在循环访问用户ID数组并匹配它们以从我的firestore DB中获得一个用户。我会毫无问题地返回结果,但当我将其存储在状态数组中并运行控制台日志时,我的状态数组总是空的。第一个console.log工作并显示DB的结果。 请帮帮忙。

  • 我正在学习将C转换为汇编,然后我发现数据存储在4字节寄存器中。 注意:我使用编译C,使用gdb!另外,我的电脑是64位的。 下面是关于char的代码,对应于assembly(我认为short和char是同一个问题,所以我放两个代码中的一个): 反汇编代码的一部分! 我学习了一些关于java数据类型的知识,隐马尔可夫模型,比如字节,字符,或者短代码被提升为int。我不确定他们有什么关系。

  • 3、段寄存器的引用 段寄存器是因为对内存的分段管理而设置的。16位CPU有四个段寄存器,所以,其程序可同时访问四个不同含义的段。段寄存器及其偏移量的引用关系如图2.7所示。 段寄存器CS指向存放程序的内存段,IP是用来存放下条待执行的指令在该段的偏移量,把它们合在一起可在该内存段内取到下次要执行的指令。 段寄存器SS指向用于堆栈的内存段,SP是用来指向该堆栈的栈顶,把它们合在一起可访问栈顶单元。另

  • 在Kotlin中,您可以创建: 然后可以使用它解析JSON,例如“{n:10}”。在这种情况下,您将有一个对象,从、或接收,它包含以下值:。 在Kotlin+GSON-How to get a emptyList when null for data类中,您可以看到另一个示例。 当您以后尝试使用时,您将在这里得到一个异常::“Kotlin.TypeCastException:null不能被强制转换

  • 在我的机器上发出命令时(断点在上),输出如下: 根据我对此答案的理解,< code>eip和< code>ebp寄存器(不在我的输出中)具有以下含义: eip是下一条要执行的指令的寄存器(也称为程序计数器) “ebp”是寄存器,通常被认为是这个堆栈帧的局部地址的起始地址,它使用“偏移量”来寻址 从另一个答案中,我明白了 [RIP是]指令指针 [...] 其中一些寄存器被设想用于特定用途,并且通常都

  • 我必须编写一个名为productOfPrevious的方法,它接受一个整数数组,并返回一个与输入大小相同的整数数组。返回数组中的每个单元格都是该单元格与前面所有单元格的乘积。 这是我的密码。但我不知道为什么输出数组中的元素总是为零。 输入:{1,2,3,4,5} 我需要的输出:{1,2,6,24,120} 我获得的输出:{0,0,0,0,0} 我的代码有什么问题吗?