2012-06-06 67 views
4

新人在這裏,我已經有一個問題。輸出數據在NASM的註冊值

我正在修改Jeff Duntemann的組裝書中使用的示例代碼,並且我想打印出存儲在數據寄存器中的整數值給終端?

什麼下面的下面的代碼確實是,它打印出好琴絃,在ECX推動價值不錯,但是當它到達了以下內容:

   pop ecx 
       mov eax,4       
       mov ebx,1       
       mov edx, ecx 

       int 80h 

它不上顯示EDX的內容終端,雖然我認爲我告訴它與mov eax,4等。

任何人都能夠給我任何「指針」(雙關語意)?參考

守則(修訂爲的17/06/2012):

SECTION .data 
    submessage: db "I am subtracting 5 from 10!", 10 
    msglen: equ $-submessage 

    ansmsg: db "Answer is:", 10 
    msglen2: equ $-ansmsg 
    EOL: db 10 

SECTION .bss 
    msg: resd 2           ; reserve space for 2 dwords 

SECTION .text 

global _start 

_start: nop 

;Displays test on shell 
        mov eax,4       ;print to terminal  
        mov ebx,1          
        mov ecx, submessage 
        mov edx, msglen 
        int 80h        ;"I am subtracting 5 from 10!" 

        mov eax,4       ;print to terminal 
        mov ebx,1            
        mov ecx, ansmsg 
        mov edx, msglen2 
        int 80h        ;"Answer is..." 

;Subtraction operation below:     
          mov edx, 10 
          sub edx, 5 
          mov [msg], edx    ; store 5 in msg 


; now we need to print msg to terminal        


          mov eax, 4     ;print to terminal 
          mov ebx, 1 
          mov dword [msg+1], 0xa  ;helps prints something out! 

        ;Encountered problem here= prints out 'Answe' instead of integer '5' 

          push dword 2    ; store size of msg 
          push dword [msg]   ; push to stack contents of msg 
          int 80h      

          add esp, 3     ;clean stack (2 push calls *4) 
          int 80h 

; I like labels :) 

sys_exit:       mov eax,1     ;exit status 
            mov ebx,0       
            int 80h 
             nop 

PS-如果我行縮進很爛,我想知道我怎麼能改善它;恕我直言學習大會得到更多的吸引力,一旦你瞭解了最初的學習「駝峯」:)

回答

1

首先,感謝這個問題 - 它促使我在int 80h學習,這是我以前不熟悉的東西。

您的程序在當前形式中做了什麼?它打印什麼?如果我在頭腦中正確執行它,我期望它打印第一條消息然後崩潰。由於緩衝,它可能甚至不會在可疑的崩潰之前顯示第一條消息。

int 80h/eax = 4映射到write()函數。運行'man 2 write'獲取完整的文檔。函數原型是:

ssize_t write(int fd, const void *buf, size_t count); 

因此,eax = 4,ebx = fd,ecx = buf,edx = count。如果你想對你的代碼註釋更迂迴,「mov eax,4」意思是「寫一個字符串到一個文件」,而「mov ebx,1」的意思是「指定文件#1,它映射到STDOUT(終端)」 。

我期望第一個int 80h調用打印一些東西。第二個int 80h調用是可疑的。此時eax和ebx保持不變。但是,edx也是不變的,並且保留了第一個字符串的字符串長度。更有問題的是,你把價值5放入ecx。 ecx將指針保存爲要寫入的字符串,而不是要寫入的值。所以當你在那裏放置5並調用中斷時,int將嘗試打印從地址0x00000005開始的字符串。這幾乎肯定會導致段錯誤(崩潰)。另外,如果我正確讀取int 80h文檔,則示例中的push/pop堆棧操作不具有任何相關性。

在ASM中打印一個數字作爲一個字符串有點麻煩。您需要將數字轉換爲字符串,然後使用int 80h打印。如果你只是想打印一個數字,這裏有一種方法可以作弊:

  • 在。數據部分,聲明一個新的字節,名爲int2char:'int2char:db 0'
  • 從ecx中減去5後,通過加上48將數字轉換爲ASCII(這會給你'5'而不是5)
  • store ecx到int2char
  • 移動int2char的地址到ECX
  • 集EDX爲1,因爲你只想打印1焦炭

與一個以上的數字轉換號碼將作爲練習留給你,一旦你得到這個工作。

祝你好運!

+0

是的!我嘗試了你的方法(你一直都在談論ASCII問題;程序最初解釋爲ASCII 5而不是整數5,當它將數值輸出到屏幕上時) 我做了一個類似的程序,它接受一個整數作爲輸入存儲到一個變量,我申請你的解決方案,截至目前該程序輸出正確的值,我是一個快樂的小兔子,謝謝! – Halodude

