C 组装,总和上的负值处理
带有注释的c版本的汇编函数:C 组装,总和上的负值处理,c,gcc,assembly,x86,signed,C,Gcc,Assembly,X86,Signed,带有注释的c版本的汇编函数: /* struct X { int c; // 4 bytes struct X *next; // 4 bytes }; int add2 (struct X *x) { if (x == NULL) return 0; else return x->c + add2(x->next); } */ .text .globl add2 add2: /*************************
/*
struct X
{
int c; // 4 bytes
struct X *next; // 4 bytes
};
int add2 (struct X *x)
{
if (x == NULL) return 0;
else return x->c + add2(x->next);
}
*/
.text
.globl add2
add2:
/********************************** prologue *************************************/
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
/********************************************************************************/
movl 8(%ebp), %ebx
cmpl $0, %ebx
jne out
movl $0, %eax
jmp end
out:
/***************************** calculates in x->next *******************************/
pushl %ecx
pushl %edx
pushl %eax
movl 4(%ebx), %esi
pushl %esi
call add2
addl $4, %esp
popl %eax
popl %edx
popl %ecx
/********************************************************************************/
cmpl $0, (%ebx) /* > negative values */
js neg /* treatment < */
addl (%ebx), %eax /* return x->c + add2(x->next); */
neg:negl (%ebx) /* c = |c| */
subl (%ebx), %eax /* return x->(-)c + add2(x->next); */
end:
/****************************************end *************************************/
popl %esi
popl %ebx
movl %ebp, %esp
popl %ebp
ret
/*********************************************************************************/
但是为什么呢?
在其他add函数中已经使用了相同的算法,并且没有问题。在我看来,一个大问题是对
add2()
的递归调用忽略了返回值:
pushl %eax
movl 4(%ebx), %esi
pushl %esi
call add2
addl $4, %esp
popl %eax ; <-- overwrites what the add2 call returned
pushl%eax
第4幕(%ebx),%esi
pushl%esi
呼叫地址2
加4美元,特别是
popl%eax;谢谢@Michael,说得好。另一个add函数没有调用
,因此没有pushl%eax
popl%eax
崩溃。我还忘记了addl(%ebx),%eax
之后的jmp end
。我在通话后添加了%edi
以接收%eax
值,并维护了它的pushl
和popl
。之后,movl
返回的%eax
的最终值。关于负值的修改(后面是减法,不是标准的加法),这是我所知道的唯一一种处理负值的算法。你知道另一个吗?
neg:negl (%ebx) /* c = |c| */
subl (%ebx), %eax /* return x->(-)c + add2(x->next); */
pushl %eax
movl 4(%ebx), %esi
pushl %esi
call add2
addl $4, %esp
popl %eax ; <-- overwrites what the add2 call returned