【问题标题】:How can I best pass a Global Offset Table (GOT) for my language on x86?如何在 x86 上最好地通过我的语言的全局偏移表 (GOT)?
【发布时间】:2010-10-10 04:49:03
【问题描述】:

我正在为我的语言编写一个小程序加载器,因为我放弃了理解 ELF 格式(在这样做的同时,我最终可能会更好地理解它)。我将文件映射到内存中,然后 tux 随心所欲..

我不想通过对程序进行任何更改来阻碍程序的共享。因此,我最终做了与 C 和 elf 相同的操作:全局偏移表。

问题是:我怎样才能通过我的程序的 GOT?

首先想到的是在寄存器或堆栈参数中提供它。在寄存器中它会很棒,但是 x86 被它的寄存器数量所阻碍。这可能意味着我将失去 ebx 或 ebp 或类似的东西。在一个合理的架构中,这将是一个公平的权衡。在 x86 中感觉有点失败。

共享库的反汇编显示 gcc 正在将其作为 IP 相对寻址。如果我这样做,它会是:

    call 0
here:
    pop eax
    ; do something with [eax + (got - here) + index*4]

不过,这在一定程度上感觉很复杂。我不喜欢这样做。

还有什么想法吗?

编辑:当使用多个库来处理这个问题时,我意识到:每个应用程序将有多个 GOT,并且某些 GOT 的使用取决于我所在的代码块。因此保持GOT 在单独的寄存器中将需要一些我不知道的额外技巧。我想知道他们在将 GOT 保存在寄存器中时如何解决这个问题。

【问题讨论】:

    标签: assembly x86 elf


    【解决方案1】:

    您可以使用段寄存器之一(或其基址)作为二进制映像的基址。所以你会参考你的全球数据,例如。作为FS:xxx。

    这些寄存器是所谓的分段内存模型的残余。基本上,段是具有指定基数(和限制)的线性地址空间的“窗口”,如果您使用它们进行寻址(例如,如果地址是 0010:00000001),则结果地址是(选择器为 0010 的段的基址) )+00000001。段的基数(以及其他参数)存储在描述符表中(还有更多),这是内存中的一个特殊区域。这些只能在内核模式下修改,Linux 中有系统调用可以做到这一点(modify_ldtarch_prctl)。在 64 位模式下,情况稍微复杂一些。

    有关参考,请参阅AMD64 architecture manual,尤其是第 2 卷:系统编程。

    【讨论】:

    • 我需要了解这些段寄存器。到目前为止,我已经忽略了它们作为遗产。
    • 其实64位模式下可以使用GS和FS。它们是平面寻址模式的例外。
    猜你喜欢
    • 2021-11-26
    • 2018-09-23
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 2017-03-24
    相关资源
    最近更新 更多