linux內核中的匯編語言

Linux內核代碼中,有一部分是用匯編語言編寫的。其大部分是關于中斷與異常處理的底層程序,還有就是與初始化有關的程序,以及一些核心代碼中調用的公用子程序。

用匯編語言編寫內核代碼中的部分代碼,大體上是出于如下幾個方面考慮:

1linux內核中的底層程序直接與硬件打交道,需要一些專用的指令,而這些指令在C語言中并無對應的語言成分。

2)內核中實現某些操作的過程、程序段或函數,在運行時會非常頻繁的被調用,這時用匯編語言編寫,其時間效率會有大幅度提高。

3)在某些特殊的場合,一段程序的空間效率也非常重要,比如操作系統的引導程序一定要容納在磁盤的第一個扇區中,多一個字節都不行。這時只能用匯編語言編寫。

Linux內核代碼中,以匯編語言編寫的程序或者程序段,有兩種不同的形式。一是完全的匯編代碼,這樣的代碼采用.s作為文件名的后綴。第二種是嵌入在C程序中的匯編語言片斷。

對于新接觸linux內核源碼的讀者,哪怕他比較熟悉i386匯編語言,在理解這些匯編程序時都會感到困難,有的甚至會望而卻步。其原因是:在內核匯編代碼中GNU采用不同于常用Intel i386匯編語言的AT&T格式的匯編語言;而在嵌入C程序的片斷中,更增加了一些指導匯編工具如何分配使用寄存器、以及如何與C程序中定義的變量相結合的語言成分。這些成分使得嵌入C程序的匯編語言片斷實際上變成了一種介乎386匯編和C之間的一種中間語言。

首先我們講一下AT&T格式與Intel格式匯編語言的以下主要區別,其它的詳細情況可以參考AT&T匯編語言手冊。

1)在Intel格式中大多使用大寫字母,而AT&T格式中都使用小寫字母。

2)在AT&T格式中,寄存器名上要加“%”作為前綴,而Intel格式則不帶前綴。

3)在AT&T格式中,指令的源操作數在前,目標在后,恰好與Intel格式完全相反。

4)在AT&T格式中,訪內指令的操作數大小由操作碼后綴來決定。用作操作碼后綴的字母有b(表示8位),w(表示16位),l(表示32位)。而在Intel格式中,則是在表示內存單元的操作數前面加上“BYTE PTR”,“WORD PTR”,“DWORD PTR”來表示。


當需要在C語言的程序中嵌入一段匯編語言程序段時,可以使用gcc提供的“asm”語句功能,例如,在include/asm/io.h中有這么一行:

#define __SLOW_DOWN_IO __asm__ __volatile__(“outb %a1,$0x80”)

這里,在asmvolatile前面的兩個“__”字符,這是gccC語言的一種補充,含義我們在前面已經講過了。下面我們看括號里面加上了引號的匯編指令,這是一條8位輸出指令,如前所述在操作符上加上后綴“b”表示是8位操作,而0x80因為是常數,所以要加上前綴“$”,而寄存器a1也加了前綴“%”

上面這個例子還是很容易理解的,因為這就是簡單的一條匯編語句,下面這個例子就困難多了(取子include/asm/atomic.h):

Static __inline__ void atomic_add(int i,atomic_t *v)

{

? __asm__ __volatile__

(

LOCK “addl %1,%0”

:”=m”(v->counter)

:”ir”(i),”m”(v->counter)

);

}

插入C代碼中的匯編語言代碼可以分成四部分,以冒號“:”加以分隔,其一般形式為:

指令部 : 輸出部 : 輸入部 : 損壞部

第一部分就是匯編語句本身,這一部分可以稱為指令部,是必需的,而其它各部分則可以視情況而定。所以在最簡單的情況下就與常規的匯編語句基本相同,如前面第一個例子。

當指令中的操作數要與C語言中的某些變量結合時,情況就復雜多了。如此例中,iv都是C語言函數的輸入部分,怎么將其與匯編語言結合在一起呢?因為程序員無法確切知道gcc在嵌入點的前后會把哪一個寄存器分配用于哪一個變量,而且還得有個手段把使用寄存器的要求告訴gcc,反過來影響它對寄存器的分配。針對這個問題,gcc采用的辦法是:程序員只提供具體的指令,而對寄存器的使用則只提供一個樣板和一些約束條件,而把到底如何與變量結合的問題留給gccgas去處理。

