x86 汇编:循环!
好吧,长话短说,我正在学习汇编,我正在尝试循环打印 ascii 字符“0”-“9”。 因此,我完成了在示例中看到的所有基础知识,例如使用 Pushad 和 Popad 保存寄存器状态、分配堆栈空间以及确保将事情保留在开始时的样子。 所以我管理了这个小例子:
;
; Hello_World.asm
; (NASM Syntax, Windows)
extern _printf
section .text
_main:
pushad ; save register states
push ebp ; save old stack
mov ebp, esp ; prepare new stack
sub esp, 1*4 ; allocate 4 bytes
mov byte [esp + 0], 48 ; add ascii '0' to stack
mov byte [esp + 1], 0 ; add ascii NULL terminator to stack
push esp; ; push the string in the stacks refrence
call _printf ; call printf()
add esp, 4 ; pop string refrence
add esp, 1*4 ; deallocate 4 bytes
mov esp, ebp ; close this stack
pop ebp ; restore old stack
popad ; restore register states
ret ; leave this function
这有效,它打印出“0”,但这有点安全。我尝试在其中添加一个循环,但事情就在那里崩溃了。我读到“循环”操作码应该递减 ECX 寄存器,并返回到标签参数应该 ECX > 。 0,但是,我认为我还没有完全掌握它。
所以我添加了几行,然后得出这样的结论:
;
; Hello_World.asm
;
extern _printf
global _main
section .text
_main:
pushad ; save register states
push ebp ; save old stack
mov ebp, esp ; prepare new stack
sub esp, 1*4 ; allocate 4 bytes
mov byte [esp + 0], 48 ; add ascii '0' to stack
mov byte [esp + 1], 0 ; add ascii NULL terminator to stack
mov ecx, 9 ; set loop counter to 9
aLoop:
inc byte [esp + 0] ; increment ascii character
push esp; ; push the string in the stacks refrence
call _printf ; call printf()
add esp, 4 ; pop string refrence
loop aLoop ; loop back to aLoop if ecx > 0
add esp, 1*4 ; deallocate 4 bytes
mov esp, ebp ; close this stack
pop ebp ; restore old stack
popad ; restore register states
ret ; leave this function
好吧,现在事情变得疯狂了。我在命令提示符下运行它,我通过耳机听到蜂鸣声,它循环遍历每个 ASCII 字符,将它们全部打印出来。因此,在角色飞行大约 5 秒后,我假设有东西溢出,然后就崩溃了。
我对汇编还很陌生(今天是我真正编码的第一天),我不知道出了什么问题。有人可以解释一下我如何更好地实现循环吗?
先谢谢了! -杰森
Okay, long story short, I'm learning assembly, and I'm trying to make a loop print out the ascii characters "0" - "9".
So, I did all of the basics I've been seeing in examples, like saving register states with pushad and popad, allocating stack space, and making sure I leave things the way they started.
So I managed this small example:
;
; Hello_World.asm
; (NASM Syntax, Windows)
extern _printf
section .text
_main:
pushad ; save register states
push ebp ; save old stack
mov ebp, esp ; prepare new stack
sub esp, 1*4 ; allocate 4 bytes
mov byte [esp + 0], 48 ; add ascii '0' to stack
mov byte [esp + 1], 0 ; add ascii NULL terminator to stack
push esp; ; push the string in the stacks refrence
call _printf ; call printf()
add esp, 4 ; pop string refrence
add esp, 1*4 ; deallocate 4 bytes
mov esp, ebp ; close this stack
pop ebp ; restore old stack
popad ; restore register states
ret ; leave this function
This works, it prints out '0', but that's a little on the safe side. I tried adding a loop into it, but things just fall apart there. I read that the 'loop' opcode is supposed to decrement the ECX register, and go back to the label parameter should ECX > 0, however, I don't think I've quite got it yet.
So I add a few lines, and come up with this:
;
; Hello_World.asm
;
extern _printf
global _main
section .text
_main:
pushad ; save register states
push ebp ; save old stack
mov ebp, esp ; prepare new stack
sub esp, 1*4 ; allocate 4 bytes
mov byte [esp + 0], 48 ; add ascii '0' to stack
mov byte [esp + 1], 0 ; add ascii NULL terminator to stack
mov ecx, 9 ; set loop counter to 9
aLoop:
inc byte [esp + 0] ; increment ascii character
push esp; ; push the string in the stacks refrence
call _printf ; call printf()
add esp, 4 ; pop string refrence
loop aLoop ; loop back to aLoop if ecx > 0
add esp, 1*4 ; deallocate 4 bytes
mov esp, ebp ; close this stack
pop ebp ; restore old stack
popad ; restore register states
ret ; leave this function
Well, now things go crazy. I run it in command prompt and I hear this beeping through my headphones, and it's cycling through every ascii character, printing them all out. So after about 5 seconds of flying characters, I assume something overflows, and it just crashes.
I'm pretty new to assembly (today's my first day of real coding), and I don't see what's going wrong. Could someone please explain how I could better implement a loop ?
Thanks ahead!
-Jason
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
“_printf”子例程是否保留 ECX 的内容?如果没有,那可能是你的问题。尝试在通话过程中保存它。
Does the "_printf" subroutine preserve the contents of ECX? If not, that could be your problem. Try saving it across the call.
好吧,你所描述的是循环由于某种原因没有终止。这意味着问题肯定就在这里:
这听起来像是调试器的工作:
ecx
到底发生了什么?嗯,我注意到您将
ecx
设置为9
。然后将4
添加到esp
。您什么时候更改ecx
? (是的,我知道它应该发生在loop
指令中,但如果这有效的话,你就不会问了。ecx<到底发生了什么
ecx< /code>?)
顺便说一句,蜂鸣声很简单:当您循环遍历所有 ASCII 字符时,您会遇到 ASCII 0x07,即 BEL 字符。
okay, well, what you're describing is that the loop isn't terminating for some reason. That means the problem pretty well has to be here:
This sounds like a job for a debugger: what's really happening to
ecx
?Well, I note that you're setting
ecx
to9
. You're then adding4
toesp
. When are you changingecx
? (Yes, I know it's supposed to be happening in theloop
instruction, but if that were working you wouldn't be asking. What's really happening toecx
?)The beeping, by the way, is easy: as you cycle through all the ASCII characters, you're hitting ASCII 0x07, the BEL character.
调用者保存的寄存器是eax、ecx、edx。被调用的子程序可以修改这些寄存器。使用搜索引擎查找调用者保存的寄存器与被调用者保存的寄存器。应该给你更多细节。
The caller-saved registers are eax, ecx, edx. The called subroutine is allowed to modify these registers. Look for caller-saved vs callee-saved registers using a search engine. Should give you more details.