以下x86汇编程序指令有什么作用?
call dword ptr ds:[00923030h]
这是我怀疑的间接电话,但它究竟是如何计算电话的地址的呢?
答案 0 :(得分:17)
[编辑]已更新
每当您看到类似ds:0x00923030
的内存操作数时,就是段相对寻址模式。被引用的实际地址tp是相对于ds
段寄存器的基址的线性地址0x00923030。
x86架构中的内存分段有些令人困惑,我认为Wikipedia可以很好地解释它。
基本上,x86有许多特殊的段寄存器:cs
(代码段),ds
(数据 segment),es
,fs
,gs
和ss
( stack 段)。每个存储器访问都与某个段寄存器相关联。通常,您不指定段寄存器,并且根据访问存储器的方式,使用默认段寄存器。例如,cs
寄存器用于读取指令。
每个段寄存器都有一个基地址和限制。基址确定线性地址0x00000000对应的物理地址,并且该限制确定该段的最大允许线性地址。例如,如果基址为0x00040000且限制为0x0000FFFF,则唯一有效的线性地址为0x00000000至0x0000FFFF,相应的物理地址为0x00040000至0x0004FFFF。
因此,被调用子程序所在的物理地址由存储在ds
段寄存器中的基地址加上0x00923030给出。但是我们还没有完成 - 指令里面有ptr
这个词。这增加了额外的间接级别,因此子例程的实际目标是位于ds:0x00923030
的存储的地址。
在AT& T语法中(由GNU汇编程序接受),该指令将按如下方式编写:
lcall *ds:0x00923030
有关该指令的完整详细信息,请参阅80386 reference manual。指令的这个特定变体是"CALL r/m16"
(调用接近寄存器间接/内存间接)。
答案 1 :(得分:10)
此特定操作码通过位于逻辑地址ds:[00923030h]
指向的位置的虚拟地址(此处为32位)进行调用。
逻辑地址由两部分组成:
请注意,上面的计算表示一个线性地址,不是一个物理地址(参见intel手册volume 3a,图2.2),然后通过4KB分页的标准机制进行翻译,即地址由页面目录索引,页面表和所选页面的偏移量组成。但请记住,所有主流操作系统都使用所谓的平坦内存模式,这意味着所有段选择器都指向地址0x00000000,限制设置为0xFFFFFFFF,这就是为什么你可以在所有段之间进行转换并最终导致(容易)利用缓冲区溢出。
您给出的汇编程序指令很可能是通过可执行文件的导入地址表(请参阅this伟大的文章以获取更多详细信息)调用,即它不太可能是一个序数子例程打电话。
像这样的代码是由编译器发出的,因为来自外部dll的导入函数的最终虚拟地址通常在编译时是不可知的(由于dll的重新定义)。通过使用这样的调用构造,OS加载器可以通过逻辑地址在地址指针处插入正确的虚拟地址,并且编译器无需关心最终函数具有哪个地址。
答案 2 :(得分:1)
答案 3 :(得分:1)
call dword ptr ds:[00923030h]
,表示call
的指针00923939h
中的data segment
值