nasm 无限循环与 rcx

nasm infinite loop with rcx

我有代码将 count 作为输入来获取 count 个数字并存储在数组

代码: 正在初始化消息

section .data
    msg db "Enter count"
    msgl equ $-msg
    msg1 db "Start Entering numbers"
    msg1l equ $-msg1

正在声明 countarray 以及获取输入和输出的宏

section .bss

count resb 1
arr resw 100;Maximum size 100 word
%macro general 4

    mov rax,%1
    mov rdi,%2
    mov rsi,%3
    mov rdx,%4
    syscall
%endmacro

主要功能

section .text

global _start

_start:
    general 1,1,msg,msgl  ;Enter a count display message
    general 0,0,count,1   ;Take count input
    general 1,1,count,1   ;Display that count
    sub byte[count],30h   ;Convert Ascii to number
    mov rcx,[count]       ;Store count to rcx
    general 1,1,msg1,msg1l   ;Display message
    mov rbx,arr            ;let rbx store starting address of arr
    again:

        general 0,0,rbx,2  ;Take number as input
        inc rbx            ;go to next address
        dec rcx            ;decrement counter
        jnz again          ;jump until counter is not zero
    ;general 1,1,msg,msgl
    general 60,0,0,0      ;Exit

OUTPUT

Enter count2
2Start Entering numbers3
1
1
1
1
2
3
3
3
3
3
3
3

不要跳出循环。 不知道为什么。

  1. mov rcx,[count] ;Store count to rcx

    这会从计数中加载 8 个字节。但是,您只为计数 (count resb 1) 保留了 one。剩下的来自下一个变量arr。如果有值,你会得到一个完全错误的 rcx。将行更改为

    movzx rcx, byte [count]     ;Store count to rcx
    
  2. System V AMD64 ABI calling conventionRCX 定义为调用者已保存。这也适用于 syscall。我建议更改宏:

    %macro general 4
        push rcx
        mov rax,%1
        mov rdi,%2
        mov rsi,%3
        mov rdx,%4
        syscall
        pop rcx
    %endmacro
    
  3. 系统调用 SYS_READ (RAX = 0) 导致您可能从 scanf 知道的相同问题。如果您不读取所有字符,输入缓冲区 (STDIN) 包含将由下一个 SYS_READ 读取的垃圾。如果您只读取一个字符 (general 0,0,count,1 ;Take count input),则 STDIN 以任何方式包含来自按下的 ENTER 键的 LF 字符。您必须清空 STDIN 缓冲区。如果您不想通过管道输入,您可以使用 IOCTL 函数:

    flush:                  ; 
        push rcx
    
    ;    32 bit Linux
    ;    mov eax,54          ; kernel function SYS_IOCTL
    ;    mov ebx,0           ; EBX=0: STDIN
    ;    mov ecx,0x540B      ; ECX=0x540B: TCFLSH
    ;    xor edx, edx        ; EDX=0: TCIFLUSH
    ;    int 0x80            ; sys_call
    
        mov eax, 16         ; kernel function SYS_IOCTL
        xor edi, edi        ; RDI=0: STDIN
        mov esi, 0x540B     ; RSI=0x540B: TCFLSH
        xor edx, edx        ; RDX=0: TCIFLUSH
        syscall             ; sys_call
    
        pop rcx
        ret
    

这是更正后的整组:

section .data

    msg db "Enter count "
    msgl equ $-msg
    msg1 db "Start Entering numbers",10
    msg1l equ $-msg1
    fmt: db `rax=%lu  rbx=%lu  rcx=%lu  rdx=%lu\n`,0

section .bss

    count resb 1
    dummy resb 1
    arr resw 100;Maximum size 100 word

%macro general 4
    push rcx
    mov rax,%1
    mov rdi,%2
    mov rsi,%3
    mov rdx,%4
    syscall
    pop rcx
%endmacro

section .text

flush:  ; 
    push rcx

;    32 bit Linux
;    mov eax,54          ; kernel function SYS_IOCTL
;    mov ebx,0           ; EBX=0: STDIN
;    mov ecx,0x540B      ; ECX=0x540B: TCFLSH
;    xor edx, edx        ; EDX=0: TCIFLUSH
;    int 0x80            ; sys_call

    mov eax, 16         ; kernel function SYS_IOCTL
    xor edi, edi        ; RDI=0: STDIN
    mov esi, 0x540B     ; RSI=0x540B: TCFLSH
    xor edx, edx        ; RDX=0: TCIFLUSH
    syscall             ; sys_call

    pop rcx
    ret

global main
main:
    general 1,1,msg,msgl    ; Enter a count display message
    general 0,0,count,1     ; Take count input
    call flush              ; flush STDIN

    general 1,1,count,1     ; Display that count
    sub byte[count],30h     ; Convert Ascii to number
    movzx rcx, byte [count] ; Store count to rcx

    general 1,1,msg1,msg1l  ; Display message

    mov rbx,arr             ; let rbx store starting address of arr
    again:

        general 0,0,rbx,2   ; Take number as input
        call flush

        inc rbx             ; go to next address
        dec rcx             ; decrement counter
        jnz again           ; jump until counter is not zero
    ;general 1,1,msg,msgl
    general 60,0,0,0        ; Exit