
В исходном коде Linux есть два разных файла head.S, расположенных по адресу:
арка/рука/ботинок/сжатый/голова.S
Какова цель каждого из них и каков порядок их выполнения?
решение1
Я приветствую лучшие ответы, но я понимаю, что это код запуска ядра (который зависит от архитектуры), написанный вручную на ассемблере (помните, на данный момент у нас есть только голый процессор и прямой доступ к памяти; мы не можем получить доступ к сложным библиотекам, хранящимся в файловой системе, потому что у нас пока нет файлового менеджера — это все равно, что спрашивать, кто создал большой взрыв). Не путайте это с загрузчиком (который загружает загрузочный сектор с диска в оперативную память). Я сам перепутал их в своем предыдущем ответе.
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
' bootloader ' ' kernel '
' ' ' '
+------+ ' +-----------------------------------+ +------------------------------+ ' ' +-----------------------------+ +---------------------------------------+ '
| BIOS | --> ' | arch/x86/boot/header.S::call main | --> | arch/x86/boot/main.c::main() | ' --> ' | init/main.c::start_kernel() | --> | arch/x86/kernel/setup.c::setup_arch() | '
+------+ ' +-----------------------------------+ +------------------------------+ ' ' +-----------------------------+ +---------------------------------------+ '
' ' ' '
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
(ПРАВКА: это Minix, я изначально ошибочно его указал)
+------+ +--------------------+ +------------------+ +------------------------+
| BIOS | --> | Bootloader (mbr.S) | --> | startup (head.S) | --> | kernel/main.c::kmain() |
+------+ +--------------------+ +------------------+ +------------------------+
В конце head.S вы увидите строку
call _C_LABEL(kmain)
что является точкой входа в ядро:
kernel/main.c
Я считаю, что head.S
он прикрепляется к верхней части образа ядра во время компиляции. BIOS знает, что нужно выполнить этот блок кода, потому что он находится в самом начале и является корневой файловой системой ram-диска.
Что касается того, почему есть сжатая и несжатая часть, я думаю, это потому, что архитектурно-специфическая часть сборки образа ядра, ни один программист не достаточно квалифицирован, чтобы сделать сжатие. Как только мы можем перейти к процедуре, kmain
написанной на C (но скомпилированной в ассемблер), мы получаем доступ к процедуре распаковки, которая делает след ядра значительно меньше.
http://duartes.org/gustavo/blog/post/kernel-boot-process/
Точка входа с использованием сборки
Нам нравится писать все на C, но мы не можем избежать небольшого количества ассемблера. Мы напишем небольшой файл на языке ассемблера x86, который послужит отправной точкой для нашего ядра. Все, что сделает наш ассемблерный файл, это вызовет внешнюю функцию, которую мы напишем на C, а затем остановит поток программы.
Как нам убедиться, что этот ассемблерный код послужит отправной точкой ядра?
Мы будем использовать скрипт компоновщика, который связывает объектные файлы для создания конечного исполняемого файла ядра. (более подробно объяснено позже) В этом скрипте компоновщика мы явно укажем, что хотим, чтобы наш двоичный файл был загружен по адресу 0x100000. Этот адрес, как я уже говорил ранее, соответствует ожидаемому месту расположения ядра. Таким образом, загрузчик позаботится о запуске точки входа ядра.
http://arjunsreedharan.org/post/82710718100/kernel-101-lets-write-a-kernel