我在努力学习NASM。我想编写一个过程,一次从控制台获取一个字符,直到只使用内核调用遇到换行符(0xA)。到目前为止

global _start

section .data
    sys_read     equ 3
    sys_write    equ 4
    stdin        equ 0
    stdout       equ 1
section .bss
    line         resb 11
    index        resb 4

section .text

_start:
    push ebp
    mov ebp, esp

    call _readLine
    afterReadLine:

    call _printLine

    mov esp, ebp
    pop ebp
    jmp exit

_readLine:
; Reads into line until new line (0xA)
; Number of bytes read will be stored in index when _readLine returns
    mov eax, sys_read             ; syscall to read
    mov ebx, stdin                ; stdin
    mov edx, [index]              ; put index into edx
    mov ecx, dword line           ; put line addr in ecx
    add ecx, edx                  ; add index to addr in ecx
    mov edx, 1                    ; read one char
    int 0x80                      ; call kernel to read char
    mov ecx, [index]              ; put index into ecx
    cmp dword [line + ecx], 0xA   ; compare value at line + ecx to new line char
    inc byte [index]              ; increment index
    je afterReadLine              ; if last char is newline return
    jne _readLine                 ; if last char is not new line, loop

_printLine:
    mov eax, sys_write
    mov ebx, stdout
    mov ecx, line
    mov edx, [index]
    int 0x80
    ret

exit:
    mov     eax, 01h        ; exit()
    xor     ebx, ebx        ; errno
    int     80h

当我测试末尾存储在索引变量中的值时,它总是等于0。我试着把index的值移到eax中,但是在跳跃之后它也是零。我尝试使用ret关键字,但这似乎也覆盖了我的值。返回从该过程中读取的字符的值的最佳实践方法是什么?
编辑:
我试过下面的,但还是没有结果。输入“abcd[newline]”时,程序输出“abcd”,如果我在打印行过程中对edx中的值4进行硬编码,但按所写内容不会输出任何内容。
global _start

section .data
    sys_read     equ 3
    sys_write    equ 4
    stdin        equ 0
    stdout       equ 1
    bytesRead    dd  0
    termios:        times 36 db 0
    ICANON:         equ 1<<1
    ECHO:           equ 1<<3

section .bss
    line         resb 11
    index        resb 4

section .text

_start:
    push ebp
    mov ebp, esp

    call canonical_off
    call echo_off

    call _readLine
    call _printLine

    call canonical_on
call echo_on

    mov esp, ebp
    pop ebp
    jmp exit

_readLine:
; Reads into line until new line (0xA)
; Number of bytes read will be stored in bytesRead when _readLine returns
    mov eax, sys_read             ; syscall to read
    mov ebx, stdin                ; stdin
    mov edx, [index]              ; put index into edx
    mov ecx, dword line           ; put line addr in ecx
    add ecx, edx                  ; add index to addr in ecx
    mov edx, 1                    ; read one char
    int 0x80                      ; call kernel to read char
    mov ecx, [index]              ; put index into ecx
    cmp dword [line + ecx], 0xA   ; compare value at line + ecx to new line char
    inc byte [index]              ; increment index
    jne _readLine                 ; if last char is not new line, loop
    ret

_printLine:
    mov eax, sys_write
    mov ebx, stdout
    mov ecx, line
    mov edx, [index]  ; Works if hardcoded 4 here!
    int 0x80
    ret

canonical_off:
        call read_stdin_termios

        ; clear canonical bit in local mode flags
        ;push rax
        mov eax, ICANON
        not eax
        and [termios+12], eax
        ;pop rax

        call write_stdin_termios
        ret

echo_off:
        call read_stdin_termios

        ; clear echo bit in local mode flags
        ;push rax
        mov eax, ECHO
        not eax
        and [termios+12], eax
        ;pop rax

        call write_stdin_termios
        ret

canonical_on:
        call read_stdin_termios

        ; set canonical bit in local mode flags
        or dword [termios+12], ICANON

        call write_stdin_termios
        ret

echo_on:
        call read_stdin_termios

        ; set echo bit in local mode flags
        or dword [termios+12], ECHO

        call write_stdin_termios
        ret

read_stdin_termios:
       ; push rax
       ; push rbx
       ; push rcx
        ;push rdx

        mov eax, 36h
        mov ebx, stdin
        mov ecx, 5401h
        mov edx, termios
        int 80h

        ;pop rdx
       ; pop rcx
        ;pop rbx
        ;pop rax
        ret

write_stdin_termios:
       ; push rax
        ;push rbx
        ;push rcx
       ; push rdx

        mov eax, 36h
        mov ebx, stdin
        mov ecx, 5402h
        mov edx, termios
        int 80h

        ;pop rdx
        ;pop rcx
       ; pop rbx
        ;pop rax
        ret

exit:
    mov     eax, 01h        ; exit()
    xor     ebx, ebx        ; errno
    int     80h

此处链接http://ideone.com/Lw3fyV

最佳答案

首先,您调用_readLine而不是从它返回,而是在方便地调用ret之后跳到标签。您应该使用call _readLine退出您的函数。
现在来回答你的问题。默认情况下,终端处于规范模式(熟模式),这意味着所有输入都被缓冲。系统将填充缓冲区,直到按下返回键并将0xA添加到缓冲区的末尾。
你想要的是非规范模式(原始模式)。这意味着系统不会处理按键,而是将其传递给您。
How do i read single character input from keyboard using nasm (assembly) under ubuntu?
通过切换到raw模式,您可以按下每个字符,直到返回键,然后使用它执行您想执行的操作。

08-16 09:52