Search code examples
assemblysegmentation-faultnasmcalling-convention

Segfaults using functions x86 nasm


I'm writing a compiler with bison, and trying to implement procedures. I found the "global intpow" example online, and that works totally fine, and I made my own procedure calls modelled after it. The function "bar" in this code snippet only takes one integer parameter, and prints it. When my compiled program is run and executed:

-intpow will run just as it's supposed to, to normal program termination, a function with the declaration of "bar" will run as its supposed to, to normal function termination, but If I call bar (And therefore add the three lines that are commented saying unique to bar call), The program will run exactly as it's supposed to until the very end, when it will Segmentation Fault.

gdb says it is at the final pop ebp in __bar_end...why is this segfaulting?

extern printf
extern scanf
extern pow
SECTION .data
printf_int:
    db "%d", 10, 0
printf_float:
    db "%lf", 10, 0
printf_str:
    db "%s", 10, 0
scan_int:
    db "%d", 0
scan_float:
    db "%lf", 0
esp_tmp:
    dd 0

SECTION .text
global intpow
intpow:
    push    ebp
    mov     ebp,esp
    mov     eax,[ebp+12]
    mov     ebx,[ebp+12]
    mov     ecx,[ebp+8]

loop:
    cmp     ecx,1
    cmp     ecx,1
    jle     finish
    dec     ecx
    imul    eax,ebx
    jmp     loop

finish:
    mov     esp,ebp
    pop     ebp
    ret
global main
main:
    push    ebp
    mov     ebp,esp
    jmp     __bar_END
global __bar
__bar:
    push    ebp
    mov     ebp,esp
    sub     esp,-4
    push    DWORD [ebp + 8]
    push    DWORD printf_int
    mov     [esp_tmp], esp
    add     DWORD [esp_tmp], 8
    call    printf
    mov     esp, DWORD [esp_tmp]
    mov     esp,ebp
    pop     ebp
    ret
__bar_END:
    push    DWORD 12 #Unique to bar call
    call    __bar    #unique to bar call
    add     esp,4    #unique to bar call
    push    DWORD str0
    push    DWORD printf_str
    mov     [esp_tmp], esp
    add     DWORD [esp_tmp],8
    call    printf
    mov     esp, DWORD [esp_tmp]
    mov     esp, ebp
    pop     ebp
    ret

SECTION .data

global_vars:    times 0 db 0

true:   db "true",0
false:  db "false",0
str0:   db "hello world",0

Solution

  • The problem is the sub esp, -4. It moves stack pointer up (subtracting a negative number is adding). Not that you need to allocate any space at all, since you are not using it. Now go clean up the rest of the mess ;)