【问题标题】:How to interpret segment register accesses on x86-64?如何解释 x86-64 上的段寄存器访问?
【发布时间】:2011-12-12 07:08:39
【问题描述】:

使用此功能:

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

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

【问题讨论】:

标签: linux assembly x86 x86-64


【解决方案1】:

我不确定自从分段架构的糟糕旧时代以来它们是否被称为 segment register。我相信正确的术语是选择器(但我可能是错的)。

但是,我认为您只需要在fs 区域中的第一个四字(64 位)。

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

就获得实际价值而言,这取决于您是处于 legacy 模式还是 long 模式。

在旧模式下,您必须获取 fs 值并在 GDT(或可能是 LDT)中查找它才能获取基地址。

在长模式下,您需要查看相关模型特定的寄存器。如果您处于这一点,那么不幸的是,您已经超出了我的专业水平。

【讨论】:

  • 我想了很多,但是如何从选择器中获取实际地址?我没有正在运行的进程,只有核心转储。
  • 是的,选择器是索引(除其他外,例如指定 LDT/GDT 的标志,来自内存)。你必须知道 GDT/LDT 在哪里,我不完全确定你真的可以从注册信息中得到。
  • 如果您担心自己处于长时间模式,我什至 更多 担心我无法进一步帮助您 :-)
  • “糟糕的过去”是指 8x86 还是 8x286?我认为 8x86 段非常棒。即使在今天,如果 x86 架构有一种工作方式类似于虚拟 8086 模式但使用 32 位而不是 16 位段寄存器的模式,那么像 .NET 框架之类的东西将能够使用 32 位对象引用访问 64GB 内存,我预计这将是一个相当大的“胜利”。如果可以使用 32 位值的前 4 位来选择 16 个逻辑段之一,每个逻辑段都有独立的基地址和比例因子,那么“平滑”可寻址内存可能会更大。
【解决方案2】:

这段代码:

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

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

Ulrich Drepper 的 TLS document 对此进行了详细解释,特别是 §4.3 和 §4.3.6。

【讨论】:

    猜你喜欢
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    相关资源
    最近更新 更多