x86 汇编:循环!

发布于 2024-11-07 11:52:40 字数 2149 浏览 0 评论 0原文

好吧,长话短说,我正在学习汇编,我正在尝试循环打印 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

归属感 2024-11-14 11:52:40

“_printf”子例程是否保留 ECX 的内容?如果没有,那可能是你的问题。尝试在通话过程中保存它。

Does the "_printf" subroutine preserve the contents of ECX? If not, that could be your problem. Try saving it across the call.

巷子口的你 2024-11-14 11:52:40

好吧,你所描述的是循环由于某种原因没有终止。这意味着问题肯定就在这里:

  add   esp, 4      ; pop string refrence
  loop  aLoop       ; loop back to aLoop if ecx > 0

这听起来像是调试器的工作: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:

  add   esp, 4      ; pop string refrence
  loop  aLoop       ; loop back to aLoop if ecx > 0

This sounds like a job for a debugger: what's really happening to ecx?

Well, I note that you're setting ecx to 9. You're then adding 4 to esp. When are you changing ecx? (Yes, I know it's supposed to be happening in the loop instruction, but if that were working you wouldn't be asking. What's really happening to ecx?)

The beeping, by the way, is easy: as you cycle through all the ASCII characters, you're hitting ASCII 0x07, the BEL character.

心凉 2024-11-14 11:52:40
aLoop:
  inc   byte [esp + 0]  ; increment ascii character
  push  ecx;        ; save ecx
  push  esp;        ; push the string in the stacks refrence
  call  printf     ; call printf()
  add   esp, 4      ; pop string refrence
  pop   ecx
  loop  aLoop           ; loop back to aLoop if ecx > 0

调用者保存的寄存器是eax、ecx、edx。被调用的子程序可以修改这些寄存器。使用搜索引擎查找调用者保存的寄存器与被调用者保存的寄存器。应该给你更多细节。

aLoop:
  inc   byte [esp + 0]  ; increment ascii character
  push  ecx;        ; save ecx
  push  esp;        ; push the string in the stacks refrence
  call  printf     ; call printf()
  add   esp, 4      ; pop string refrence
  pop   ecx
  loop  aLoop           ; loop back to aLoop if ecx > 0

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文