Yog*_*R.L 14 c static linux-device-driver linux-kernel static-functions
为什么大多数设备驱动程序中的每个功能都是静态的?由于静态函数在文件范围之外不可见.那么,这些驱动程序函数如何被用户空间应用程序调用?
Jes*_*mos 13
记住比在C中一切都是地址.这意味着如果你有地址,你可以调用一个函数.内核有一个名为的宏EXPORT_SYMBOL,就是这样.它导出函数的地址,以便可以调用驱动程序函数而无需放置标头声明,因为这些函数有时在编译时不知道.在这种情况下,静态限定符只是为了确保它们只通过这种方法调用,而不是从可能包含该驱动程序代码的其他文件中调用(在某些情况下,包含驱动程序代码头并直接调用它们不是一个好主意) .
编辑:因为有人指出我没有覆盖用户空间.
驱动程序函数通常不是通过用户空间直接调用的(除了SYSCALL指令的x86实现,它有时会做一些小技巧来保存上下文切换).所以这里的静态关键字没有区别.它只会对内核空间产生影响.正如@Cong Wang所指出的,函数通常放在函数指针的结构中,这样它们就可以通过简单地让结构指向这个结构来调用它们(比如file_ops,调度程序,文件系统,网络代码等......).
因为这些静态函数不应该直接在模块外部使用.它们由模块中的其他函数调用,其中可以是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;
}
Run Code Online (Sandbox Code Playgroud)
但它是 - > 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,
};
Run Code Online (Sandbox Code Playgroud)
显而易见,没有人应该直接调用dummy_dev_init().