Search code examples
cgccassemblyx86signed

Assembly, negative values treatment on sum


The assembly function with commented c version:

/*
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
/*********************************************************************************/

The main c code:

#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;
}

The intention is to print the sum of the elements of a linked list. I'm getting memory garbage when using negative values. I believe the error is somehow here:

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

But why? Already used the same algorithm in other add function and it was ok.


Solution

  • It seems to me that a big problem is that your recursive call to add2() ignores the return value:

    pushl   %eax        
    
    movl    4(%ebx), %esi   
    pushl   %esi        
    call    add2        
    addl    $4, %esp    
    
    popl    %eax        ; <-- overwrites what the add2 call returned
    

    Also, your C equivalent code doesn't seem to be really be equivalent. The assembly version modifies the negative values in the list to be positive; that isn't reflected in your C code version.