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
.
- 为什么我们递归调用addNumbers时,那里的值没有被清除?
- 什么操作(跳转、切换标签)实际导致寄存器清除?
您的程序不调用任何函数,也不进行任何 return 的系统调用,因此保存的寄存器完全无关紧要。 None 程序中的寄存器曾经被“清除”。差异的真正原因在于,与 amd64 Linux 不同,i386 Linux 上系统调用的第一个参数不是 edi
而是 ebx
。如果你交换 ebx
和 ecx
,然后将最终结果放回 ebx
而不是 edi
,那么你将再次得到正确答案。
此程序将 %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
.
- 为什么我们递归调用addNumbers时,那里的值没有被清除?
- 什么操作(跳转、切换标签)实际导致寄存器清除?
您的程序不调用任何函数,也不进行任何 return 的系统调用,因此保存的寄存器完全无关紧要。 None 程序中的寄存器曾经被“清除”。差异的真正原因在于,与 amd64 Linux 不同,i386 Linux 上系统调用的第一个参数不是 edi
而是 ebx
。如果你交换 ebx
和 ecx
,然后将最终结果放回 ebx
而不是 edi
,那么你将再次得到正确答案。