+0

很高興聽到,特別是因爲我還沒有找到時間通讀你的後續行動。 :-) –

1

我認爲推送消息是相關的。這是「hello world」程序的另一個例子。現在

section  .text 
    global _start      ;must be declared for linker (ld) 

_syscall:   
    int  0x80   ;system call 
    ret 

_start:       ;tell linker entry point 

    push dword len  ;message length 
    push dword msg  ;message to write 
    push dword 1   ;file descriptor (stdout) 
    mov  eax,0x4   ;system call number (sys_write) 
    call _syscall  ;call kernel 

         ;the alternate way to call kernel: 
         ;push eax 
         ;call 7:0 

    add  esp,12   ;clean stack (3 arguments * 4) 

    push dword 0   ;exit code 
    mov  eax,0x1   ;system call number (sys_exit) 
    call _syscall  ;call kernel 

         ;we do not return from sys_exit, 
         ;there's no need to clean stack 
section .data 

    msg  db  "Hello, world!",0xa  ;our dear string 
    len  equ  $ - msg     ;length of our dear string 

,我沒有寫上面的代碼,它來自這裏:

http://www.cin.ufpe.br/~if817/arquivos/asmtut/index.html#helloworld

所以你可以看到,這個作者是能夠移動值壓入堆棧,並調用內核例程將從參數棧中取出參數。這實際上對我來說更有意義,因爲我認爲這就是params傳遞給c函數的方式。通過特定寄存器傳遞參數是沒有意義的。如果一個方法有30個參數,如何通過寄存器傳遞?

在任何情況下,我已編譯上述代碼,將其鏈接並運行在我的macbook pro上,它工作正常。

無論如何,就像上面的例子一樣好,它並沒有教你太多。在這裏,我認爲,這是一個更好的例子,你將如何從寄存器打印任意值。

所以我想要的不是一個預定義的字符串,而是一個真正的編程結構;一個變量。

很容易的,你可以通過執行以下操作定義了一個32位的變量:

section .bss 
    msg:  resd 2 

這給了我一個變量(或存儲器位置)被稱爲「味精」,我可以的東西存入。通過用resd聲明它,我正在定義我希望保留的雙字的數量。雙字是32位,所以我聲明我希望保留2個雙字。爲什麼2?我會在一會兒告訴你。

到目前爲止這麼好。

現在,我需要做的就是將值移入該內存位置,並按照來自hello,world的示例對吧?所以我編碼了這個:

section  .text 
    global _start      ;must be declared for linker (ld) 

_syscall:   
    int  0x80   ;system call 
    ret 

_start:      ;tell linker entry point 
    mov dword [msg], 'h' ;move the letter h into my memory location 
    mov dword [msg+1], 0xa ;this is so important, but other author's gloss over it 
          ; the line terminator is essential in order to 
          ; print something out 
    push dword 2   ;message length 
    push dword msg  ;message to write 
    push dword 1   ;file descriptor (stdout) 
    mov  eax,0x4   ;system call number (sys_write) 
    call _syscall  ;call kernel 

         ;the alternate way to call kernel: 
         ;push eax 
         ;call 7:0 

    add  esp,12   ;clean stack (3 arguments * 4) 

    push dword 0   ;exit code 
    mov  eax,0x1   ;system call number (sys_exit) 
    call _syscall  ;call kernel 

         ;we do not return from sys_exit, 
         ;there's no need to clean stack 
section .bss 
    msg:  resd 1 

所以沒有太多改變。我添加了.bss部分,它用於未初始化的數據。比靜態字符串更有用。我們正在移動一個靜態值(字母h)到我的味精內存位置,但你可以很容易地移動這樣註冊

mov [msg], eax 

下一行是非常重要的,但每一個「Hello World」的作者只是掩飾它。該0xa是一個行結束符,需要或它WILL_NOT顯示您的值。這讓我瘋狂了很長一段時間,試圖弄清楚爲什麼我的東西不會打印出來。你需要那個行結束符。這也是爲什麼我們需要定義我們的變量來保存兩個值而不是一個值。我們需要存儲該行終止符。

其餘的很簡單,把參數扔到堆棧上並調用內核。現在你有一個真實的例子來說明如何從實際的可變數據位置打印出一些任意的數據。請享用!

+0

@Multimedia Mike,等待道歉,不知道這個問題是否會得到任何答案!我爲你的問題修改了你的代碼,這有點奏效。它設法在.bss中輸出一個變量的內容。但是我遇到了一個新問題。 當我通過調試器(我使用洞察)編譯,鏈接和運行他的代碼時,我發現不是輸出數字'5'(因爲10-5 = 5),而是決定輸出ansmsg的前5個字符.data部分。 我已經在使用你的想法後修改了我的代碼。 – Halodude