歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux Kernel代碼藝術——系統調用宏定義

我們習慣在SI(Source Insight)中閱讀Linux內核,SI會建立符號表數據庫,能非常方便地跳轉到變量、宏、函數等的定義處。但在處理系統調用的函數時,卻會遇到一些麻煩:我們知道系統調用函數名的特點是sys_×××,例如我們想找open函數的內核系統調用代碼,在SI提供的符號表中搜索sys_open,能找到函數的聲明:

asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode);

原本SI提供從函數名按住Ctrl單擊鼠標左鍵能跳轉到定義處的功能,但運用在系統調用函數sys_open上卻失敗了,這是什麼回事呢?

系統調用宏定義展開

經過分析,原來內核中系統調用采用了宏定義,如這裡的sys_open就被定義為:

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)

可以猜測出這個宏定義展開之後就是上面函數聲明那樣的,難怪SI不能跳轉到系統調用的定義處呢!

下面以open系統調用為例分析這個宏是如何展開的:

首先在 include/linux/syscall.h 中有下面這樣的宏定義:

#define SYSCALL_DEFINE3(name, ...)                 \
   SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

針對這個宏定義有幾點說明:

  1. 反斜槓\:當宏定義過長需要換行時,在行尾要加上換行標志“\”;
  2. …:省略號代表可變的部分,下面用__VA_AEGS__ 代表省略的變長部分;
  3. ##:分隔連接方式,它的作用是先分隔,然後進行強制連接,例如:
#define VAR(type, name) type name##_##type
VAR(int, var1);
展開之後就是:
int var1_int;

那麼:

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
展開之後是:
SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
這又是一個宏,根據宏定義:
#define SYSCALL_DEFINEx(x, sname, ...)             \
   __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
展開為:
__SYSCALL_DEFINEx(3, _open, __VA_ARGS__)

再根據宏定義:
#define __SYSCALL_DEFINEx(x, name, ...)                    \
   asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

__SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
展開為:
asmlinkage long sys_name(__SC_DECL3(__VA_ARGS__))

這裡 __VA_ARGS__ 是 const char __user *, filename, int, flags, umode_t, mode,而同樣__SC_DECL3 又是一組宏定義:

#define __SC_DECL1(t1, a1) t1 a1
#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)

這樣,一步一步地展開:

__SC_DECL3(const char __user *, filename, int, flags, umode_t, mode)
==>   __SC_DECL3(const char __user *, filename, int, flags, umode_t, mode)
==>   const char __user* filename, __SC_DECL2( int, flags, umode_t, mode)
==>   const char __user* filename, int flags, __SC_DECL1(umode_t, mode)
==>   const char __user* filename, int flags, umode_t mode

最終:

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
宏定義展開之後就成為:
asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode);

正如我們之前猜測的那樣。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-12/110240p2.htm

Copyright © Linux教程網 All Rights Reserved