循环/输入逻辑流程问题(NASM x86汇编)

时间:2011-11-14 00:22:31

标签: linux assembly x86 nasm

我有一个程序,试图从用户那里获取输入并重复相同的字符串,直到用户再次输入。 (这是个人学习项目)

然而,我正在努力使其正确执行。在过去的帖子here中,您可以看到其他用户就此问题提供的输入,双关语。

%include "system.inc"

section .data
    greet:      db 'Hello!', 0Ah, 'Please enter a word or character:', 0Ah
    greetL:     equ $-greet     ;length of string
    inform:     db 'I will now repeat this until you type it back to me.', 0Ah
    informL:    equ $-inform
    finish:     db 'Good bye!', 0Ah
    finishL:    equ $-finish
    newline:    db 0Ah
    newlineL:   equ $-newline


section .bss

input: resb 40  ;first input buffer
check: resb 40  ;second input buffer

section .text

    global _start
_start:


greeting:
    mov eax, 4
    mov ebx, 1
    mov ecx, greet
    mov edx, greetL
    sys.write

getword:
    mov eax, 3
    mov ebx, 0
    mov ecx, input
    mov edx, 40
    sys.read

    sub eax, 1  ;remove the newline
    push eax    ;store length for later

instruct:
    mov eax, 4
    mov ebx, 1
    mov ecx, inform
    mov edx, informL
    sys.write

    pop edx     ;pop length into edx
    mov ecx, edx    ;copy into ecx
    push ecx    ;store ecx again (needed multiple times)

    mov eax, 4
    mov ebx, 1
    mov ecx, input
    sys.write

    mov eax, 4  ;print newline
    mov ebx, 1
    mov ecx, newline
    mov edx, newlineL
    sys.write

    mov eax, 3  ;get the user's word
    mov ebx, 0
    mov ecx, check
    mov edx, 40
    sys.read

    sub eax, 1
    push eax

    xor eax, eax

checker:
    pop ecx     ;length of check
    pop ebx     ;length of input
    mov edx, ebx    ;copy
    cmp ebx, ecx    ;see if input was the same as before

    jne loop    ;if not the same go to input again

    mov ebx, check
    mov ecx, input
secondcheck:

    mov dl, [ebx]
    cmp dl, [ecx]
    jne loop    
    inc ebx
    inc ecx
    dec eax
    jnz secondcheck

    jmp done

loop:

    pop edx
    mov ecx, edx
    push ecx
    mov eax, 4
    mov ebx, 1
    mov ecx, check
    sys.write   ;repeat the word

    mov eax, 4
    mov ebx, 1
    mov ecx, newline
    mov edx, newlineL
    sys.write
    mov eax, 3  ;replace new input with old
    mov ebx, 0
    mov ecx, check
    mov edx, 40
    sys.read

    jmp checker

done:

    mov eax, 1  
    mov ebx, 0  
    sys.exit

示例输出将产生:

Hello!
Please enter a word or character:
INPUT: Nick
I will now repeat this until you type it back to me.
Nick
INPUT: Nick
N
INPUT: Nick

INPUT: Nick

这种情况一直持续到它死亡为止。关于这个问题的任何想法?

感谢。

1 个答案:

答案 0 :(得分:1)

instruct在堆栈上留下两个项目,第一次循环时由checker消耗。但是,对于再次绕过循环的情况,它们不会被替换。这是代码中最基本的问题(可能还有其他问题)。

你可以通过运行调试器并观察堆栈指针esp来找到它;但只是通过查看代码就可以看出 - 如果除了堆栈操作和分支之外你已经把所有东西都拿出来了,你可以清楚地看到checker - > loop - >返回checker路径弹出三个项目,但只推送一个:

greeting:
    ...
getword:
    ...
    push eax    ;store length for later
instruct:
    ...
    pop edx     ;pop length into edx
    ...
    push ecx    ;store ecx again (needed multiple times)
    ...
    push eax
checker:
    pop ecx     ;length of check
    pop ebx     ;length of input
    ...
    jne loop    ;if not the same go to input again
    ...
secondcheck:
    ...
    jne loop    
    ...
    jnz secondcheck
    jmp done
loop:
    pop edx
    ...
    push ecx
    ...
    jmp checker
done:
    ...

有更好的方法可以保留长期存在的变量,而不是像pushpop一样在堆栈中将它们混乱。

  1. 将它们保存在数据部分(您已经拥有的.bss适合)而不是堆栈中。

  2. 在堆栈上分配一些空间,并直接在那里加载/存储它们。例如sub esp, 8要保留两个32位字,然后访问[esp][esp+4]。 (堆栈应与32位边界对齐,因此请始终保留4个字节的倍数。)完成使用后,请记得add esp, 8

  3. (这些基本上相当于C编译器将分别对全局(或static)变量和局部变量执行的操作。)