Почему может возникать путаница в порядке выполнения функций module_init и module_exit в модулях ядра Linux?

Добрый день, коллеги! <br/> У меня возникла проблема при написании каркаса модуля ядра. <br/> <br/> В коде ниже: <pre><code class="c">#include &lt;linux/init.h&gt;
#include &lt;linux/module.h&gt;
#include &lt;linux/kernel.h&gt;


static int __init hello_init(void) {
    printk("Hello, world 2!");
    return 0;
}


static void __exit hello_exit2(void) {
    printk("Goodbye, world 2!");
}


module_init(hello_init);
module_exit(hello_exit2);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mikhail");</code></pre> <br/> <br/> При загрузке модуля с помощью команды <i>insmod test-mod.ko</i> в журнале отображается сообщение " <i>Goodbye, world 2!</i> ", а при выгрузке с помощью <i>rmmod test-mod</i> появляется сообщение " <i>Hello, world 2!</i> ". Таким образом, функция hello_exit2 вызывается при инициализации модуля, тогда как hello_init вызывается при его завершении. <br/> Подскажите, в чем может быть причина такого поведения? Возможно, я что-то упускаю?
  • 12 ноября 2024 г. 10:03
Ответы на вопрос 2
Добрый день!

Ситуация, которую вы описали, действительно странная и не соответствует ожидаемому поведению модулей ядра Linux. По описанию вашего кода, всё должно работать корректно: функция `hello_init()` должна вызываться при инициализации модуля (например, при использовании команды `insmod`), а функция `hello_exit2()` — при его выгрузке (например, с помощью `rmmod`).

Если вы наблюдаете, что сообщения выводятся в обратном порядке, то есть сообщение от функции `hello_exit2()` появляется при загрузке модуля, а сообщение от `hello_init()` — при его выгрузке, возможно, проблема кроется в чем-то другом. Вот несколько возможных причин:

1. **Ошибки в коде**: Убедитесь, что в файле, который вы компилируете, нет другого кода, который также использует `module_init` и `module_exit`. Возможно, вы ошиблись в имени файла или инициализировали другие модули.

2. **Конфликт с другими модулями**: Если у вас есть другие модули с теми же именами функций или идентификаторами, это может вызвать путаницу. Убедитесь, что в системе не загружены другие модули с такими же именами.

3. **Ошибка сборки или старые бинарные файлы**: Возможно, в директории сборки остались старые бинарные файлы, которые не были удалены перед пересборкой модуля. Запустите `make clean`, чтобы удалить предыдущие собранные файлы, и соберите модуль заново.

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

5. **Версии ядра и компилятора**: Убедитесь, что компилятор и версия ядра совпадают. Несоответствия могут приводить к странным проблемам.

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

Вызов readelf -s test-mod.ko | grep FUNC выдает:
34: 0000000000000000    29 FUNC    LOCAL  DEFAULT    4 hello_init
35: 0000000000000000    22 FUNC    LOCAL  DEFAULT    6 hello_exit2
39: 0000000000000000    22 FUNC    GLOBAL DEFAULT    6 cleanup_module
41: 0000000000000000    29 FUNC    GLOBAL DEFAULT    4 init_module


То есть, похоже, что все функции на своих местах.

Еще один момент. При компиляции получаю ворнинг:
warning: the compiler differs from the one used to build the kernel
  The kernel was built by: gcc (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0
  You are using:           gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0


Сомневаюсь, что из-за этого может поменяться (как?) порядок вызова функций, но всё же...
Похожие вопросы