Search code examples
cassemblyx86nasmcalling-convention

Accessing function args from the stack relative to EBP while pushing/popping other registers?


I am writing an assembly program and a C program; the C program will call a function written in assembly. The environment is Ubuntu 18.04LTS x64.

It is designed for 32 bits x86 and will be compiled by NASM, but it can't pass correct parameters.

To simplify the problem, I just changed my function to get the sum of a and b.

extern int FindPattern(int a,int b);

int result;
result=FindPattern(1,1);
printf("%d\n",result);
global FindPattern
 section .text
FindPattern:
    push    ebp
    push    esi
    push    edi
    push    ebx
    push    edx
    push    ecx
    
    mov     ebp,esp
    mov     esi,[ebp+8]     ; a
    mov     edi,[ebp+12]    ; b
    mov     eax,0
    add     eax,esi
    add     eax,edi         ; return a+b
    
    pop     ecx
    pop     edx
    pop     ebx
    pop     edi               
    pop     esi
    pop     ebp
    ret          

The function just adds a and b, and returns the sum. The sum should be 2, however I got a random number like 1449041840. It seems the assembly didn't get correct parameters.

What's wrong with the code and how can I fix it?

# Makefile
cc=gcc
ASMBIN=nasm

all : asm cc link
asm:
    $(ASMBIN) -o findpattern.o -f elf32 -l findpattern.lst findpattern.asm
cc :
    $(cc) -m32 -c -g -O0 -fpack-struct graph_io.c
link :
    $(cc) -m32 -o graph_io findpattern.o graph_io.o 
clean:
    rm *.o
    rm graph_io
    rm findpattern.lst

Solution

  • Your stack frame set up is wrong. push ebp; mov ebp, esp must be issued before any other stack movement takes place.

    By pushing other stuff on the stack before setting up ebp you have set up ebp to point to a different place than usual, causing all the offsets to be different. To fix this, first set up the stack frame, then push the remaining registers:

    global FindPattern
     section .text
    FindPattern:
        push    ebp
        mov     ebp,esp
    
        push    esi
        push    edi
        push    ebx
        push    edx
        push    ecx
        
        mov     esi,[ebp+8]     ; a
        mov     edi,[ebp+12]    ; b
        mov     eax,0
        add     eax,esi
        add     eax,edi         ; return a+b
        
        pop     ecx
        pop     edx
        pop     ebx
        pop     edi               
        pop     esi
        pop     ebp
        ret