在指令部中,數字加上前綴%,表示需要使用寄存器的樣板操作數。這樣,指令部中用到了幾個不同的這種操作數,就說明有幾個變量需要與寄存器結合,由gccgas在編譯和匯編時根據后面的約束條件自行變通處理。那么,怎樣表達對變量結合的約束條件呢?這就是其余幾個部分的作用。輸出部用以規定對輸出變量的約束條件,必要時輸出部可以有多個約束,互相之間用逗號分隔。每個輸出約束以“=”號開頭,然后是一個字母表示對操作數類型的說明,然后是關于變量結合的約束。例如在本例中,輸出部里只有一個約束,“=m”表示相應的操作數(指令部中的%0)是一個內存單元v->counter

輸出部后面是輸入部,輸入約束的格式與輸出約束相似,但不帶號。在本例中有兩個輸入約束,第一個為”ir”(i),表示指令中的%1可以是一個寄存器中的直接操作數(i表示immediater表示任何寄存器),并且該操作數來自C代碼中的變量名i;第二個約束為”m”(v->counter)表示這是一個內存單元。

表示約束條件的字母有很多,主要有:“m””v””o”表示內存單元;”r”表示任何寄存器;”q”表示寄存器eaxebxecxedx之一;”i””h”表示直接操作數;”a””b””c””d”分別表示要求使用寄存器eax,ebx,ecxedx”S””D”分別表示要使用esiedi”I”表示常數(031)。

在有些操作中,除用于輸入操作和輸出操作數的寄存器以外,還要將若干寄存器用于計算或操作的中間結果。這樣,這些寄存器原有的內容就損壞了,所以要在損壞部對操作的副作用加以說明,讓gcc采取相應的措施,不過,有時候就直接把這些說明放在輸出部了。另外還應注意,當輸出部為空,即沒有輸出約束時,如果有輸入約束存在,則必須保留分隔標記“:”號。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383348.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383348.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383348.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構課程設計---c語言實現通訊錄(動態擴容+文件存儲)

1 題目一 : 通訊錄 1.1問題描述 編寫一個通訊錄管理系統,以把所學數據結構知識應用到實際軟件開發中去。每條信息至包含 :姓名(NAME )街道(STREET)城市(CITY)郵編&#…

linux內核panic

1. Linux Kernel Panic的產生的原因 panic是英文中是驚慌的意思,Linux Kernel panic正如其名,linux kernel不知道如何走了,它會盡可能把它此時能獲取的全部信息都打印出來。 有兩種主要類型kernel panic,后面會對這兩類panic做詳細…

數據結構課程設計------c實現散列表(二次探測再哈希)電話簿(文件存儲)

題目二 :散列表的設計與實現 2.1問題描述 設計散列表實現電話號碼查找系統,使得平均查找長度不超過2基本要求 (1)設每個記錄有下列數據項:電話號碼、用戶名、地址; (2)從鍵盤輸入各…

科技論文----論搜索引擎現狀及發展趨勢

搜索引擎現狀及發展趨勢 【摘要】 隨著最近10年中國互聯網的快速發展菜互聯網已經徹底改變了人們的生活方式,而在互聯網的發展過程中。搜索引擎發揮了巨大的推動作用。本文對搜索引擎的發展歷史采用的技術,發展現狀出現的問題以及未來發展方向進行了綜述…

inittab文件格式

/etc/inittab文件是Linux系統第一個進程init的配置文件。其每個記錄占一行,每行最多512個字符。該文件的每個記錄的格式為: id:runlevel:action:process 其中,id是一個不超過4個字符的標識,用來唯一標識一條記錄。runlevel表明該條…

數據結構課程設計------掃雷游戲(升級版,可展開)

本程序由團隊中的一個人所寫,本人看懂并寫下此文章 題目:掃雷 3.1問題描述 掃雷游戲 [基本要求] (1)完成棋盤的初始化并在標準顯示器中顯示 (2)通過輸入行列值確定用戶輸入 (3)游…

C語言的編譯鏈接過程的介紹

