我正在为我的语言编写一个小程序加载器,因为我放弃了对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保存在寄存器中时解决这个问题。
答案 0 :(得分:1)
您可以使用其中一个段寄存器(或其基础)作为二进制映像的基础。所以你会参考你的全球数据,例如。作为FS:xxx。
这些寄存器是所谓的分段存储器模型的残余。基本上,段是指向具有指定基数(和限制)的线性地址空间的“窗口”,如果使用它们进行寻址,(例如,如果地址是0010:00000001),则生成的地址是(带有选择器0010的段的基数) )00000001。段的基数(以及其他参数)存储在描述符表中(有更多这些),这是内存中的特殊区域。这些只能在内核模式下修改,linux中有系统调用执行此操作(modify_ldt
,arch_prctl
)。在64位模式下,情况稍微复杂一些。
有关参考,请参阅AMD64 architecture manual,尤其是第2卷:系统编程。