如何解释x86-64上的段寄存器访问?

8
使用此功能:
mov    1069833(%rip),%rax        # 0x2b5c1bf9ef90 <_fini+3250648>
add    %fs:0x0,%rax
retq

如何理解第二条指令,并找出添加到RAX中的内容?


3
假设您正在运行Linux操作系统,那么这个问题可能是相关的。 - user786653
2
可能是What does "DS:[40207A]" mean in assembly?的重复问题。 - Ciro Santilli OurBigBook.com
2个回答

9
这段代码:
mov    1069833(%rip),%rax        # 0x2b5c1bf9ef90 <_fini+3250648>
add    %fs:0x0,%rax
retq

这是返回线程局部变量地址。 %fs:0x0 是TCB(线程控制块)的地址,而1069833(%rip)是从该地址到变量的偏移量,由于该变量位于程序或在程序加载时加载的某个动态库中(通过dlopen()在运行时加载的库需要一些不同的代码),所以已知。

Ulrich Drepper的TLS文档中详细解释了这一点,特别是§4.3和§4.3.6。


3

我不确定自从分段式架构的不良旧日以来是否还称它们为寄存器。我认为正确的术语应该是选择器(但我可能是错的)。

然而,我认为你只需要在fs区域的第一个四元组(64位)。

%fs:0x0位表示fs:0处内存的内容。由于你使用了通用的add(而不是例如addl),我认为它将从目标%rax中获取数据宽度。

关于获取实际值,这取决于您是在传统模式还是长模式下。

在传统模式下,您需要获取fs值并在GDT(或可能是LDT)中查找以获取基地址。

在长模式下,您需要查看相关的模型特定寄存器。如果您到达了这个点,恐怕已经超出了我的专业水平。


我也想到了,但是我如何从选择器中获取实际地址呢?我没有运行的进程,只有一个核心转储。 - Alex B
是的,选择器是索引(除了其他一些东西,比如指定LDT/GDT的标志,从内存中读取)。你必须知道GDT/LDT在哪里,我不完全确定您是否可以从寄存器信息中获取它。 - paxdiablo
1
如果你担心你处于长模式,我甚至更担心我无法再为你提供更多帮助 :-) - paxdiablo
“坏老时代”是指8x86还是8x286?我认为8x86段非常出色;即使在今天,如果x86架构有一个模式,它可以像虚拟8086模式一样工作,但使用32位而不是16位段寄存器,那么类似.NET框架的东西将能够使用32位对象引用访问64GB内存,这应该是一个相当大的“胜利”。如果可以使用32位值的前4位来选择其中一个具有独立基地址和缩放因子的16个逻辑段中的一个,则可寻址内存将更大。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接