Assembly NASM-JBE指令给出了分段错误
我正在尝试使用NASM汇编程序在汇编中实现斐波那契算法。 这是算法的伪代码Assembly NASM-JBE指令给出了分段错误,assembly,nasm,Assembly,Nasm,我正在尝试使用NASM汇编程序在汇编中实现斐波那契算法。 这是算法的伪代码 fibonacci_it(n): int f_i-1 = 1; int f_i-2 = 1; if (n==0): return 1; else: int i = 1; int f_i = 1; while (i < n): f_i = f_i-1 + f_i-2 f_i
fibonacci_it(n):
int f_i-1 = 1;
int f_i-2 = 1;
if (n==0):
return 1;
else:
int i = 1;
int f_i = 1;
while (i < n):
f_i = f_i-1 + f_i-2
f_i-2 = f_i-1
f_i-1 = f_i
i = i + 1
return f_i
fibonacci\u it(n):
int f_i-1=1;
int f_i-2=1;
如果(n==0):
返回1;
其他:
int i=1;
int f_i=1;
而(i
我试过的是这样的:
%include "asm_io.inc"
segment .data
prompt db "Enter number: ", 0
segment .bss
fibnum resd 1
segment .text
global asm_main
asm_main:
enter 0,0
pusha
mov eax, prompt
call print_string
call read_int
mov [fibnum], eax
push dword [fibnum]
call fib_it
call print_int
popa
mov eax, 0
leave
ret
fib_it:
enter 12,0 ; 3 local variables: f_i, f_i-1, f_i-2
pusha
mov dword [ebp-4], 1 ; initialize f_i
mov dword [ebp-8], 1 ; initialize f_i-1
mov dword [ebp-12], 1 ; initialize f_i-2
mov ecx, 1 ; i = 1
mov edx, 1 ; comparison operator for n
cmp [ebp+8], edx ; n <= 1 ?
jbe end_fib_it ; if n <= 1 -> end and return 1
fib_it_while:
dump_regs 1
mov eax, [ebp-8] ; eax = f_i-1
add eax, [ebp-12] ; eax = f_i-1 + f_i-2
mov [ebp-4], eax ; f_i = f_i-1 + f_i-2
mov eax, [ebp-8] ; eax = f_i-1
mov [ebp-12], eax ; f_i-2 = f_i-1
mov eax, [ebp-4] ; eax = f_i
mov [ebp-8], eax ; f_i-1 = f_i
inc ecx ; i += 1
cmp ecx, [ebp+8] ; i < n ?
jae end_fib_it ; end while loop if i < n
jmp fib_it_while ; else -> loop again
end_fib_it:
mov eax, [ebp-4] ; return f_i
popa
leave
ret
%包括“asm_io.inc”
段.数据
提示db“输入编号:”,0
第2部分:bss
fibnum resd 1
段.文本
全球ASMU主
asm_main:
输入0,0
普沙
mov-eax,提示符
调用打印字符串
调用read_int
mov[fibnum],eax
推送dword[fibnum]
称之为谎言
调用print_int
波帕
mov-eax,0
离开
ret
小谎:
输入12,0;3个局部变量:f_i,f_i-1,f_i-2
普沙
莫夫·德沃德[ebp-4],1;初始化f_i
莫夫·德沃德[ebp-8],1;初始化f_i-1
莫夫·德沃德[ebp-12],1;初始化f_i-2
mov-ecx,1;i=1
mov-edx,1;n的比较运算符
cmp[ebp+8],edx;再绕一圈
结束fib\u it:
mov-eax[ebp-4];返回f_i
波帕
离开
ret
程序首先从终端读取一个整数。然后将其作为fib_it的参数推送到堆栈中
当我运行程序时,它给出了一个分段错误。我发现每次jbe end\u fib\u it
或jae end\u fib\u it
都是真的,程序必须跳转,然后给出一个分段错误。我对dump_regs
进行了更多的调试,发现while循环运行得很好,jmp fib_it_while
没有问题
我发现每次jbe end_fib_it或jae end_fib_it都是真的,程序必须跳转,然后它就会给出一个分段错误
你的观察可能根本不是问题
当你调用fib_it时,你在堆栈上推一个双字,之后你不会在任何地方弹出它。
最简单的解决方案可能是以另一种形式ret
结束fib_it:
popa
leave
ret 4 ; The 4 will remove the parameter from the stack
不要使用
pusha
/popa
您想在EAX
中返回一个结果,但是后面的popa
指令将立即销毁您刚才放在那里的内容强>
由于您仅使用附加寄存器ECX
和EDX
,因此最好将pusha
更改为push ECX
push EDX
。同时将popa
更改为pop-edx
pop-ecx
优化
前面提到的pusha/
popa
的替代品只会是push ecx
/pop ecx
@Codey我添加了一个优化。输入0,0
也非常慢。如果你想谈论优化,使用内存做任何事情(并像OP那样复制内存)比英特尔Haswell上的简单的add eax,edx
/add edx,eax
要慢12到18倍。至少他们决定将循环计数器保留在寄存器中,并使用循环上限只读。(比另一种方法要好得多,对于inc[mem]
使用RMW,对于cmp
使用另一个加载)对于一个像样的asm斐波那契(它将序列存储在一个数组中),请参阅。第一个版本只是一个简单的一次一个版本,带有registermov
。更高版本通过对介绍代码的各种优化展开:)将所有数据保留在内存中而不是寄存器中的速度非常慢addeax,edx
/addedx,eax
更有效地计算斐波那契序列!从相当简单的开始,查看一些好的编写方法。
popa
leave
ret 4 ; The 4 will remove the parameter from the stack
end_fib_it:
mov eax, [ebp-4] ; return f_i
popa
mov edx, 1 ; comparison operator for n
cmp [ebp+8], edx ; n <= 1 ?
cmp dword [ebp+8], 1 ; n <= 1 ?