【问题标题】:assembly intel x86 call function with local variables带有局部变量的汇编 intel x86 调用函数
【发布时间】:2016-10-20 08:37:49
【问题描述】:

我遇到了二进制搜索实现的问题。请注意,我不想修改此 c 代码,我正在尝试将其转换为程序集。这是我的 c 代码:

int binary_search_c(int n, int list[], int low, int high) {
int middle;

    if (low > high)
        return -1;

    middle = (low + high)/2;

    if (n == list[middle])
        return middle;
    if (n < list[middle]) {
        high = middle - 1;
    } else {
        low = middle + 1;
    }

    return binary_search_c(n, list, low, high);
}

这是我在汇编中的二进制搜索。我已经用我第一次添加的东西评论了 NEW,所以可能存在问题区域,尽管我很确定我的问题在于 bin。

;* int binary_search(int n, int list[], int low, int high);                *
;*****************************************************************************
%define n [ebp+8]
%define list [ebp+12]
%define low [ebp+16]
%define high [ebp+20]
binary_search:
    push ebp 
    mov ebp, esp

    sub esp, 4      ;one local var                    |
%define middle [ebp-4] ; define local var as middle   | NEW
    mov eax, low  ; pull low into register
    cmp eax, high ; compare low to high low > high
    jle less;    ; if less than or greater, go to less  
    mov eax, -1  ; move -1 into eax for return
    jmp return; ; call return/end function


less:               ;if low is not > high
    mov eax, low    ;move middle into register
    add eax, high   ;high+low
    mov ebx, 2      ;move 2 into ebx for div
    xor edx, edx    ;clear edx                        |
    xor eax, eax                      
    div ebx         ; div eax, by 2 =>(low+high)/2    | NEW
    mov middle, eax ;move (low+high)/2 into middle   
    mov eax, n      ; move middle into eax
    mov edi, list   ; move list into edi for list call
    mov edx, middle ; move middle into edx as list index |
    lea esi, [edi+edx*4] ; grab list[middle]             |
    mov ebx, [esi]      ; move list[middle] into register| NEW
    cmp eax, ebx  ; compare n and list[middle]             
    jne notE;     ; if not equal (n ==list[middle]
    mov eax, middle ;move middle into eax for return
    jmp return;   ;call return/end function

notE:       ;if n !=list[middle]
    mov eax, n  ;move eax into n
    mov edi, list ; move list into edi to access list
    mov ebx, middle ; move middle into ebx as index |
    lea esi, [edi+ebx*4] ; grab list[middle]        |
    mov ebx, [esi] ;move list[middle] into ebx      |NEW
    cmp eax, ebx   ; compare n and list[middle]
    jge .else;     ; if greater than or equal n < list[middle]
    mov eax, middle ;move middle into eax for return
    sub eax, 1     ;middle-1
    mov ebx, high  ; put high into ebx for replacement
    mov ebx, eax  ; high = middle-1
    jmp bin;     ;jump to next part[not return]


.else:     ;if n >= list[middle]
    mov eax, middle ;move middle into eax to add 1
    add eax, 1     ; middle+1
    mov ebx, low   ;move low into ebx for change in low
    mov ebx, eax   ;low = middle+1
bin:         ; final return
    mov eax, high ; move high into eax for push
    push eax   ; push high
    mov ebx, low ;low into ebx
    push ebx  ; push low
    mov ecx, list ; list for push
    push ecx ;push list
    mov edx, n ;n for push
    push edx ;push n                 |
    call binary_search ; call search |
    add esp, 16 ; add 16=>(4*4) to stack for reset | NEW

return:  ;end function
    leave
    ret

因此,在尝试查找错误时将我的代码切碎后,我在尝试使用 bin 运行任何东西时遇到了段错误

我认为我可能在使用add esp, 16 添加到堆栈时做错了,但我不确定,因为这是我第一次调用具有如此多参数且手头有一个局部变量的函数。 我很乐意对我的代码进行任何优化,我只是厌倦了标记为 NEW 的东西,我需要弄清楚我在 bin 中做错了什么导致错误,任何帮助将不胜感激。

【问题讨论】:

  • 尝试询问编译器。 :) 也就是说,编译 C 代码,然后查看生成的程序集作为参考。无需优化即可编译,并且可能在列表模式下保留 C 代码。
  • 仅供参考,除以 2 是右移,不需要使用 div
  • @Monkleys The DIV opcode has much higher latency and much lower throughput than SHR. 如果您为了可读性而更喜欢使用DIV,最好只用 C 编写代码并让编译器为您优化。
  • 因此减少问题的潜在来源 - 首先确保您可以调用不带参数的汇编函数,通过添加返回值来扩展它,将其扩展为接受四个参数并返回一个以某种简单的方式基于参数的值,然后添加一个局部变量,然后添加一个有限深度的递归调用(您可以使用输入数据来控制它),....所有这些都可以通过从您当前删除的东西来完成代码不难。
  • 您最好在原始问题中重新插入xor eax, eax 指令,否则您首先问的原因就变得不那么明显了!

