2013-01-20 17 views
13

爲什麼大多數設備驅動程序中的每個函數都是靜態的?由於靜態函數在文件範圍之外不可見。那麼,這些驅動程序功能如何被用戶空間應用程序調用?Linux設備驅動程序中的靜態函數

+0

可能的重複:http://stackoverflow.com/questions/12917198/linux-device-driver-program-where-the-program-starts/12923107#12923107你忽略了這些靜態函數的一些是事實在*操作*結構中使用,它允許通過標準驅動程序接口(例如文件操作)間接訪問這些靜態例程。 – sawdust

回答

11

記住比在C中一切都是地址。這意味着如果你有地址,你可以調用一個函數。內核有一個名爲EXPORT_SYMBOL的宏就是這樣做的。它導出一個函數的地址,以便調用驅動函數而不必放置頭聲明,因爲這些函數有時在編譯時不知道。在這種情況下,靜態限定符僅用於確保它們僅通過此方法調用,而不是從可能包含該驅動程序代碼的其他文件調用(在某些情況下,包含驅動程序代碼頭並直接調用它們並不是一個好主意) 。

編輯:既然有人指出我沒有覆蓋用戶空間。

驅動程序函數通常不直接通過用戶空間調用(SYSCALL指令的x86實現除外,它有時會執行一些小技巧來保存上下文切換)。所以這裏的static關鍵字沒有區別。它僅在內核空間上有所不同。正如@Cong Wang指出的那樣,函數通常放置在函數指針的結構中,以便可以通過簡單地指向這個結構的結構(比如file_ops,調度器,文件系統,網絡代碼等)來調用它們。

+0

「通過此方法調用」。此方法是什麼。你的意思是EXPORT_SYMBOL宏? –

+0

@Sibrajas是的,這主要是爲了確保您不依賴動態驅動程序(它並不總是可用)。 –

+0

這個「答案」是假的,但票數最多?!驅動程序中的導出符號只能由其他內核例程使用,並且不能從用戶空間訪問。僅僅因爲你「知道」地址並不意味着用戶空間程序可以訪問該地址。Linux是使用MMU的受保護內核。 – sawdust

7

因爲這些靜態功能不應該被用於直接以外的模塊。它們被模塊中的其他函數調用,其中可以是ioctl或任何回調函數的接口。這就是爲什麼他們可以從用戶空間調用,他們只是在呼叫路徑。

看一看網絡虛設模塊:

dummy_dev_init()顯然是靜態的:

static int dummy_dev_init(struct net_device *dev) 
{ 
     dev->dstats = alloc_percpu(struct pcpu_dstats); 
     if (!dev->dstats) 
       return -ENOMEM; 

     return 0; 
} 

但它是一個回調 - )> ndo_init(註冊該網絡設備時被調用。

static const struct net_device_ops dummy_netdev_ops = { 
     .ndo_init    = dummy_dev_init, 
     .ndo_uninit    = dummy_dev_uninit, 
     .ndo_start_xmit   = dummy_xmit, 
     .ndo_validate_addr  = eth_validate_addr, 
     .ndo_set_rx_mode  = set_multicast_list, 
     .ndo_set_mac_address = eth_mac_addr, 
     .ndo_get_stats64  = dummy_get_stats64, 
     .ndo_change_carrier  = dummy_change_carrier, 
}; 

很明顯,沒有人應該直接調用dummy_dev_init()。

2

內核擁有數千個模塊,它們(或曾經是)所有的目標文件,通過類似於鏈接的過程動態加載 - 或者實際上鍊接到可執行文件中。你能想象如果它們全都導出所有函數名稱,那麼會有多少名稱衝突,除非指定了static,否則默認的C行爲也是如此。

用戶空間應用程序不能直接調用驅動程序功能,但有other ways進行交互。

+0

通過直接調用它們,我的意思是編譯時調用某個特定驅動程序的方法,而無需執行ioctl或將自己註冊爲某個設備或某些設備。總是可以只做一個頭部或外部函數並刪除靜態關鍵字:P –