0

据我了解,当我根据 GCC 调用约定调用函数时,会发生以下情况:

调用者保存 AX、CX 和 DX 寄存器的值。参数和返回地址被压入堆栈。此外,calle 必须保留 SI、DI、BX 和 BP 寄存器的值。

但是,状态寄存器呢?谁来拯救它?

另外,压入堆栈的返回地址的值实际上是指令寄存器的值吗?

4

3 回答 3

2

状态寄存器不跨函数调用保留。如果状态寄存器中有重要的东西需要复制到其他地方(通常使用 SETcc),但调用约定不需要调用函数来执行此操作,就像它不需要调用函数来保存和恢复 AX等。如果他们没有什么重要的。

于 2018-01-08T08:26:30.430 回答
2

回答你的第二个问题:

另外,压入堆栈的返回地址的值实际上是指令寄存器的值吗?

call你的意思是指令推送的值?是的,这是内部执行期间的当前值ripeip/ip在 32/16 位模式下) (指向下一条指令)。callrip

并且该ret指令将弹出堆栈顶部的任何值,并将其设置为rip,从而更改下一条指令的代码执行流程(远离ret在堆栈中的地址/值之后的下一条指令)。因此堆栈中的值在完成后成为ip寄存器的内容ret。The retis like (non-existent) pop ip,但它有自己的助记符,使其在人类阅读时更好地在源代码中脱颖而出,并且它具有完全不同的操作码,因此晶体管中的硬件实现完全特定于它(这在现代 x86 上是有意义的,其中ret实现使用许多额外的技巧来获得更好的性能,但我有点好奇为什么 8086 不会将其编码为pop ip,就像另一个寄存器一样pop,甚至在当时可能在某些细节上有些特别)。

于 2018-01-08T09:55:09.257 回答
0

GCC 调用约定

gcc 在它所针对的任何平台上都使用标准调用约定。听起来您在描述 Linux 上使用的 i386 System V 调用约定/ABI,和/或一些 Windows 调用约定。(其中一些以不同的方式传递参数,但对可以被破坏的寄存器做出相同的选择)。

您使用的是 16 位寄存器名称,但 gcc 几乎不支持 16 位 x86。它基本上生成 32 位代码,然后将其组装起来,.code16因此大多数指令都有操作数大小和/或地址大小前缀。

调用者保存 AX、CX 和 DX 寄存器的值

不,调用者只有在它有任何想要在call. 正常情况是调用者让这些值消失。“调用者保存”与“被调用者保存”是不好的术语,因为它意味着所有寄存器实际上都保存在某个地方。

更容易理解,IMO,是

  • call-clobbered : EAX ECX EDX 和条件代码(EFLAGS 的一部分),所有 xmm regs
  • 呼叫保留:EBX、ESI EDI、EBP、ESP。

DF 在调用和返回时必须为 0,因此字符串指令向上。(DF 是 EFLAGS 中的另一个位)。callx87 堆栈在和上必须为空ret,但返回 FP 值的函数除外(在这种情况下st0具有返回值,并且 x87 堆栈的其余部分为空)。

Call-clobbered 意味着在 a 之后call,调用者必须假设寄存器包含垃圾,无论被调用者是否实际使用了寄存器。 如果该寄存器中有调用者稍后需要的任何内容,它必须将其移动到其他地方。但如果不是,让价值消亡完全没问题。例如,要编译类似的东西rv = foo(a + b + c),调用者会a+b+c在寄存器中计算。但是,如果在函数调用之后它也不需要该值,则无需保留它。

调用保留意味着调用者可以假设寄存器值没有改变,无论被调用者只是避免接触该寄存器,还是被调用者保存/恢复它。(或者对于 ESP,被调用者通常用 anadd esp, 28或类似的东西来恢复它,以逆转它用pushand所做的任何更改sub。被调用者如何设法返回仍然保存调用者值的调用保留寄存器并不重要,只是这就是为什么“被调用者保存”也不是最清楚的术语:它意味着被调用者显式地保存了它们。

但是,状态寄存器呢?谁来拯救它?

没有人会保存它,除非在极少数情况下。如果需要,调用者可以保存它,但通常重做比较更容易和更便宜(popf很慢,而且pushf首先保存 EFLAGS 不是免费的)。

或者更常见的情况是,条件代码中没有任何有用的数据,只有整数寄存器中的整数值。大多数指令都会写入 EFLAGS,但大多数时候您从未阅读过这些结果。您通常对整数结果使用add,等,而忽略标志结果。imul

有趣的事实:64 位 OS X 系统调用将 CF 设置为错误,否则将清除 CF。没有常见的 32 位或 64 位函数调用约定在 EFLAGS 中返回任何内容;他们只是被重创了。(对于 Linux 系统调用,保留 EFLAGS / RFLAGS。系统调用通常不会破坏除返回值之外的任何寄存器,部分原因是这样可以避免将内核信息泄漏回用户空间。)

于 2018-01-08T11:09:08.133 回答