概述: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位)
=輸出運算元,輸出值將替換前值
+表示運算元可讀可寫
&早期彙編的運算元。表示在使用完運算元之前,內容會被修改
外部參考:linux核心完全剖析第三章
C 嵌入彙編
1.include include using namespace std int main cout 直接在watch裡面輸入暫存器的名字就可以 如,eax,ax,ah,al 3.函式呼叫,引數及返回值 具體例子 這篇中有的例子不是很好,比如第五個例子,只用暫存器就可以控制迴圈,不知道為什麼要加上...
C語言嵌入彙編
概述 linux核心原始碼中,有很多c語言中嵌入了彙編語句,如何理解這些彙編語句,對理解核心有很重要的作用。具有輸入和輸出引數的嵌入式彙編語句的基本格式為 asm 彙編語句 輸出暫存器 輸入暫存器 會被修改的暫存器 除第一行以外,後面帶冒號的行若不使用就都可以省略。彙編語句 是你寫彙編指令的地方 輸...
C語言怎樣嵌入彙編
tips 在編譯過程匯中,彙編 塊是原封不動地送到組合語言編譯階段的。o8 q y3 c s r 一 為什麼會用到彙編?n3 m2 7 d 8 l 二 何時使用彙編?b,k q0 b 第一種情況是,絕對沒有其他方法可以使用。l d8 t6 m6 v c t e s 第二種情況出現在某個c語言程式的執...