开发者

x86 Assembly: Loops!

开发者 https://www.devze.com 2023-03-06 04:04 出处:网络
Okay, long story short, I\'m learning assembly, and I\'m trying to make a loop print out the ascii characters \"0\" - \"9\".

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


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


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消