【问题标题】:Hand-assembling an x86 call instruction手工组装 x86 调用指令
【发布时间】:2014-05-06 10:07:13
【问题描述】:

出于好奇,我决定手工组装一些 x86 代码。到目前为止,我一切正常,但我无法确定 call 指令的正确编码。

我知道它基本上应该是E8 xx xx xx xx,其中xx xx xx xx是我要跳转到的地址。

我尝试编码的方式是这样的(NASM):

extern _printf

; ...

db 0xe8
dd _printf

组装和链接都很好,但是程序崩溃了。

我查看了 NASM 如何组装指令 call _printf,它生成的 xx xx xx xx 与我的不同。我想知道是我指定的地址不正确还是什么,但是代码

times 512 nop
dd _printf
times 512 nop

产生大量的90s 围绕着我从我手工组装的call 获得的相同地址,这意味着_printf 的实际地址不是我应该传递的。

我在这里错过了什么?

(另外:我很好奇call 的另一种编码,以FF 开头的那个。有什么区别?)

【问题讨论】:

  • E8 使用相对寻址:"E8 cd CALL rel32 调用近、相对、相对于下一条指令的位移。32 位位移符号在 64 位中扩展到 64 位模式。” 请参阅英特尔的软件开发人员手册第 2 卷。

标签: assembly x86 nasm


【解决方案1】:

0xE8 与相对地址一起使用。所以下面的指令编码为 E8 00 00 00 00

  call label
label:

一些以 0xFF 开头的编码可用于间接调用,其中目标地址存储在寄存器或内存中。如果你想在特定地址调用过程,你可以这样做:

  mov  eax, 0x12345678 ; address of procedure (not relative)
  call eax

0x9A 编码允许您进行更新 CS-register 的远调用。比如:

  call 0x1234:0x55667788

将 CS 寄存器的值更新为 0x1234,将指令指针的值更新为 0x55667788。返回地址也被压入堆栈,其中包含 CS 和指令指针的值。

有关不同编码的更多信息,我推荐this reference

【讨论】:

    猜你喜欢
    • 2018-09-16
    • 2012-01-15
    • 2011-10-27
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 2015-10-27
    相关资源
    最近更新 更多