發布時間: 2012-11-08 10:17 作者: 未知 來源: 51Testing軟件測試網采編 字體: 小 中 大 | 上一篇 下一篇 | 打印 | 我要投稿 | 推薦標簽: DotNet 軟件開發 | 感言十年 C語言的編譯鏈接過程要把我們編寫的一個c程序(源代碼&#x…

vs2013鏈接Mysql時出現 (由于找不到libmysql.dll,無法繼續執行代碼。重新安裝程序可能會解決此問題)

將MySQL安裝目錄下的lib文件夾中 的libmysql.dll文件拷貝到C:\Windows\System32目錄下即可

gcc 優化選項 -O1 -O2 -O3 -Os 優先級,-fomit-frame-pointer

少優化->多優化: O0 -->> O1 -->> O2 -->> O3 -O0表示沒有優化,-O1為缺省值,-O3優化級別最高 英文解析: -O -O1 Optimize. Optimizing compilation takes somewhat more time, an…

const 和 #define 區別總結

const有類型,可進行編譯器安全檢查,#define 無類型,不可進行類型檢查const 有作用域,而#define 不重視作用域,默認定義在指定作用域下有效的常量,那么#define 就不能用(可以用#undef結束宏定義生…

Eclipse : Unresolved inclusion

Eclipse 中新建C 或C 到項目時&#xff0c;頭文件報警&#xff0c;顯示“Unresolved inclusion:<stdio.h>” 雖然不影響項目到編譯和運行&#xff0c;確也無法查看頭文件&#xff0c;讓人感覺實在不爽。下面是在國外到網站上看到解決方案&#xff0c;自己整理了一下拿來分…

c++對const增強 和cosnt分配內存情況

const增強 c語言中const是偽常量&#xff0c;可以通過指針修改 c中const會放到符號表中 c語言中const默認是外部連接&#xff0c;c中const默認是內部鏈接 #include<iostream> using namespace std;const int m_a 10; //在全局區域里&#xff0c;受到保護&…

Linux下crontab命令的用法

任務調度的crond常駐命令 crond 是linux用來定期執行程序的命令。當安裝完成操作系統之后&#xff0c;默認便會啟動此任務調度命令。crond命令每分鍾會定期檢查是否有要執行的工作&#xff0c;如果有要執行的工作便會自動執行該工作。而linux任務調度的工作主要分為以下兩類&am…

c++中引用的作用

引用的基本語法 用途起別名 Type &別名原名 引用必須初始化 一旦初始化后&#xff0c;不能修改 對數組建立引用 #include<iostream>using namespace std;//1.引用基本語法 Type &別名原名void test01(){int a 10;int &b a;cout << "a"…

LVM (Logic Volume Management,邏輯卷管理)

是傳統商業Unix就帶有的一項高級磁盤管理工具&#xff0c;異常強大。后來LVM移植到了Linux操作系統上&#xff0c;盡管不像原來Unix版本那么強大&#xff0c;但瘦死的駱駝比馬大&#xff0c;Linux的LVM仍然非常強大&#xff0c;可以在生產運行系統上面直接在線擴展硬盤分區&…

cpu中的MMU的作用

虛擬內存與物理內存之間的映射 用戶空間映射到物理內存是獨立的&#xff0c;提高安全性修改內存訪問級別 &#xff08;0是最高級&#xff09;

Linux命令行與Shell腳本編程大全讀書筆記

Linux內核4大主要功能&#xff1a; 內存管理 進程管理 設備管理 文件系統管理 Linux系統啟動的進程和腳本管理 1./etc/inittab 管理系統開機時會自動啟動的進程 2./etc/init.d 管理開機時啟動或停止某個應用的腳本放在這個目錄下&#xff0c;/etc/rcX.d目錄在啟動時&…

拷貝構造函數的總結

構造函數的分類及調用 按照參數分類 1.無參構造&#xff08;默認構造&#xff09; 2.有參構造按照類型分類 1.普通構造函數2.拷貝構造函數無參構造寫法和調用 Person p1; 注意不能寫Person (),因為編譯器認為這個是函數聲明有參構造函數寫法 和調用 Person p2(10) 或者Per…

技術與技巧札記

Linux常用命令及技巧&#xff1a; &#xff08;1&#xff09;cat /proc/version 查看當前內核的版本 (2) 掛載nfs文件夾&#xff1a;需要先確認在&#xff0f;etc&#xff0f;exports文件&#xff0c;可以用于開發板掛載的文件夾 mount -o nolock 10.0.22.30:/root/sharednfs …

c++中new的總結(動態管理,malloc存在的問題,malloc與new的區別)

c中使用malloc出現的問題 程序員必須確定對象的長度malloc 返回一個&#xff08;void *&#xff09;指針 &#xff0c;c不允許將&#xff08;void*) 賦值給其它指針&#xff0c;必須強轉malloc可能申請內存失敗&#xff0c;所以必須判斷返回值來保存內存分配成功用戶在使用對象…