程序集x86_64:从用户获取输入整数并打印它

时间:2017-05-09 14:11:49

标签: assembly nasm x86-64

我正在尝试编写一个以下列方式工作的程序:

获取用户->输入的数字,例如,2 ->打印结果(商)。

divide-by-the-number-2部分似乎没有太大的困难,所以初步我写了一个程序,用户获取整数输入并打印整数。

这意味着我尝试编写一个程序,将用户的字符串整数转换为实数,然后将其转换回字符串并打印出来。

但是在编译之后我最终陷入无限循环(在点击Enter之后没有任何反应)。

我使用以下命令编译:

nasm -f elf64 ascii.asm -o ascii.o

ld ascii.o -o ascii

./ascii

在下面的代码中,子例程_getInteger用于从字符串转换为整数,子例程_appendEOL_loopDigit用于从整数到字符串的整个转换。

section .bss
        ascii resb 16           ; holds user input
        intMemory resb 100      ; will hold the endline feed 
        intAddress resb 8       ; hold offset address from the intMemory

section .data
        text db "It's not an integer", 10
        len equ $-text

section .text

        global _start

_start:

        call _getText
        call _toInteger
        call _appendEOL

mov rax, 60
        mov rdi, 0
        syscall

_getText:
        mov rax, 0
        mov rdi, 0
        mov rsi, ascii
        mov rdx, 16
        syscall
        ret

_toInteger:
        mov rbx,10      ; for decimal scaling
        xor rax, rax    ; initializing result
        mov rcx, ascii  ; preparing for working with input
        movzx rdx, byte [rcx]   ; getting first byte (digit)
        inc rcx         ; for the next digit

        cmp rdx, '0'    ; if it's less than '0' is not a digit
        jb _invalid

        cmp rdx, '9'    ; if it's greater than '9' is not a digit
        ja _invalid

        sub rdx, '0'    ; getting decimal value
        mul rbx         ; rax = rax*10
        add rax, rdx    ; rax = rax + rdx
        jmp _toInteger  ; repeat
        ret

_invalid:
        mov rax, 1
        mov rdi, 1
        mov rsi, text
        mov rdx, len
        syscall
        ret

_appendEOL:
        ; getting EOL
        mov rcx, intMemory
        mov rbx, 10 ; EOL
        mov [rcx], rbx
        inc rcx
        mov [intAddress], rcx

_loopDigit:
        xor rdx, rdx
        mov rbx, 10
        div rbx
        push rax
        add rdx, '0'
        mov rcx, [intAddress]
        mov [rcx], dl
        inc rcx
        mov [intAddress], rcx
        pop rax
        cmp rax, 0
        jne _loopDigit

_printDigit:
        mov rcx, [intAddress]

        mov rax, 1
        mov rdi, 1
        mov rsi, rcx
        mov rdx, 1
        syscall
        mov rcx, [intAddress]
        dec rcx
        mov [intAddress], rcx
        cmp rcx, intMemory
        jge _printDigit

        ret

2 个答案:

答案 0 :(得分:2)

_toInteger是一个无限循环,它会永远检查第一个数字。您需要更好的循环条目和休息条件。

下一期是mul rbx。此指令也会更改EDX,这需要添加到下面的RAX行。如果您不想使用IMUL rax,rax,10,则可以使用LEA的算术能力:

add rax, rax                ; RAX = RAX * 2
lea rax, [rax + rax * 4]    ; RAX = (former RAX * 2) + (former RAX * 8)

另一个问题是SYS_READ_getText系统调用的棘手行为。您将不会获得带有null终止符的C样式字符串。如果根据SYS_READ有足够的位置,则\n会在RDX的末尾填充缓冲区。有时\n,有时不会 - 这对_toInteger来说不是一个有用的中断条件。 woirkaround是取消SYS_READ的最后一个字节,无论它是\n还是数字。这会将可用缓冲区缩短1。

_getText:
    mov rax, 0
    mov rdi, 0
    mov rsi, ascii
    mov rdx, 16
    syscall
    mov byte [ascii-1+rax], 0
    ret

SYS_READ给你的进一步惊喜做好准备。中断条件现在为空。我们这样做:

_toInteger:
    mov rbx,10      ; for decimal scaling
    xor rax, rax    ; initializing result
    mov rcx, ascii  ; preparing for working with input

    .LL1:           ; loops the bytes
    movzx rdx, byte [rcx]   ; getting current byte (digit)

    test rdx, rdx   ; RDX == 0?
    jz .done        ; Yes: break

    inc rcx         ; for the next digit

    cmp rdx, '0'    ; if it's less than '0' is not a digit
    jb _invalid

    cmp rdx, '9'    ; if it's greater than '9' is not a digit
    ja _invalid

    sub rdx, '0'    ; getting decimal value

    ; mul rbx         ; rax = rax*10
    add rax, rax
    lea rax, [rax + rax * 4]

    add rax, rdx    ; rax = rax + rdx

    ;jmp _toInteger  ; repeat
    jmp .LL1  ; repeat

    .done:
    ret

只是警告:_toInteger返回RAX中的整数,但您不保存此值。 EAX上的下一个写操作会破坏它。

答案 1 :(得分:1)

你的"无限循环"在你的_toInteger函数中。

RDX将为0或第一个元素或ASCII输入的值,因为您通过跳回标签_toInteger重置指向第一个元素的指针。因此,您永远不能离开或跳出循环。

我们不能强调这一点;你应该总是使用调试器。

 mov rcx, ascii  ; preparing for working with input

但即使你解决了这个问题,_toInteger函数似乎还有其他问题。

$ ./jazz_001
12
It's not an integer
20