Linux设备驱动程序中的静态函数

为什么大多数设备驱动程序中的每个function都是静态的? 由于静态函数在文件范围之外不可见。 然后,这些驱动程序函数如何被用户空间应用程序调用?

记住比在C中一切都是地址。 这意味着如果你有地址,你可以调用一个函数。 内核有一个名为EXPORT_SYMBOL的宏,它就是这样做的。 它导出函数的地址,以便可以调用驱动程序函数而无需放置标头声明,因为这些函数有时在编译时不知道。 在这种情况下,静态限定符只是为了确保它们仅通过此方法调用,而不是从可能包含该驱动程序代码的其他文件调用(在某些情况下,包含驱动程序代docker并直接调用它们不是一个好主意) 。

编辑:因为有人指出我没有覆盖用户空间。

驱动程序函数通常不会直接通过用户空间调用(除了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; } 

但它是 – > 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()。

内核有数千个模块,它们是(或曾经是)所有目标文件,通过类似于链接的过程动态加载 – 或者实际上是链接到可执行文件中。 你能想象如果它们都要导出所有的函数名,会有多少名称冲突,除非指定static否则默认的C行为是什么?

用户空间应用程序不能直接调用驱动程序函数,但还有其他交互方式 。