GNU GASM (x86_32) 跨函数保存寄存器值 (jmp)

GNU GASM (x86_32) Preserving register value across functions (jmp)

此程序将 %ebx 中从 1 到 n(本例中为 10)的数字相加并将它们移动到 %edi 中,因此执行程序的 return 值可以是用 echo $?

调用
        .global _start

_start:
        movl [=11=], %ebx
        movl , %ecx

addNumbers:
        cmpl , %ecx # sum up until n 
        jg exitRoutine
        addl %ecx, %ebx
        incl %ecx
        jmp addNumbers

exitRoutine:
        movl , %eax
        movl %ebx, %edi
        int [=11=]x80

为了测试,如果这个文件被调用 addUpTo10.s :

as -o addUpTo10.o addUpTo10.s && ld -o addUpTo10 addUpTo10.o && (./addUpTo10 ; echo $?)

我知道这是有效的,因为写入 %ebx 的值在函数调用中保留。如果我们要切换 %ebx%ecx 寄存器,值 returned 将是 $n+1$,因为 %ebx 中的值将被保留,但 ecx.

令我困惑的部分是在带有 %ecx 的 addNumbers 标签中发生的事情,其中​​我们有一个 jmp.

  1. 为什么我们递归调用addNumbers时,那里的值没有被清除?
  2. 什么操作(跳转、切换标签)实际导致寄存器清除?

您的程序不调用任何函数,也不进行任何 return 的系统调用,因此保存的寄存器完全无关紧要。 None 程序中的寄存器曾经被“清除”。差异的真正原因在于,与 amd64 Linux 不同,i386 Linux 上系统调用的第一个参数不是 edi 而是 ebx。如果你交换 ebxecx,然后将最终结果放回 ebx 而不是 edi,那么你将再次得到正确答案。