标签: c assembly nasm


【解决方案1】:
mov eax, low    ;move middle into register
add eax, high   ;high+low
mov ebx, 2      ;move 2 into ebx for div
xor edx, edx    ;clear edx                        |
xor eax, eax    ;clear eax                        |
div ebx         ; div eax, by 2 =>(low+high)/2    | NEW

在这段代码中,您尝试计算 中间,但实际上并没有这样做,因为您在除法之前将 EAX 寄存器归零
请删除xor eax, eax 指令。


mov ebx, high  ; put high into ebx for replacement
mov ebx, eax  ; high = middle-1
jmp bin

这是另一个问题:

您想为较低的分区设置,但实际上并未存储新的 high 索引!
这样就可以了:

mov high, eax  ; high = middle-1
jmp bin

这同样适用于 索引。

【讨论】:

  • 是的,我错过了这个。谢谢你。但是,这仍然不能解决我的问题。虽然它本来是一个,但谢谢。 *编辑以反映
  • 供您编辑,mov ebx, eax 更新不高吗?还是只是复制它以供使用?
  • 我明白了,我不知道这个。谢谢你。它运行良好。
【解决方案2】:

只是对工作代码的更新,使用div by 2 而不是一个转变,效率低下,按功能。如果其他人需要它,请点击此处:

;* int binary_search(int n, int list[], int low, int high);                *
;*****************************************************************************
%define n [ebp+8]
%define list [ebp+12]
%define low [ebp+16]
%define high [ebp+20]
binary_search:
    push ebp 
    mov ebp, esp

    sub esp, 4      ;one local var
%define middle [ebp-4] ; define local var as middle
    mov eax, low  ; pull low into register
    cmp eax, high ; compare low to high low > high
    jle less;    ; if less than or greater, go to less  
    mov eax, -1  ; move -1 into eax for return
    jmp return; ; call return/end function


less:               ;if low is not > high
    mov eax, low    ;move middle into register
    add eax, high   ;high+low
    mov ebx, 2      ;move 2 into ebx for div
    xor edx, edx    ;clear edx
    div ebx         ; div eax, by 2 =>(low+high)/2
    mov middle, eax ;move (low+high)/2 into middle  
    mov eax, n      ; move middle into eax
    mov edi, list   ; move list into edi for list call
    mov edx, middle ; move middle into edx as list index
    lea esi, [edi+edx*4] ; grab list[middle]
    mov ebx, [esi]      ; move list[middle] into register
    cmp eax, ebx  ; compare n and list[middle]
    jne notE;     ; if not equal (n ==list[middle]
    mov eax, middle ;move middle into eax for return
    jmp return;   ;call return/end function

notE:       ;if n !=list[middle]
    mov eax, n  ;move eax into n
    mov edi, list ; move list into edi to access list
    mov ebx, middle ; move middle into ebx as index
    lea esi, [edi+ebx*4] ; grab list[middle]
    mov ebx, [esi] ;move list[middle] into ebx
    cmp eax, ebx   ; compare n and list[middle]
    jge .else;     ; if greater than or equal n < list[middle]
    mov eax, middle ;move middle into eax for return
    sub eax, 1     ;middle-1
    mov high, eax
    jmp bin;     ;jump to next part[not return]


.else:     ;if n >= list[middle]
    mov eax, middle ;move middle into eax to add 1
    add eax, 1     ; middle+1
       ;move low into ebx for change in low
    mov low, eax   ;low = middle+1

bin:         ; final return
    mov eax, high ; move high into eax for push
    push eax   ; push high
    mov ebx, low ;low into ebx
    push ebx  ; push low
    mov ecx, list ; list for push
    push ecx ;push list
    mov edx, n ;n for push
    push edx ;push n
    call binary_search ; call search
    add esp, 16 ; add 16=>(4*4) to stack for reset


return:  ;end function
    leave
    ret

感谢@Fifoernik 的回答

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 2015-07-31
    • 1970-01-01
    • 2018-10-13
    • 2019-02-13
    • 1970-01-01
    相关资源
    最近更新 更多