2017-05-09 51 views
1

我想編寫一個程序,在工作方式如下:大會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 
+0

聽起來像學習GDB(或其他調試器)的時候了 – Tommylee2k

+0

@ Tommylee2k這是什麼意思(?)我在上面的代碼中弄錯了什麼?我花了兩週的時間。幾乎不知道太少,我不明白你的意思): – Jazz

+0

這意味着,如果您試圖證明代碼的正確性(除了立即出現任何編譯時失敗規則),源是否編譯幾乎完全不重要。實際上,即使運行可執行文件並收到預期結果仍然遠不足以證明正確性。爲了至少接近這個難以捉摸的烏托邦目標,您應該使用調試器按指令逐步執行您的代碼指令,根據您的期望/設計在每次執行的指令後測試當前機器狀態,並測試不同的輸入,如空/空/ large/... – Ped7g

回答

1

_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) 

另一個問題是_getTextSYS_READ系統調用的棘手問題。你不會得到一個帶有空終止符的C風格的字符串。 SYS_READ最後用\n填充緩衝區 - 如果根據RDX有足夠的地方。有時候\n,有時候不會 - 這不是_toInteger的有用的休息條件。無論是\n還是一位數字,最簡單的方法是取消SYS_READ的最後一個字節。這將可用緩衝區縮短了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

對不起,對於遲到的回覆,但我對'GDB'(一個非常整潔的東西,真的)有點熟悉。我有4個問題,所以我感謝你的指導:'1)'在這個預期的程序中,除了由於乘法之後的溢出,'mul rbx'會改變'edx'寄存器嗎? (也許有關於我在這個問題中沒有考慮的字節)。 '2)'我知道每次循環將'rax 2'位的值向左移動以便爲下一個數字獲得一些空間後'rax rax,[rax + rax * 4]'。那是對的嗎? – Jazz

+0

'3)'您指出'SYS_READ'的問題是由於我隨意設置了用戶輸入字符串的長度這個事實,對吧? '4)'我讀了'imul'清除了溢出(如果我沒有錯,那就意味着'edx'沒有改變),但爲什麼要使用'imul'的三操作數形式,而不僅僅是一個操作數(或兩個操作數)。 – Jazz

+0

@Jazz:這是一個全球性的網站。即使延遲24小時也不失禮。 ** 1 **)'mul rbx'在EDX:EAX中產生64位結果,不僅是溢出。 ** 2 **)與前一行一起使用'LEA'行只是執行EAX = EAX * 10的一種方式。它不會更改EDX,也不會更改EDX。 ** 3 **)SYS_READ的問題是SYS_READ的問題。你過時無辜。我向SYS_READ提出了三個關於頂部的問題。點擊[tag:nasm]標籤,然後點擊「active」,你會在你的問題下面看到這些問題(由我修改)。 – rkhb

1

你的「無限循環」在你的_toInteger函數中。

RDX將爲0或您的第一個元素或ASCII輸入的值,因爲您通過跳回標籤_toInteger將指針重置爲第一個元素。因此,你永遠不能離開或跳出循環。

我們不能強調這一點;你應該總是使用一個調試器。

mov rcx, ascii ; preparing for working with input 

但即使你解決了這個問題,似乎還有_toInteger函數的其他問題。

$ ./jazz_001 
12 
It's not an integer 
20 
相關問題