如何解决在NASM中使用printf循环
在第一个循环中,我填充array
,然后我想打印该数组,但是会出现错误。是Segmentation fault
。我只是更改ecx
寄存器,因为这是我的_loop2
计数器。
extern printf
SECTION .bss
array resb 10
SECTION .data
fmt: db "array[%d] = %d",10,0 ; The printf format,"\n",'0'
SECTION .text
global main
main:
mov ecx,0
_loop:
inc ecx
mov [array + ecx * 4],ecx
cmp ecx,10
jnz _loop
mov ecx,0
_loop2:
jmp print
add ecx,1
cmp ecx,10
jnz _loop2
ret
print:
;push ebp ; set up stack frame
;mov ebp,esp
push ecx
push dword [array + ecx * 4] ; value of variable a SECOND
push dword fmt ; address of ctrl string
call printf ; Call C function
add esp,8 ; stack (4 * 2)
;mov esp,ebp ; takedown stack frame
;pop ebp ; same as "leave" op
mov eax,0 ; normal,no error,return value
;ret ; return
解决方法
评论中提到的几个问题:
-
array resb 10
将保留10个字节的空间,但您想在那里存储10个双字(40个字节)。更改为array resd 10
。 -
(由Sep Roland指出)在
_loop
中,您有一个错误的错误;由于inc
是在mov
之前完成的,因此您将访问[array+4],[array+8],... [array+40]
处的双字,其中最后一个超出范围。这就像在C语言中进行int array[10]; for (i=1; i <= 10; i++) array[i]=i;
一样,并且由于完全相同的原因也是不正确的。一种解决方法是改为mov [array + ecx * 4 - 4],ecx
。 -
在
_loop2
之后,您拥有jmp print
,它将控制权转移到print
,并且再也不会回来。由于您显然想调用print
作为子例程并继续执行add ecx,1 ; cmp ecx,10
等,因此您需要call print
而不是jmp
。并且在ret
的末尾取消注释print
,以便它实际上将返回。除非您实际执行ret
,否则汇编语言的子例程不会自动返回。否则,CPU将继续执行内存中接下来可能发生的任何垃圾操作。 -
在调用
push ecx
之前,您有一个ecx
保存printf
的值,这很好,因为printf
将覆盖该寄存器,但是您之后需要pop ecx
来获取该值并将堆栈放回原来的位置。具体来说,
pop ecx
应该跟在add esp,8
之后;堆栈是后进先出的结构,并且push ecx
在推送printf
参数之前,因此从堆栈中删除这些参数后需要pop ecx
。 -
mov eax,0
不需要作为print
末尾的返回值,因为您从未在其他任何地方使用它。
通过这些更改,代码可以正常工作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。