2

我正在为我的语言编写一个小程序加载器,因为我放弃了理解 ELF 格式(在这样做的同时,我最终可能会更好地理解它)。我将文件映射到内存中,然后无尾礼服欢欣鼓舞。

我不想通过对其进行任何更改来阻碍程序的共享。因此,我最终做了与 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 保存在寄存器中时如何解决这个问题。

4

1 回答 1

1

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

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

如需参考,请参阅AMD64 架构手册,尤其是第 2 卷:系统编程。

于 2009-02-26T21:37:50.730 回答