概述:linux核心原始碼中,有很多c語言中嵌入了彙編語句,如何理解這些彙編語句,對理解核心有很重要的作用。
具有輸入和輸出引數的嵌入式彙編語句的基本格式為:
asm("彙編語句"
:輸出暫存器
:輸入暫存器
:會被修改的暫存器);
1 #define get_seg_byte(seg,addr) \
2 ( )
這段**定義了乙個嵌入式組合語言函式。通常使用組合語言最方便的方法是把他們放在乙個巨集內。用圓括號括住的組合語句(花括號中的語句)「({})」可以作為表示式使用,其中最後一行的變數_res是該表示式的輸出值。
因為巨集語句需要定義在一行上,因此這裡使用反斜槓「\」將這些語句連成一行。這條紅第一將被替換到程式中引用改巨集名稱的地方。第一行定義了巨集的名稱,即巨集函式名稱get_seg_byte(seg,addr)。第三行定義了乙個暫存器變數_res。該變數將被儲存在乙個暫存器中,以便快速訪問和操作。如果想指定暫存器(如eax),那麼我們可以把改句寫成"register char _res asm("ax");",其中asm也可以寫成_asm_。第四行上的_asm_表示嵌入式彙編語句的開始。第4-7行的4條語句是at&t格式的彙編語句。另外,為了讓gcc編譯產生的組合語言程式中暫存器名稱前有乙個百分號「%」,在嵌入彙編語句暫存器名稱前就必須寫上兩個百分號「%%」。
第8行即輸出暫存器,該語句的含義是在這段**執行結束後將eax所代表的的暫存器的值放入_res變數中,作為本函式的輸出值,「=a」中的「a」稱為載入**,「=」表示這是輸出暫存器,並且其中的值將被輸出值替代。載入**是cpu暫存器,記憶體位址以及一些數值的簡寫字母代號。第9行表示在這段**開始執行時將seg放到eax暫存器中,「0」表示使用與上面相同位置上的輸出暫存器。而((*addr))表示乙個記憶體偏移位址值。為了在上面彙編語句中使用該位址值,嵌入式匯程式設計序規定把輸出和輸入暫存器按統一順序編號,順序是從輸出暫存器序列從左到右從上到下以「%0」開始,分別記為%0、%1···%9.因此,輸出暫存器的編號是%0(這裡只有乙個輸出暫存器),輸入暫存器前一部分(「0」(seg))的編號是%1,而後部分的編號是%2。上面第6行上的%2即代表(*(addr))這個記憶體偏移量。
常用暫存器載入**說明
**說明
**說明
a使用暫存器eax
m使用記憶體位址
b使用暫存器ebx
o使用記憶體位址並可以加偏移值
c使用暫存器ecx
i使用常數0-31
d使用暫存器edx
j使用常數0-63
s使用esi
k使用常數0-255
d使用edi
l使用常數0-65535
q使用動態分配位元組可定址暫存器(eax,ebx,ecx或edx)
m使用常數0-3
r使用任意動態分配的暫存器
n使用1位元組常數(0-255)
g使用通用有效的位址即可(eax,ebx,ecx,edx或記憶體變數)
o使用常數0-31
a使用eax與edx聯合(64位)
=輸出運算元,輸出值將替換前值
+表示運算元可讀可寫
&早期彙編的運算元。表示在使用完運算元之前,內容會被修改
C嵌入彙編
概述 linux核心原始碼中,有很多c語言中嵌入了彙編語句,如何理解這些彙編語句,對理解核心有很重要的作用。具有輸入和輸出引數的嵌入式彙編語句的基本格式為 asm 彙編語句 輸出暫存器 輸入暫存器 會被修改的暫存器 1 define get seg byte seg,addr 2 這段 定義了乙個嵌...
C 嵌入彙編
1.include include using namespace std int main cout 直接在watch裡面輸入暫存器的名字就可以 如,eax,ax,ah,al 3.函式呼叫,引數及返回值 具體例子 這篇中有的例子不是很好,比如第五個例子,只用暫存器就可以控制迴圈,不知道為什麼要加上...
Linux 0 11彙編的語法問題
define set tssldt desc n,addr,type asm movw 104,1 n t movw ax,2 n t rorl 16,eax n t movb al,3 n t movb type 4 n t 這裡用了 type 後面用了 0x89 type 在這裡為何要加上雙引號...