Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 为什么'call dword 0x12345678'编译为[66,E8,72,56,34,12]?_Assembly_X86_Nasm - Fatal编程技术网

Assembly 为什么'call dword 0x12345678'编译为[66,E8,72,56,34,12]?

Assembly 为什么'call dword 0x12345678'编译为[66,E8,72,56,34,12]?,assembly,x86,nasm,Assembly,X86,Nasm,为什么结果[66,E8,72,56,34,12]不是[66,E8,78,56,34,12]?为什么0x78变为0x72?您使用此指令调用的是一个绝对地址,尽管乍一看可能并不明显。让我们一步一步地完成装配过程 首先,您可以看到您的指令已组装到66 E866是操作数大小前缀-稍后我将解释它为什么会出现E8指向预期的调用指令,以下字节-72563412-是在调用指令之后相对于指令的32位位移的小端表示。这实际上是x86中所有相对跳转和调用的编码方式:因为CPU总是知道指令指针的当前值,所以它可以将指令

为什么结果[66,E8,72,56,34,12]不是[66,E8,78,56,34,12]?为什么
0x78
变为
0x72

您使用此指令调用的是一个绝对地址,尽管乍一看可能并不明显。让我们一步一步地完成装配过程

首先,您可以看到您的指令已组装到
66 E8
66
是操作数大小前缀-稍后我将解释它为什么会出现
E8
指向预期的
调用
指令,以下字节-
72563412
-是在
调用
指令之后相对于指令的32位位移的小端表示。这实际上是x86中所有相对跳转和调用的编码方式:因为CPU总是知道指令指针的当前值,所以它可以将指令指定的值添加到该值,然后执行调用/跳转

其次,有一个问题是,为什么汇编程序选择以这种方式汇编指令。如果实际运行的
nasm
没有任何标志,则默认为
bin
输出模式,该模式仅将原始操作码输出到指定的文件中。此外,它默认为在该输出模式下以16位模式组装指令。这就是为什么有
66
前缀的原因:如果操作码前面有前缀,就可以在16位模式下使用32位操作数执行指令。另外,
bin
输出模式中的
nasm
假设生成的二进制文件从地址
0
开始:这就是为什么您的呼叫的“偏移量”是
72563412
-如果IP从0开始,那么在处理
呼叫后它将是6,
0x6+0x12345672
为您提供
0x12345678
,那是你想打电话的地址。您可以通过
ORG
(origin)指令更改加载程序的偏移量

如果不想使用带相对寻址的跳转/调用,则必须将要跳转到/调用的代码的地址放入寄存器中,然后以寄存器作为操作数执行指令。大概是这样的:

$ cat call.s
call dword 0x12345678
$ nasm call.s
$ ndisasm call
00000000  66E872563412      call dword 0x12345678
组装到以下位置:

mov eax, somecode
jmp eax

somecode:
    int 3

您可以看到跳转的绝对地址直接移动到寄存器中。然而,如果您只是执行对标签的跳转/调用,我想不出任何不使用相对寻址的原因。CPU总是知道它的当前IP,你的汇编程序也应该知道。

因为这条指令有6字节长。@DanielKamilKozar抱歉,我是asm的新手。。。无法在机器代码级别调用绝对地址吗?调用地址编码为应用于EIP寄存器的偏移量。加载CALL指令后,其值将不是0x00000000,而是0x000000006。所以它是0x00000006+0x12345672==0x12345678我想使用绝对地址,因为我想动态更改地址。谢谢你令人印象深刻的回答!在这种情况下,通过寄存器的间接寻址就是您要寻找的。如果你想了解更多关于这个的实际用法,请查阅“跳转表”。
00000000  66B809000000      mov eax,0x9
00000006  66FFE0            jmp eax
00000009  CD03              int 0x3