Search code examples
assemblyx86gdb

X86 Assembly - Segmentation Fault Passing Array To Function?


Using GDB I see where the segmentation fault happens when it executes "call Mby5" but even debugging it, I don't see why it's getting a segmentation fault when I call the function?

In this code I have two arrays, the first I print to the screen and then the second "ard2" I want to multiply the values of the first one by 5 and then store those new values in "ard2" and then print them. The Mby5 function is where I'm trying to multiply them and store the new values inside ard2, then return and call PrintArray. Here is the complete code and will attach a screenshot of GDB showing when the error hits.

section .data 
    msg1: db 'Here are the array element values: ',10, 0 
    msgL1: equ $-msg1

    msg2: db"Here are the new array element values after multiplying by 5! ",10, 0
    msgL2: equ $-msg2

    ard1: dd 2, 4, 6, 8, 10, 20, 40
    ard1L: equ ($-ard1) / 4 ; Number of elments = array length / 4

    ard2: dd 0, 0, 0, 0, 0, 0, 0
    ard2L: equ ($-ard2) / 4 ; Number of elments = array length / 4


section .text 
    global _start ; declare _start as a global label
_start:
    push ebp        ; save ebp for whoever called main function (OS or other program)
    mov ebp, esp    ; create our new stack frame

   mov ecx,msg1 ; print message #1
   mov edx,msgL1
   call PString

   ;save array base address in ebx and save size of the array in ecx
   mov ebx, ard1
   mov ecx, ard1L

   ;call PrintArray to print the array element
   call PrintArray

   ;print message2
   mov ecx, msg2
   mov edx, msgL2
   call PString

   ;restore the array address and its size to the stack before calling Mby5 function
   mov ebx, ard1
   mov ecx, ard1L
   call Mby5  **[ERROR HAPPENS WHEN I CALL IT HERE]**
    
  ;After multplfying array1 elements by 5 and storing it in ard2 we call PrintArray and pass it ard2
  mov ebx, ard2
  mov ecx, ard2L

  ;Call PrintArray 
  call PrintArray

PrintArray:
    section .text
        push ebp 
        mov ebp, esp

top:
    mov eax,[ebx] ;move the value of [ebx] to eax
    call printDec
    call println
    add ebx, 4
    loop top

    mov esp, ebp ; destroy the stack
    pop ebp
    ret

Mby5:  
    section .text
      push ebp
      mov ebp, esp

top1:
    mov eax, [ebx] ; access first array element. Move its value to eax
    shl eax, 2 ; multiply by 4
    add eax, [ebx] ; multiply by 5
    mov [ard2 + ebx - ard1], eax ; store the result in array2
    add ebx, 4
    loop top1

    popa ;restore registers
    ret


println:
    section .data
    nl db"", 10 
    section .text
        ;save register values of the called function
        pusha
        mov ecx, nl
        mov edx, 1
        mov eax, 4
        mov ebx, 1
        int 80h

        ;restore the old register values of the called function
        popa 
        ret

PString:
    ;Save register values of called function
    pusha

    mov eax, 4  ;use 'write' system call = 4
    mov ebx, 1  ;file descriptor 1 = STDOUT
    int 80h     ;call the kernel

    ;restore the old register values of the called function
    popa
    ret


printDec:
    section .bss
        decstr resb 10;
        ct1 resd 1

    section .text
        pusha ;save all registers

        mov dword[ct1], 0 ; assume initially 0
        mov edi, decstr ;edi points to dec-string in memory
        add edi, 9 ;moved to the last element of string
        xor edx, edx

whileNotZero:
        mov ebx, 10 ;get ready to divide by 10
        div ebx ;divide by 10
        add edx,'0' ; convert to ascii char
        mov byte[edi], dl ; put it in string
        dec edi ;move to next char in string
        inc dword[ct1]
        xor edx, edx ;clear edx
        cmp eax, 0 ;is remainder 0
        jne whileNotZero ; keep looping

        inc edi ; conversion finish
        mov ecx, edi
        mov edx, [ct1]
        mov eax, 4
        mov ebx, 1
        int 0x80

        popa ;restore registers
        ret

Error Picture

Error

Stepped through with GDP and checked register values. Can't seem to find the issue.


I changed Mby5 but using leave and ret

    Mby5:
    push ebp
    mov ebp, esp

    mov edi, 0 ; index variable
top1:
    mov eax, [ebx] ; access first array element. Move its value to eax
    shl eax, 2 ; multiply by 4
    add eax, [ebx] ; multiply by 5
    mov [ard2 + ebx - ard1], eax ; store the result in array2
    add ebx, 4
    loop top1

    leave ; restore the original stack frame before returning
    ret

But then my output is

 Here are the new array element values after multiplying by 5! 
10
20
30
40
50
100
200
10
0
825360384
2356
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
zsh: segmentation fault 

Solution

  • If you 'hide' the instructions from Mby5 that don't have to do with the stack, this remains:

    push ebp
    mov ebp, esp
    
    ...
    
    popa ;restore registers
    ret
    

    Obviously the popa isn't matched by an appropriate number of pushed bytes. This leads to the call address being removed from the stack before the ret is reached, and so the call returns to a dubious address.

    You fix this by aligning push and pop instructions, like:

    push ebp
    pusha
    ...
    popa
    pop ebp
    ret
    

    or just

    pushad
    ...
    popad