爲什麼32位下的系統調用要用asmlinkage

爲什麼32位下的系統調用要用asmlinkage

asmlinkage是告訴編譯器參數將通過堆棧傳遞。kernel 裏的system call函數中(C 函數),爲什麼每一個函數原型的前面都有一個"asmlinkage" 的tag?例如:

asmlinkage long sys_nice(int increment)

“asmlinkage” 是在i386 system call 實現中相當重要的一個gcc 標籤(tag)。

當system call handler(系統調用處理程序)要call相對應的system call routine(系統調用例程)時,便將一般用途的暫存器的值push 到stack 裏,因此system call routine 就要從stack來讀取system call handler 傳遞的參數。這就是asmlinkage 標籤的用意。因爲32體系結構,

system call handler 是assembly code,system call routine(例如:sys_nice)是C code,當assembly code 調用C function,並且是以stack 方式傳參數(parameter)時,在C function 的prototype(原型)前面就要加上"asmlinkage "。

加上"asmlinkage" 後,C function 就會由stack 取參數,而不是從register 取參數。

對於未從彙編代碼調用的C函數,我們可以安全地假定默認調用約定爲cdecl(或快速調用stacall ,這無關緊要,因爲gcc會做好調用方和被調用方參數傳遞的工作。默認調用約定可以是在編譯時指定)。但是,對於從彙編代碼調用的C函數,我們應該顯式聲明該函數的調用約定,因爲在彙編端傳遞參數的代碼已固定。例如,如果將patch_espfix_desc聲明爲asmlinkage,則gcc將編譯該函數以從堆棧中檢索參數,這與將參數放入寄存器的彙編端不一致。

爲什麼所有系統調用函數都使用堆棧來傳遞參數?

原因是在處理來自用戶空間的系統調用請求時,內核無論如何都需要將所有寄存器保存到堆棧中(以便在返回用戶空間之前恢復環境),所以之後參數在堆棧上可用,不需要再做其他的工作。

另一方面,如果要將fastcall用於調用約定,則需要完成更多工作。我們首先需要知道,當用戶程序發出系統調用時,在x86-linux中,%eax保存系統調用號,%ebx,%ecx,%edx,%esi,%edi,%ebp用於將6個參數傳遞給系統調用(在“ int 80h”或“ sysenter”之前)。但是,fastcall的調用約定是在%eax中傳遞第一個參數,在%edx中傳遞第二個參數,在%ecx中傳遞第三個,其他參數從右到左推入堆棧。這樣,爲了在內核中實施這種快速調用約定,除了將所有寄存器保存在堆棧上之外,還需要做一些其他的工作。

80x86 的 assembly 有2種傳遞參數的方法:

  1. register method
  2. stack method

Register method 大多使用通用寄存器組(general-purpose)傳遞參數,這種方法的好處是簡單快速。另外一種傳遞參數的做法是使用stack(堆棧),assembly code 的模式如下:

  1. push number1
  2. push number2
  3. push number3
  4. call sum

在 ‘sum’ procedure 裏取值的方法,最簡單的做法是:

  1. pop ax
  2. pop bx
  3. pop cx

其它有關asmlinkage

  1. asmlinkage是一個定義
  2. "asmlinkage"被定義在/usr/include/linux/linkage.h
  3. 如果您看了linkage.h,會發現"attribute"這個語法,這是gcc用來定義function attribute(功能屬性)的語法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章