Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 OS
 osjournal 
 Protected Mode 
 Hardware 
 Kernels
  Dark Fiber
  BOS
  QNX
  OS Dev
  Lecture notes
  MINIX
  OS
  Solaris
  История UNIX
  История FreeBSD
  Сетунь
  Эльбрус
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Linux Kernel 2.6...5163 
 Trees...935 
 Максвелл 3...860 
 Go Web ...814 
 William Gropp...794 
 Ethreal 3...778 
 Ethreal 4...766 
 Gary V.Vaughan-> Libtool...764 
 Rodriguez 6...754 
 Clickhouse...748 
 Steve Pate 1...747 
 Ext4 FS...747 
 Ethreal 1...735 
 Secure Programming for Li...718 
 C++ Patterns 3...711 
 Ulrich Drepper...691 
 Assembler...686 
 DevFS...653 
 Стивенс 9...643 
 MySQL & PosgreSQL...621 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org
Writing a Kernel in C
by Tim Robinson,

Introduction

Написание собственной ОС может длиться недели и месяцы . Но начинать можно , не имея даже особо специфических навыков в С-программировании.


The C Programming Language
Первоначально язык C разрабатывался как низкоуровневый язык . Компиляция С-программы мало отличается от кода , написанного на ассемблере , в том смысле , что си-шный код в конечном итоге транслируется во все тот же ассемблер .
Tools
Существуют 2 главных компонента , транслирующих С-код в машинный - компилятор и линкер . БОльшую работу выполняет компилятор . Есть компиляторы , которые генерят непосредственно исполняемые файлы , но как правило они вызывают линкер неявно.
Линкер обьединяет все обьекты и настраивает ссылочные связи между ними . Линкер позволяет писать код внутри одного проекта на нескольких языках .
Для написания ОС в максимальной степени подходят GNU gcc и ld linker, потому что:
*Они free и open-source

*ld поддерживает любой исполняемый формат

*gcc поддерживается практически на всех известных процах


GNU для различных операционных систем : MS-DOS - DJGPP, Windows - Cygwin. GCC по умолчанию входит во все линуксовые дистрибутивы .

Различные гну-шные тулзы полезны при разработке ОС : пакет binutils включает утилиту objdump , позволяющую исследовать внуренности исполняемых файлов и дизассемблировать их .
Наиболее популярными форматами сейчас являются юниксовый ELF и виндовый PE , поскольку они поддерживаются большинством линкеров . ELF попроще , PE помощнее . Оба хорошо документированы . Есть еще один бинарный формат - COFF , который более специфичен . В качестве альтернативы можно для ядер использовать flat binary format - то бишь отсутствие всякого формата . Ld генерит т.н. raw code , примером которого может служить MS-DOS-кий .COM format.

Недостатком всех основных компиляторов является то , что по умолчанию используется flat 32-битное адресное пространство . Поскольку они не используют far-указатели (48-bit seg16:ofs32) , это усложняет написание кода . Watcom кстати до сих пор обещает написать компилятор OpenWatcom , который теоретически должен поддерживать дальние указатели для 32-bit protected mode.

Есть еще несколько замечаний по поводу работы gcc и ld . Например , gcc похоже ложит символьные строки , используемые внутри функций , выше самих функций . Рассмотрим пример :
int main(void)
{
char *str = "Hello, world", *ch;
unsigned short *vidmem = (unsigned short*) 0xb8000;
unsigned i;

for (ch = str, i = 0; *ch; ch++, i++)
vidmem[i] = (unsigned char) *ch | 0x0700;
for (;;)
;
}


Код должен вывести строку “Hello, world” в видео-память . После компиляции строка окажется выше функции main , и если это залинковать с flat binary format и запустить, то ничего путного не выйдет . Победить это можно так :
* Написать функцию , которая будет вызывать main() и затем halt. В стартовой функции не должно быть символьных строк .

*Использовать опцию gcc -fwritable-strings. Строки будут выведены в data-сегмент .

В обычном мире пользовательских программ роль функции , которая вызывает функцию main() , играет crt0 .


Run-Time Library
Основную часть в написании собственной ОС займет переписывание run-time library, которая еще известна как libc. RTL уже является частью компилятора . Каждый вендор предлагает использовать различные RTL внутри одной OS: Microsoft Visual C++ предлагает различные библиотеки для различных вариантов debug/multi-threaded/DLL, MS-DOS как известно предлагают 6 различных моделей памяти .

Но для начала надо будет определиться с одним вариантом ран-тайм библиотеки . Эта библиотека должна будет соответствовать стандарту ISO C . Если вы напишите нестандартную библиотеку , все ваши программы будут непортабельны на другие ОС .

Существует большое количество си-шных функций , которые платформенно-независимы . например , большинство <string.h> и <wchar.h> могут быть просто скопированы .

Другие функции наоборот зависят от версии ядра , например <stdio.h> , даже printf() . По поводу printf(): большинство си-шных библиотек используют шаблон printf() для генерации аналогичных fprintf(), sprintf() и т.д. Нужно уметь пользоваться функциями , которые посылают символьный вывод на абстрактный интерфейс типа stream.

RTL несет ответственность не только за переносимость приложений , но и за нормальную работу ядра . Такие вещи , как strcpy() или malloc()) должны быть реализованы максимально просто и эффективно . Они должны быть доступны любому драйверо-писателю .


OS-Specific Support
С точки зрения ядра си ,вообще говоря, неидеален в плане получения доступа к железу . Это приводит к тому , что приходится либо делать инлайн , либо писать целые куски на чистом ассемблере . Поддержка инлайна существует для gcc для всех платформ . Чего нельзя сказать ни о Visual C++ , ни тем более о Borland C++. Gcc-инлайн будет пожалуй что помощнее- например , в нем можно явно указать , какие регистры можно модифицировать внутри инлайна .

Ассемблерный код может потребоваться и в user mode для вызова системных функций . Можно поместить вызовы прерываний прямо в RTL (как в MS-DOS ), или создать отдельную библиотеку (как в Windows NT ntdll.dll).

C++ in the Kernel
Точка зрения в линуксе на использование плюсов известна . В то же время некоторые целиком пишут оси на плюсах . При использовании плюсов прийдется потратить много усилий на промежуточный фрейм-ворк , помня о том , что плюсы имеют ограничения в плане переносимости .

Вам прийдется постоянно помнить о дилемме new - delete. Например , если вам понадобится какой-то глобальный обьект класса , нужно будет очень хорошо разобраться , как это делается у вашего вендора , возможно прийдется изучить изнутри что-то типа crt0.c. Если вы не дай бог захотите использовать в ядре try/catch , возможно вам тогда прийдется изобретать колесо , поскольку это уже реализовано в вашем нативном компиляторе , с помощью которого вы будете собирать свое плюсовое ядро .

Использование плюсовых exception handling и virtual classes вряд ли будет оправдано по причине их тормознутости . Ядро должно работать максимально быстро , а прелести дизайна имеют к этому мало отношения .


Итого
Написание ОС на языке C , прямо скажем , занятие гораздо более продуктивное , нежели на ассемблере . Такой компилятор как gcc - это безусловно выбор номер 1 .
И это правильно .


Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье
screw
  Про виртуальные ф-ии в ядре написан полный бред.
2007-08-02 15:41:45