-1

我最近开始使用 C++ 编程和汇编语言。我想澄清几件事。

从我读到的内容,指令指针从指令中获取它应该执行的下一个地址retn。会不会和做 a 一样,jmp因为jmp也设置了指令指针?

如果我是对的,retn和 和有什么不一样jmp?如果我错了,有人可以用 C 伪代码解释吗?

无限循环的程序集等效项是什么?

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

4

3 回答 3

3

您似乎在谈论子程序调用,所以这是内幕。

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

1234  call 8888
1235  <next instruction>

发生的情况是,call首先将下一条指令指针放入1235堆栈(后进先出数据结构),然后将指令指针设置为您正在调用的任何内容,8888在这种情况下。

稍后,在以下位置完成退货8889

8888  mov eax, 0
8889  ret

return 所做的只是将第一个值从堆栈中弹出(即,1235由调用压入)并将其加载到指令指针中。所以不是返回告诉你去哪里,而是调用压入堆栈的信息。

如果您jmp在子程序的末尾有一条指令,它只能返回到代码中的一个点(暂时不考虑您可以用其他寻址模式做的所有美妙的事情):

8889  jmp 1235

通过使用 return,您可以返回到您来自的任何地方,无论它在哪里。


无限循环的汇编器可以很简单:

loopy:
    jmp loopy

至于寄存器,eaxebxecxedx被认为是通用寄存器。这将它们与堆栈指针、基指针、源和目标索引等更特殊用途的寄存器区分开来,这些寄存器根据其用途具有专门的指令。

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

于 2013-08-02T06:03:52.673 回答
1

C/C++ 函数的区别retjmp就 C/C++ 函数而言类似于:

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

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

   x += 10;

 Quit:
   return x;     <- similar to ret

}

当您return在 C 中执行此操作时,在机器级别上实际发生的事情会稍微复杂一些,因为通常会执行附加代码,例如将返回值放入eax并清理堆栈。ö 在 C++ 中,本地对象也会被破坏,但是函数的 ultiate 和 将是一条ret指令。

无限循环的程序集等效项是什么?

while(1);

就好像

000000 jmp 000000

或更高级

00000  inc ecx
00001  jmp 00000

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

一个例子是movsw,它要求你使用(E)SIand (E)DI,所以在这种情况下你不能自由选择。如果您使用rep movsw附加(E)CX也使用。通常,汇编器知道哪些寄存器对指令有效,并会给您一条错误消息,但当然,您应该查看手册以确定,因为如果汇编器不能抛出错误,您可能会得到意想不到的结果。

于 2013-08-02T10:18:45.930 回答
0

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

ecxcl确实但足够接近)是您可以在 Haswell 之前移动的唯一寄存器(它引入sarxshlx并且shrx所有这些都可以通过任何 GPR 移动)。ecx也被代表前缀用作计数器。pcmp*stri把长度放进去ecx

许多专用指令没有明确的操作数,而是为某些 GPR 赋予特殊含义,例如cpuid, rdpmc, rdtsc, wrmsr, xgetbv, xsave。通常edx:eax,也经常ecx,而且很少ebx。您可能不必经常处理这些问题。

于 2013-08-02T07:43:41.523 回答