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

时间:2013-01-20 09:47:55

标签: c static linux-kernel linux-device-driver static-functions

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

3 个答案:

答案 0 :(得分:12)

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

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

驱动程序函数通常不是直接通过用户空间调用的(除了x86实现的SYSCALL指令,它有时会做一些小技巧来保存上下文切换)。所以这里的静态关键字没有区别。它只会对内核空间产生影响。正如@Cong Wang所指出的,函数通常放在函数指针的结构中,这样它们就可以通过简单地让结构指向这个结构来调用它们(比如file_ops,调度程序,文件系统,网络代码等......)。

答案 1 :(得分: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 :(得分:2)

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

用户空间应用程序无法直接调用驱动程序函数,但有other ways进行交互。