从C调用的nasm函数最终会导致segfaulting

时间:2014-06-02 20:44:15

标签: c++ nasm

我必须只使用一个条件跳转指令在数组中找到最小值。

编译并链接下面的两个文件后,我得到Segmentation Fault (core dumped),但我不明白为什么会这样。

问题:导致细分错误的原因是什么?


的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

2 个答案:

答案 0 :(得分:3)

冗长,简短

您需要在使用ret之前恢复堆栈。

您的 asm 实施在许多级别上都有问题,但分段错误的原因是对ret的工作原理认识不足。


无效使用ret

ret不会将您带回到最后一个跳转,它会读取堆栈顶部的值,然后返回到该地址。

跳转到min:max:后,您拨打ret,然后您应该跳回到循环中。

这意味着它会尝试返回回到堆栈顶部的地址,这当然不是有效的地址;你在进入这个功能时修改了它。

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

答案 1 :(得分:0)

我不知道你究竟想做什么,但汇编程序功能写得很差。

试试这个:

   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