程序集retn,jmp,进程寄存器

时间:2013-08-02 05:53:42

标签: assembly x86 cpu-registers eip

我最近开始使用汇编语言进行C ++编程。我想澄清一些事情。

根据我的阅读,指令指针从retn指令获取接下来应该执行的地址。它与执行jmp不一样,因为jmp也设置了指令指针吗?

如果我是对的,retnjmp之间有什么区别?如果我错了,有人可以解释C伪代码吗?

无限循环的装配等价物是什么?

我读到EAX,EBX,ECX,EDX可以互换,但它们有什么区别吗?如果是这样,我应该在哪种情况下专门使用EAX/EBX/ECX/EDX

3 个答案:

答案 0 :(得分:3)

你似乎在谈论子程序调用,所以这就是它的下行。

当你调用子程序时,它看起来像这样(地址会有所不同,但我不想让你混淆可变长度指令):

1234  call 8888
1235  <next instruction>

call首先将下一个指令指针1235置于堆栈(后进先出数据结构)中,然后将指令指针设置为您所需的任何内容在这种情况下调用8888

稍后,返回8889

8888  mov eax, 0
8889  ret

返回的作用只是弹出堆栈的第一个值(即1235,它被调用推送)并将其加载到指令指针中。所以不是 return 告诉你去哪里,它是调用在堆栈上推送的信息。

如果在子程序结束时有一条jmp指令,它只能返回代码中的一个点(折扣你现在可以用其他寻址模式做的所有精彩事情):

8889  jmp 1235

通过使用返回,无论你身在何处,都会回到原地。


无限循环的汇编程序可以简单如下:

loopy:
    jmp loopy

对于寄存器,eaxebxecxedx被视为通用寄存器。这使它们与诸如堆栈指针,基指针,源和目标索引等更特殊用途的寄存器区别开来,它们根据其用途具有专门的指令。

ax可能在x86架构的早期迭代中有一些额外的功能,但我不确定是否仍然如此。如果你正在编写自己的东西,你应该能够互换使用它们。如果您正在关注API或ABI,则需要遵循它所施加的规则(例如eax保存系统调用号的Linux系统调用接口。)

答案 1 :(得分:1)

根据C / C ++函数,retjmp的区别与此类似:

int foo()
{
   int x = 3+4;

   if(x < 10)
      goto Quit;    <- similar to jmp

   x += 10;

 Quit:
   return x;     <- similar to ret

}

当您在C中执行return时,在机器级别实际发生的事情会更复杂一些,因为经常会执行其他代码,例如将返回值放在eax中并清理堆栈。在C ++中,本地对象也会被解构,但是ultiate和函数将是ret指令。

  

无限循环的装配等价物是什么?

while(1);

就像

000000 jmp 000000

或更高级的

00000  inc ecx
00001  jmp 00000

通用寄存器。在某些情况下,您可以混合寄存器并根据需要使用它们。对于某些指令,他们希望使用特定的寄存器。您必须查阅说明手册以了解这种情况。

一个例子是movsw,要求您使用(E)SI(E)DI,因此在这种情况下您无法自由选择。如果您使用rep movsw,则还会使用其他(E)CX。 通常,汇编程序知道哪些寄存器对于一个inxtruction有效并且会给你一个错误信息,当然,你应该查看手册以确定,因为如果汇编程序不能抛出错误,你可能会得到意想不到的结果。

答案 2 :(得分:0)

eaxedx是除法中的隐式操作数,并且是乘法的宽结果版本。还有一些特殊的符号扩展指令,仅对rax(操作码98)的部分操作或将eax符号扩展为edx:eax(操作码99)。十进制数学指令都适用于eax的部分内容。

ecx(确实cl非常接近)是唯一可以在Haswell引入之前转移的注册表(引入sarxshlx和{{1}所有这些都可以通过任何GPR移动)。 shrx也用作重复前缀的计数器。 ecx将长度设为pcmp*stri

许多专用指令没有明确的操作数,而是为某些GPR赋予特殊含义,例如ecxcpuidrdpmcrdtsc,{{1 },wrmsr。通常xgetbv,通常xsave,很少edx:eax。你可能不需要处理这些问题。