Подтвердить что ты не робот

Статические функции в драйвере устройства Linux

Почему каждая функция в большинстве драйверов устройств статична? Поскольку статические функции не видны за пределами области файла. Затем, как эти функции драйвера вызываются приложениями пользовательского пространства?

4b9b3361

Ответ 1

Помните, что в C все адреса. Это означает, что вы можете вызвать функцию, если у вас есть адрес. Ядро имеет макрос с именем EXPORT_SYMBOL, который делает именно это. Он экспортирует адрес функции, чтобы функции драйвера могли быть вызваны без необходимости размещения объявлений заголовков, поскольку эти функции иногда не известны во время компиляции. В подобных случаях статический классификатор просто делается для обеспечения того, чтобы они вызывались только этим методом, а не из других файлов, которые могут включать этот код драйвера (в некоторых случаях не рекомендуется включать заголовки кода драйвера и вызывать их напрямую).

EDIT: Поскольку было указано, что я не охватывал пространство пользователей.

Функции драйвера обычно не вызываются через пользовательское пространство напрямую (кроме реализации x86 инструкции SYSCALL, которая делает некоторые небольшие трюки, чтобы иногда сохранять контекстный переключатель). Таким образом, статическое ключевое слово здесь не имеет значения. Это только влияет на пространство ядра. Как отмечалось в @Cong Wang, функции обычно помещаются в структуру указателей функций, так что их можно вызвать, просто имея структуры, указывающие на эту структуру (например, файловые_программы, планировщики, файловые системы, сетевой код и т.д.).

Ответ 2

Поскольку эта статическая функция не предполагается использовать напрямую вне модуля. Они вызываются другими функциями в модуле, среди которых может быть интерфейс для 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() напрямую.

Ответ 3

Ядро имеет тысячи модулей, и они являются (или используются) всеми объектными файлами, загружаемыми динамически с помощью процесса, аналогичного привязке - или фактически связаны - с исполняемым файлом. Можете ли вы представить, сколько будет конфликтов имен, если бы все они экспортировали все их имена функций, как и поведение по умолчанию C, если не указано static?

Приложения для пользовательского пространства не могут напрямую вызвать функции драйвера, но есть другие способы для взаимодействия.