Сборка x86: петли! - PullRequest
       10

Сборка x86: петли!

2 голосов
/ 17 мая 2011

Хорошо, короче говоря, я изучаю ассемблер и пытаюсь сделать цикл, выводящий символы 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», но это немного безопаснее. Я попытался добавить петлю в это, но вещи просто разваливаются там. Я прочитал, что код операции 'loop' должен уменьшать регистр 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 секунд полета персонажей, я предполагаю, что что-то переполняется, и оно просто падает.

Я довольно новичок в сборке (сегодня мой первый день реального кодирования), и я не вижу, что происходит не так. Может кто-нибудь объяснить, как я мог бы лучше реализовать цикл?

Спасибо, вперед! * Джейсон 1013 *

Ответы [ 3 ]

3 голосов
/ 17 мая 2011

Сохраняет ли подпрограмма "_printf" содержимое ECX? Если нет, то это может быть вашей проблемой. Попробуйте сохранить его во время разговора.

3 голосов
/ 17 мая 2011

хорошо, хорошо, вы описываете, что цикл по какой-то причине не завершается. Это означает, что проблема довольно хорошо должна быть здесь:

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

Это похоже на работу отладчика: что действительно происходит с ecx?

Хорошо, я отмечаю, что вы устанавливаете ecx на 9. Затем вы добавляете 4 к esp. Когда вы меняете ecx? (Да, я знаю, что это должно происходить в инструкции loop, но если бы это сработало, вы бы не спрашивали.

Кстати, звуковой сигнал очень прост: когда вы перебираете все символы ASCII, вы нажимаете ASCII 0x07, символ BEL.

1 голос
/ 17 мая 2011
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. Вызываемой подпрограмме разрешено изменять эти регистры. Ищите сохраненные абонентом против сохраненных абонентом регистры, используя поисковую систему. Должен дать вам более подробную информацию.

...