2014-06-12 20 views
1

带有注释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: 
/********************************** 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 
/*********************************************************************************/ 

主要的C代码:

#include <stdio.h> 
#include <stdlib.h> 

struct X 
{ 
    int c; 
    struct X * next; 
}; 
typedef struct X Xlist; 

Xlist * lst_create (void) 
{ 
    return NULL; 
} 

Xlist * lst_insert (Xlist * l, int c) 
{ 
    Xlist * new = (Xlist*) malloc(sizeof(Xlist)); 
    new->c = c; 
    new->next = l; 

    return new; 
} 

int add2 (struct X * x); 

int main (void) 
{ 
// int i; 
    Xlist * l; 
    l = lst_create(); 

    //for (i=-9;i<10;i++) 
    l = lst_insert(l, -1); 

    printf("%d\n", add2(l)); 

    return 0; 
} 

的意图是要打印链接的元素的总和名单。 使用负值时我收到内存垃圾。我相信错误在这里:

neg:negl (%ebx)   /* c = |c|        */ 
    subl (%ebx), %eax /* return x->(-)c + add2(x->next);  */ 

但是为什么? 已经在其他添加功能中使用了相同的算法,并没有问题。

回答

1

在我看来,一个很大的问题是,你要add2()递归调用忽略返回值:

pushl %eax   

movl 4(%ebx), %esi 
pushl %esi   
call add2   
addl $4, %esp  

popl %eax  ; <-- overwrites what the add2 call returned 

而且,你的C等效代码似乎并不真的是等价的。程序集版本将列表中的负值修改为正值;这不会反映在您的C代码版本中。

+0

谢谢@迈克尔,好点。另一个add函数没有'call',所以没有'pushl%eax''popl%eax'崩溃。在'addl(%ebx),%eax'之后我也忘记了'jmp end'。我在调用之后添加了'%edi'来接收'%eax'的值,并维护它的'pushl'和'popl'。之后,将'movl'的最终值转换为'return'的'%eax'。关于负值的修改(接着是减法,而不是标准加法),这是我知道的负值处理的唯一算法。你知道另一个吗? – Ajna