【问题标题】:nasm function called from C ends up segfaulting从 C 调用的 nasm 函数最终会出现段错误
【发布时间】:2014-07-23 01:39:20
【问题描述】:

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

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

问题分段错误的原因是什么?


ma​​in.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

【问题讨论】:

  • “我能写成这样”:什么是……?
  • minmax 函数内部是否发生了段错误?您应该能够在 gdb 中运行程序并找出段错误时的堆栈跟踪以及导致段错误的指令。
  • @Spundun Sth 是一个不能正常工作的函数,也不符合只有一个条件跳转的要求。
  • 相关:在将maxmin 发送到你的asm 函数的深渊之前如何初始化它们?现在是它的 UB。
  • 是的,这是个好主意,我会更改代码。

标签: c++ nasm


【解决方案1】:

长话短说

在使用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

【讨论】:

    【解决方案2】:

    我不知道你到底想做什么,但是汇编函数写得很糟糕。

    试试这个:

       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
    

    【讨论】:

      猜你喜欢
      • 2019-11-21
      • 2019-06-12
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 2017-10-08
      • 2011-07-02
      • 2021-09-24
      • 1970-01-01
      相关资源
      最近更新 更多