2013-01-20 57 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 –