2017-07-28 75 views
0

我學習組件使用以下的Hello World程序如何打印字符串的長度在裝配

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

_start:    ;tells linker entry point 
    mov edx,len  ;message length 
    mov ecx,msg  ;message to write 
    mov ebx,1  ;file descriptor (stdout) 
    mov eax,4  ;system call number (sys_write) 
    int 0x80  ;call kernel 

    mov eax,1  ;system call number (sys_exit) 
    int 0x80  ;call kernel 

section .data 
    msg db 'Hello, world!', 0xa ;our string 
    len equ $ - msg    ;length of our string 

原來的問題我是什麼是字符串的長度的意思。這是否意味着字符數或內存中的長度(字節數)? 檢查這個我想打印變量len。我怎樣才能做到這一點?我天真地試圖定義新的變量

len2 equ $ - len 

,然後改爲運行

mov edx,len2  ;message length 
    mov ecx,len  ;message to write 
    mov ebx,1  ;file descriptor (stdout) 
    mov eax,4  ;system call number (sys_write) 
    int 0x80  ;call kernel 

嘗試打印LEN,但這種印刷什麼。如何打印由len代表的號碼?

+5

您可能需要檢查[**如何在彙編NASM中打印數字**](https://stackoverflow.com/questions/8194141/how-to-print-a-number-in-assembly- nasm)簡短的回答是你寫*字符*到'stdout'。數字是一個十進制值,而不是可以立即寫入的字符串,您必須將整數或無符號值轉換爲其字符表示形式,然後將其寫入'stdout'。 –

+0

出於好奇,你編程的操作系統是什麼?視窗? Unix的?蘋果系統?我在問,因爲在這樣的問題之上,經常有人問這個問題是否使用了錯誤平臺的教程。 –

+0

謝謝。我正在使用Ubuntu。出於好奇,當我嘗試直接使用stdout打印數字時,我什麼也沒有得到。爲什麼它不打印什麼,而不是打印一些廢話? –

回答

0
... 
    mov edx,len  ;message length 

這會加載edx帶有某種數值,如14這種情況下。 len是「當量」恆定符號,像在#define C.

mov ecx,msg  ;message to write 

此加載與ecx第一個字符的地址(msg是標籤,指向存儲器)。

mov ebx,1  ;file descriptor (stdout) 
    mov eax,4  ;system call number (sys_write) 
    int 0x80  ;call kernel 
    ... 

    msg db 'Hello, world!', 0xa ;our string 

這定義了14個字節的存儲器,其值爲72('H'),101('e')......。第一個字節由msg標籤(它的內存地址)指向。

len equ $ - msg    ;length of our string 

這定義了編譯時可見的常量len。它沒有定義任何內存內容,所以你不能在可執行文件或運行時找到它(除非使用,例如mov edx,len,那麼它就會被編譯成特定的指令)。

的定義是$ - msg,將$在這方面的工作爲「當前地址」,下一個定義的機器代碼的字節將被編譯,所以在這個地方它等於msg + 14(我希望我沒有算人數字符正確:))。並且((msg+14) - msg) = 14 =定義在len的定義和標籤msg之間的存儲器中定義的字節數。

請注意,我如何避免字作爲變量或字符,ASM是更低的水平,所以標籤到內存和字節是更準確的措辭,我希望它會幫助你識別細微的差異。

len2 equ $ - lenlen後也這樣定義len2(msg+14)len這是14(仍然存在於內存中,通過定義len不添加任何新的字節),讓你有效地定義len2等於msg值。

然後:

mov edx,len2  ;message length 
    mov ecx,len  ;message to write 
    ... 

是否與指針調用sys_write串等於14(無效存儲器參考,該內存區域是禁止普通用戶代碼),並且長度等於地址msg,這將在32b linux上很可能有一些值,如0x80004000,即超過2G的字符輸出。

sys_write自然不會那樣,失敗並返回錯誤代碼eax

要輸出什麼關係sys_write,你必須首先將其寫入內存ASCII(我覺得UTF8默認情況下,在Ubuntu外殼支持,但懶得去核實)編碼字符串,並賦予該內存的sys_write地址安慰和字節長度(UTF8字符串字節和字符之間的差異很重要,sys_write不知道字符,它與二進制文件和字節一起工作,所以長度是字節量)。

我不會寫代碼輸出數字,因爲這是幾行(實現簡化的printf),SO有幾個Q + A,但我希望我的解釋能幫助你理解發生了什麼,以及如何有用。

如果你剛開始學習ASM,認爲無論是鏈接到的clibprintf可用的,甚至更好,使用調試器和調試器在寄存器中直覈實值,不串輸出困擾了,這是一個有點更高級的話題,然後是最初的算法,以及基本的流量控制和操作堆棧。在你更熟悉基本指令的工作方式以及如何調試代碼之後,然後嘗試輸出數字會更容易。