2017-06-25 44 views
5

我目前通過遵循Kip Irvine的「彙編語言x86編程」書籍學習彙編編程。x86彙編程序中「數據標籤」的功能是什麼?

在這本書中,作者試圖解釋的data label

數據標籤標識變量的位置的概念,提供到引用該變量在代碼 方便的方法。以下,爲了 例如,定義了一個名爲計數變量:

count DWORD 100 

彙編 數字地址分配給每個標籤。

所以我什麼data label做的理解是:數據標籤count是包含一個數值,其中數值是在內存中的位置的變量。當我在我的代碼中使用count時,實際上我使用的是存儲器中該位置中包含的值,在本例中爲100.

我對數據標籤的理解是否正確?如果有些不正確,有人可以指出錯誤嗎?

+4

數據標籤是保存數據的內存地址的引用(別名)。 'count DWORD 100'創建一個標籤,該標籤的偏移量在程序運行時最終會被識別。 'count'是標籤。它最終會有一個地址。在該地址有一個32位值(DWORD)等於100 –

+0

@MichaelPetch,所以當我在我的代碼中使用'count'數據標籤時,我實際上使用了包含在該內存位置中的值。如果我想知道'count'的實際內存位置怎麼辦?有可能獲得內存位置的實際值嗎? – Thor

+2

在masm中,您可以使用'offset'關鍵字來獲取'count'的地址。如果你有一個32位的程序'mov eax,offset count'會把count的32位地址移到eax中。 'mov eax,[count]'將在與_EAX_中count相關的地址處移動32位值。您還可以使用'lea eax,[count]''等東西來獲取帶有_LEA_的標籤地址。使用_LEA_(加載有效地址),您不使用'offset'關鍵字。 –

回答

5

標籤是寫入內存地址的一種象徵性方式,不外乎是。標籤本身沒有空間,只是一種方便的方式,讓您稍後參考內存中的該位置。 (而且,它們也可以變成對象文件中的符號,以允許在鏈接時計算數字地址,而不是在彙編時計算。但是對於在同一文件中定義和引用的標籤,這種額外的複雜性主要是不可見的;關於地址是鏈接時間常數,而不是組裝時間,請參閱下文。)

eg

; NASM syntax, but the concepts apply exactly to MASM as well 
; For MASM, you may need BYTE PTR or whatever size overrides in loads. 
section .rodata  ; or section .data if you want to be able to store here, too. 
COUNT: 
    db 0x12 
FOO: 
    db 0 
BAR: 
    dw 0x80FF  ; same as db 0xff, 0x80 

mov eax, [COUNT] 4字節負荷將得到0x80FF0012(因爲86是小端)。來自FOO(如mov cx, [FOO])的2字節加載將得到0xFF00。

實際上,您可能會以這種方式使用來自常量的重疊荷載,例如,有些字符串是其他字符串的子字符串。對於以空字符結尾的字符串,只能將通用後綴以這種方式組合到相同的存儲空間中。


現在這是否意味着COUNT是一個4字節的變量或1字節的變量?不,不是。彙編語言並不真正具有「變量」。

變量是一個更高層次的概念,你可以彙編語言帶有標籤是保留一些靜態空間彙編指令執行。請注意,標籤與上述示例中的db指令是分開的。

但是一個變量不需要有任何靜態存儲空間:例如,您的循環計數器變量可以(並且通常應該)僅存在於寄存器中。

變量甚至不需要具有單個固定位置。它可以在函數的一部分被分散到堆棧中,但它不在函數的另一部分中存在於寄存器中。在編譯器生成的代碼中,變量通常會在寄存器之間無緣無故地移動,因爲編譯器甚至不會嘗試爲同一個變量使用相同的寄存器。


請注意,MASM會基於它後面的指令隱式地將標籤與操作數大小相關聯。因此,如果mov eax, [count]給出操作數大小不匹配錯誤,則可能必須編寫mov eax, dword ptr [count]

有些人認爲這是一個功能,但其他人認爲這個奇妙的操作數大小的東西是奇怪的。 NASM語法沒有任何這種魔法。你可以知道一條線將如何組裝,而不必去找到標籤的定義位置。 add [count], 1是NASM中的錯誤,因爲沒有暗示操作數大小。

不要一直以爲C語言中所有使用變量的東西都必須在彙編語言程序中有標籤的靜態存儲。但是,如果您確實想要使用「變量」這個術語來表示靜態數據存儲+像Kip Irvine這樣的標籤,那麼請繼續。


另請注意,數據標籤並非特殊或與代碼標籤不同。沒有什麼能阻止你寫作jmp COUNT。解碼12 00 FF 80作爲(一系列)x86指令作爲練習留給讀者,但是(如果它在具有執行權限的頁面中),它將被CPU取出並解碼。

同樣,沒有什麼能阻止你從代碼標籤中加載數據作爲內存操作數。混合代碼和數據(所有的CPU使用分離的L1D和L1I高速緩存)並不是一個好的主意,但這也起作用。在典型的操作系統(如Linux)中,可執行文件的文本段包含代碼和只讀數據段,並且被映射爲讀取和執行權限。 (但不能寫入權限,所以嘗試存儲將會出現故障,除非您修改權限。)

JIT編譯器將機器代碼寫入緩衝區,然後跳到那裏。它可能是一個帶有標籤的靜態緩衝區,但更通常的情況是它將是一個動態分配的緩衝區,其地址是一個變量。


靜態地址通常是鏈接時間常量,但通常不是彙編時間常量。 (除非你正在編寫自舉程序,或者其他地方肯定加載了一個已知地址,那麼org 0x100可能會有用。)這意味着你可以做mov al, [COUNT+2],但不是mov al, [COUNT*2]。 (對象文件格式支持整數位移,但不支持其他數學運算符)。

在PIC代碼中,標籤地址甚至不是鏈接時間常量,但至少在64位PIC代碼中,從代碼到數據標籤的偏移量是鏈接時間常量,因此可以使用RIP相對尋址沒有額外的間接水平(通過全局抵消表)。