【问题标题】:Static functions in Linux device driverLinux 设备驱动程序中的静态函数
【发布时间】:2013-01-20 09:47:54
【问题描述】:

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

【问题讨论】:

  • 可能重复:stackoverflow.com/questions/12917198/… 您忽略了这样一个事实,即在 operation 结构中使用了其中一些静态函数,这使得这些静态例程可以通过以下方式间接访问一个标准的驱动接口(例如文件操作)。

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


【解决方案1】:

因为这些静态函数不应该在模块之外直接使用。它们被模块中的其他函数调用,其中可以是 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】:

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

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

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

    【讨论】:

    • “通过这个方法调用”。这个方法是什么。你的意思是 EXPORT_SYMBOL 宏?
    • @Sibrajas 是的,主要是为了确保您不依赖动态驱动程序(并非总是可用)。
    • 这个“答案”是假的,但得票最多?!驱动程序中导出的符号只能由其他内核例程使用,并且不能从用户空间访问。仅仅因为您“知道”一个地址并不意味着用户空间程序可以访问该位置。 Linux 是一个使用 MMU 的受保护内核。
    • @sawdust 我意识到这一点,但我说的是从内核本身内部访问。我认为很明显,如果没有 ioctl 或通过其他系统调用,您不能直接从用户空间调用驱动程序。我在说的是,即使它在文件中声明为静态,您也可以获得地址(在内核中)并仍然调用该函数,但直接调用是不明智的。
    【解决方案3】:

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

    用户空间应用不能直接调用驱动函数,但是有other ways可以交互。

    【讨论】:

    • 通过直接调用它们,我的意思是编译时特定驱动程序的方法调用,而不执行 ioctl 或将自身注册为设备或类似的东西。总是可以只创建一个标题或外部函数并删除静态关键字:P
    猜你喜欢
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    • 2012-12-10
    • 1970-01-01
    相关资源
    最近更新 更多