【发布时间】: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
DIVopcode has much higher latency and much lower throughput thanSHR. 如果您为了可读性而更喜欢使用DIV,最好只用 C 编写代码并让编译器为您优化。 -
因此减少问题的潜在来源 - 首先确保您可以调用不带参数的汇编函数,通过添加返回值来扩展它,将其扩展为接受四个参数并返回一个以某种简单的方式基于参数的值,然后添加一个局部变量,然后添加一个有限深度的递归调用(您可以使用输入数据来控制它),....所有这些都可以通过从您当前删除的东西来完成代码不难。
-
您最好在原始问题中重新插入
xor eax, eax指令,否则您首先问的原因就变得不那么明显了!