NASM - JBE 指令给出分段错误
NASM - JBE instruction gives segmentation fault
我正在尝试使用 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-2 = f_i-1
f_i-1 = f_i
i = i + 1
return f_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
程序首先从终端读取一个整数。然后它将其作为 fib_it 的参数推入堆栈
当我 运行 程序出现分段错误时。我发现每次 jbe end_fib_it
或 jae end_fib_it
为真并且程序必须跳转然后它给出分段错误。我用 dump_regs
进行了更多调试,发现 while 循环 运行 非常完美并且 jmp fib_it_while
没有问题。
I found out that every time jbe end_fib_it or jae end_fib_it is true and the program has to jump then it gives a segmentation fault.
您的观察可能根本不是问题所在。
push dword [fibnum]
call fib_it
当您调用 fib_it 时,您将一个双字压入堆栈 ,之后您不会将其弹出。
最简单的解决方案可能是以 ret
:
的替代形式结束 fib_it
popa
leave
ret 4 ; The 4 will remove the parameter from the stack
不要使用 pusha
/popa
end_fib_it:
mov eax, [ebp-4] ; return f_i
popa
您想 return 得到 EAX
、 的结果,但随后的 popa
指令会立即破坏您刚刚放入其中的内容!
因为您只使用附加寄存器 ECX
和 EDX
,最好将 pusha
更改为 push ecx
push edx
。同时将 popa
更改为 pop edx
pop ecx
.
优化
mov edx, 1 ; comparison operator for n
cmp [ebp+8], edx ; n <= 1 ?
如果您只将它用于单个比较,为什么还要使用附加寄存器 EDX
?
如果把这对指令改成:
cmp dword [ebp+8], 1 ; n <= 1 ?
上述 pusha
/popa
的替换只会是 push ecx
/pop ecx
.
我正在尝试使用 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-2 = f_i-1
f_i-1 = f_i
i = i + 1
return f_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
程序首先从终端读取一个整数。然后它将其作为 fib_it 的参数推入堆栈
当我 运行 程序出现分段错误时。我发现每次 jbe end_fib_it
或 jae end_fib_it
为真并且程序必须跳转然后它给出分段错误。我用 dump_regs
进行了更多调试,发现 while 循环 运行 非常完美并且 jmp fib_it_while
没有问题。
I found out that every time jbe end_fib_it or jae end_fib_it is true and the program has to jump then it gives a segmentation fault.
您的观察可能根本不是问题所在。
push dword [fibnum] call fib_it
当您调用 fib_it 时,您将一个双字压入堆栈 ,之后您不会将其弹出。
最简单的解决方案可能是以 ret
:
popa
leave
ret 4 ; The 4 will remove the parameter from the stack
不要使用 pusha
/popa
end_fib_it: mov eax, [ebp-4] ; return f_i popa
您想 return 得到 EAX
、 的结果,但随后的 popa
指令会立即破坏您刚刚放入其中的内容!
因为您只使用附加寄存器 ECX
和 EDX
,最好将 pusha
更改为 push ecx
push edx
。同时将 popa
更改为 pop edx
pop ecx
.
优化
mov edx, 1 ; comparison operator for n cmp [ebp+8], edx ; n <= 1 ?
如果您只将它用于单个比较,为什么还要使用附加寄存器 EDX
?
如果把这对指令改成:
cmp dword [ebp+8], 1 ; n <= 1 ?
上述 pusha
/popa
的替换只会是 push ecx
/pop ecx
.