RMachnik
RMachnik

Reputation: 3684

nasm function called from C ends up segfaulting

I have to find min max values in array using only one conditional jump directive.

After compiling and linking the two files below I get a Segmentation Fault (core dumped), but I don't understand why that is.

Question: What is causing the segmentation fault?


main.cpp

#include <cstdio>
#include <time.h>

using namespace std;
extern "C" void minmax(int n, int * tab, int * max, int * min);

int main(){
   const int rozmiar = 100000;
   const int liczba_powtorzen = 10000; 

   int tab[rozmiar] = {1, 3, 3, -65, 3, 123, 4, 32, 342, 22, 11, 32, 44, 12, 324, 43};
   tab[rozmiar-1] = -1000;

   int min, max;

   min = 99999;
   max = -99999;


   clock_t start, stop;
   start = clock();

   for(int i=0; i<liczba_powtorzen; i++){
      minmax(rozmiar, tab, &max, &min);
   }

   printf("min = %d    max = %d\n", min, max);

   stop = clock();
   printf("\n time = %f ( %d cykli)", (stop - start)*1.0/CLOCKS_PER_SEC, (stop - start));

   return 0;
}

minmax.asm

global minmax               ; required for linker and NASM

section .text              ; start of the "CODE segment"

minmax:
    push ebp           
    mov ebp, esp        ; set up the EBP
    push ecx            ; save used registers
    push esi


    mov ecx, [ebp+8]    ; array length n
    mov esi, [ebp+12]   ; array address
    mov eax, [ebp+16]   ;max
    mov edi, [ebp+20]   ; min


lp:     add eax, [esi]  ; fetch an array element
        cmp eax, [esi]
        jl max          ; max<[esi] ->update max
        cmp edi, [esi]
        jg min          ; min>[esi] ->update min
        add esi, 4      ; move to another element
        loop lp         ; loop over all elements

max: 
    mov eax, esi
    ret

min: 
    mov edi, esi
    ret

    pop esi             ; restore used registers
    pop ecx
    pop ebp
    ret                 ; return to caller

Upvotes: 0

Views: 148

Answers (2)

Filip Ros&#233;en
Filip Ros&#233;en

Reputation: 63797

Long story, short:

You need to restore the stack before using ret.

Your asm implementation is faulty on many levels, but the reason for your segmentation fault is poor understanding of how ret works.


Invalid use of ret

ret does not bring you back to the last jump, it reads the value that is at the top of the stack, and returns to that address.

After you jump to either min: or max:, you call ret, where you should be jumping back to your loop.

This means that it will try to return back to the address at the top of the stack, which certainly isn't a valid address; you modified it upon entering the function.

push ebp           
mov ebp, esp        ; set up the EBP
push ecx            ; save used registers
push esi            ; note, this is where `ret` will try to go

Upvotes: 3

Ted
Ted

Reputation: 66

I do not know what you're exactly trying to do, but the assembler function is written poor.

Try this:

   push ebp           
   mov ebp, esp        ; set up the EBP
   push ecx            ; save used registers
   push esi

   mov ecx, [ebp+8]    ; array length n
   mov esi, [ebp+12]   ; array address

   mov eax, 0x80000000
   mov edi,[ebp+16]
   mov [edi], eax
   mov eax, 0x7fffffff
   mov edi,[ebp+20]
   mov [edi], eax

lp:
   mov edi,[ebp+16]
   lodsd
   cmp [edi], eax
   jg short _min_test
   mov [edi], eax

_min_test:
   mov edi,[ebp+20]
   cmp [edi], eax
   jl short _loop
   mov [edi], eax
_loop:
   loop lp

   pop esi             ; restore used registers
   pop ecx
   pop ebp
   ret                 ; return to caller

Upvotes: 0

Related Questions