【问题标题】:Read and print user input with x86 assembly (GNU/Linux)使用 x86 程序集 (GNU/Linux) 读取和打印用户输入
【发布时间】:2014-05-05 08:35:43
【问题描述】:

我正在学习 GNU/Linux 上的 x86 汇编,我正在尝试编写一个程序,该程序从标准输入读取用户输入并将其打印到标准输出。

以下代码确实有效,但如果用户输入的字符串的大小小于 100 字节,它会打印额外的字符。

section .data
    str: db 100    ; Allocate buffer of 100 bytes

section .bss

section .text

global _start

_start:
    mov eax, 3          ; Read user input into str 
    mov ebx, 0          ; |
    mov ecx, str        ; | <- destination
    mov edx, 100        ; | <- length
    int 80h             ; \

    mov eax, 4          ; Print 100 bytes starting from str
    mov ebx, 1          ; |
    mov ecx, str        ; | <- source
    mov edx, 100        ; | <- length
    int 80h             ; \ 

    mov eax, 1          ; Return
    mov ebx, 0          ; | <- return code
    int 80h             ; \

如何可靠地计算用户输入字符串的长度?

如何避免打印多余的字符?

【问题讨论】:

    标签: linux assembly x86 nasm


    【解决方案1】:

    str: db 100 是错误的。您分配了 一个 值为 100 的字节。正确的是:str: times 100 db 0 分配值为 0 的 100 个字节。

    你有两个问题:

    1) 要获取输入字节数,您可以评估EAX 中读取函数的返回值 (int 80h / fn 3)。

    2) 如果您输入的字符多于“允许”字符,则其余字符将存储在您必须清空的输入缓冲区中。一个可能的方法是在下面的例子中:

    global _start
    
    section .data
        str: times 100 db 0 ; Allocate buffer of 100 bytes
        lf:  db 10          ; LF for full str-buffer
    
    section .bss
        e1_len resd 1
        dummy resd 1
    
    section .text
    
    _start:
        mov eax, 3          ; Read user input into str
        mov ebx, 0          ; |
        mov ecx, str        ; | <- destination
        mov edx, 100        ; | <- length
        int 80h             ; \
    
        mov [e1_len],eax    ; Store number of inputted bytes
        cmp eax, edx        ; all bytes read?
        jb .2               ; yes: ok
        mov bl,[ecx+eax-1]  ; BL = last byte in buffer
        cmp bl,10           ; LF in buffer?
        je .2               ; yes: ok
        inc DWORD [e1_len]  ; no: length++ (include 'lf')
    
        .1:                 ; Loop
        mov eax,3           ; SYS_READ
        mov ebx, 0          ; EBX=0: STDIN
        mov ecx, dummy      ; pointer to a temporary buffer
        mov edx, 1          ; read one byte
        int 0x80            ; syscall
        test eax, eax       ; EOF?
        jz .2               ; yes: ok
        mov al,[dummy]      ; AL = character
        cmp al, 10          ; character = LF ?
        jne .1              ; no -> next character
        .2:                 ; end of loop
    
        mov eax, 4          ; Print 100 bytes starting from str
        mov ebx, 1          ; |
        mov ecx, str        ; | <- source
        mov edx, [e1_len]   ; | <- length
        int 80h             ; \
    
        mov eax, 1          ; Return
        mov ebx, 0          ; | <- return code
        int 80h             ; \
    

    【讨论】:

    • 我注意到您使用文件描述符 0 (stdin) 来读取键盘值,这对我来说似乎是正确的。但是,以下网站改用文件描述符 2。这是一个错误吗? tutorialspoint.com/assembly_programming/…
    • @dave558:这是一件令人着迷的事情。 STDERR 也是一个读取流。所以,使用文件描述符没有。 2 不是错误,但不必要且尴尬。
    【解决方案2】:

    这是在 x86 汇编中计算字符串长度的一种方法:

    lea esi,[string]
    mov ecx,-1    ; Start with ecx = -1
    xor eax,eax   ; Clear eax
    cld           ; Make scasb scan forward 
    repne scasb   ; while (ecx != 0) { ecx--; if (*esi++ == al) break; }
    ; ecx now contains -1 - (strlen(string) + 1) == -strlen(string) - 2
    not ecx       ; Inverting ecx gives us -(-strlen(string) - 2) - 1 == strlen(string) + 1 
    dec ecx       ; Subtract 1 to get strlen(string)
    

    这假定字符串是 NUL 终止的 ('\0')。如果字符串使用其他终结符,则必须在 repne scasb 之前将 al 初始化为该值。

    【讨论】:

      猜你喜欢
      • 2011-12-13
      • 1970-01-01
      • 1970-01-01
      • 2012-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多