Чи має ядро ​​основну () функцію? [зачинено]


52

Я вивчаю драйвери пристроїв та програмування ядра. Згідно з книгою Джонатана Корбета, main()у драйверах пристроїв немає жодної функції.

Тож у мене два питання:

  • Чому нам не потрібна main()функція в драйверах пристроїв?
  • Чи має саме ядро main()функцію?

Може хтось мені це пояснить?


1
Також запитав цей самий користувач тут: stackoverflow.com/q/18266063/827263
Keith Thompson

@KeithThompson ... Так ... Просто тому, що я не отримав відповіді, що я хочу, тому я запитав це тут.
хтось

@Shadur ... так чи інакше, це вже буде закрито ... І я не маю привілею мігрувати це ...
хтось

Це повинно було бути закрито навпаки, у цього набагато більше переглядів :-)
Ciro Santilli 新疆 改造 中心 法轮功 六四

Відповіді:


82

У програмах простору користувача main()є точкою входу до програми, яка викликається кодом ініціалізації libc при виконанні двійкового файлу. Код ядра не має розкіш покладатися на libc, так як сам libc покладається на інтерфейс syscall ядра для розподілу пам'яті, вводу / виводу, управління процесами тощо.

При цьому, еквівалент main()коду ядра start_kernel(), який викликається завантажувачем після завантаження зображення ядра, декомпресує його в пам'ять і налаштовує необхідне обладнання та підкачку пам'яті. start_kernel()виконує більшість системних налаштувань і врешті-решт породжує процес init.

Точка входу до модулів ядра Linux - це функція init, яка реєструється в ядрі за допомогою виклику module_init()макросу. Потім зареєстрована функція модуля init викликається кодом ядра через do_initcalls()функцію під час запуску ядра.


11
Дякую, що визнали справжню мету mainметоду в C. (Це занадто поширена помилка, що ОС робить прямий виклик main, що не так, і тим більше, наприклад, на C ++.) I ' я дам вам ще одну пропозицію, якби я міг просто заради цього.
CVn

1
@Thomas ... Дякую за чудову відповідь ....
хтось

17

Ядро не має mainфункції. mainє поняттям мови С. Ядро пишеться на С і збирання. Вхідний код ядра записується складанням.

Послідовність завантаження організована наступним чином:

  1. Зазвичай BIOS завантажує завантажувач із пристрою завантажувального блоку. Популярний зараз завантажувач - grub.
  2. Grub завантажує зображення ядра в рамку, можливо з початковим кореневим пристроєм ( initrd). Потім виконується код за якоюсь адресою.
  3. У зображенні ядра є деякі модулі ядра, наприклад: модулі файлової системи, драйвери пристроїв. Зображення ядра використовує модуль файлової системи для монтажу кореневої файлової системи. Тепер ядро ​​може завантажувати та запускати всі модулі ядра з диска.
  4. Ядро виконує завдання ініціалізації. Наприклад: пройти шину PCI та знайти всі пристрої PCI, ініціалізувати всі драйвери пристроїв.
  5. Нарешті, ядро ​​створює процес 0 і процес 1 ( initпроцес), перемикає контекст ЦП з кільця 0 на кільце 3 і запускає процес init (ідентифікатор процесу 1). Тепер завантаження ядра закінчено!
  6. initПрограма запускає все системні сценарії запуску. Всі послуги запускаються. Оболонка називається. Користувачі можуть увійти в систему.

mainФункція є функцією С. Насправді основним методом не є точка входу в програми C. Виконання програми C заздалегідь викликає багато функцій main. GCC має особливість розширення: конструктори. Функції, оголошені "конструктором", називаються раніше main.

Наприклад:

/* This should not be used directly. Use block_init etc. instead. */ 
#define module_init(function, type) \
    static void _attribute__((constructor)) do_qemu_init ## function(void) { \
    register_module_init(function, type); \
} 

Цей макрос є з проекту qemu.


Основним методом є метод змінного струму. Фактично основним методом є не запис програми c. Програма виконує багато методів перед основним методом.
Едвард Шен

ну, біос зазвичай завантажує завантажувач, і цей завантажувач завантажує зображення ядра (і, можливо, initrd). Код ядра є у зображенні ядра, а не в initrd
Stéphane Chazelas

GCC має особливість розширення: конструктор. Оголошення методу "конструктор" викликається перед основним методом. Наприклад: / * Це не слід використовувати безпосередньо. Замість цього використовуйте block_init тощо. * / #define module_init (функція, тип) \ static void _attribute __ ((конструктор)) do_qemu_init ## функція (void) {\ register_module_init (функція, тип); \}
Едвард Шен

1
initrd.img НЕ є зображенням ядра. Це набір модулів, завантажених ядром під час завантаження. Зображення ядра зазвичай мають назви, що починаються з "vmlinuz", але відрізняються від distro до distro.
goldilocks

3
Ця відповідь набита "все - це PC / Linux / i86", і воно завантажується таким чином, і ядро ​​саме так ... Чому всі думають, що це єдиний можливий шлях у світі?
Єнс

9

Наприклад, існує функція main () в arch / x86 / boot / main.c для підготовки системи до переходу з реального в захищений режим, але інші архітектури не мають такого коду. Є хороший огляд того, як працює завантаження ядра Linux 2.6.x на платформі x86. Це справді варто прочитати.

Згідно з документом HOWTO займаються розробкою ядра Linux, ядро ​​Linux є

відокремлене середовище C, не покладаючись на стандартну бібліотеку C, тому деякі частини стандарту C не підтримуються.

що відповідно до стандарту C BTW означає це

Це визначається реалізацією, чи потрібна програма у вільно розташованому середовищі для визначення "головної" функції.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.