Как стать автором
Обновить

Комментарии 25

Круто! В конце 90-х еще мечтал о таком, но инфы было мало, интернета не было. Загрузчик был готов, еще несколько вещей типа графики были тоже (правда их надо было под PM переделать еще), но застопорился на переключении в защищенный режим, а потом уже не до того было. Я на чистом ассемблере писал.
P.S. Про OsDev знаю, сам там иногда лазил. Мне бы в те времена такой ресурс…
НЛО прилетело и опубликовало эту надпись здесь
Конечно же! Как я мог забыть… Я постоянно поглядывал в репозиторий. Сейчас добавлю в статью, спасибо вам.
Отличная статья! Найден оптимальный баланс между изложением только важных/новых вещей и пропуском (с отсылками к другим статьям) очевидных/общеизвестных/разжеваных ранее. За «правильный» ассемблер — отдельный плюс (сам так и не смог привыкнуть ко всяким этим %eax и прочим).
За «правильный» ассемблер — отдельный плюс

Были б мы на ЛОРе, я б знал как это прокомментировать. Здесь придётся ограничиться многозначительным молчанием.

Вот поэтому я и не пишу каменты на ЛОРе, здесь заботливое НЛО есть…

А если серьёзно — не могли бы поделиться, почему тот синткасис лучше, и чем именно, или порекомендовать почитать на тему? Это ведь не просто вкусовщина, есть и объективные причины?

Сам я со времён DOS'а, как старый пользователь MASM и TASM, привычен к интеловскому, но это всего лишь привычка.
почему тот синткасис лучше

Просто он продуманнее. Интеловский более хаотичен — где-то нужно явно указывать размер операндов, где-то не нужно и т. д.


Но я сомневаюсь, что найдётся хотя бы один человек, предпочитающий одно другому по объективным (рациональным) причинам. Привычка/идеология и не более.

Найдётся. Долго пользовался Интелловским, плевался на AT&T. Потом решил посмотреть, что там за другой синтаксис такой. Удобство победило привычку. Сейчас AT&T читается проще и кажется более адекватным, логичным и удобным.

Вообще "правильный" ассемблер в данном случае не очень хорош, так как под другие платформы в основном используется синтаксис at&t, и портировать будет сложнее — придется изменять не только код под платформу, но и систему сборки. Но мне приятнее писать в Интел синтаксисе, так что пусть будет.

«The reason why the GNU Assembler (GAS) uses AT&T syntax for x86 assembly is for compatibility with AT&T's x86 assemblers. Instead of using a syntax based on Intel's official x86 assembly syntax, AT&T chose to create a new syntax based on their earlier 68000 and PDP-11 assemblers. „

Зависит от платформы. Под ARM, к счастью, он не используется.
НЛО прилетело и опубликовало эту надпись здесь
Если посмотреть, как именно компиляторы собирают программы на этапе линковки, то окажется, что они начинаются с линейного адреса ноль или около ноля. Это значит, что если образ ядра займет пространство памяти около ноля, программы собранные таким образом не смогут исполняться, любая jmp инструкция программы приведет ко входу в защищенную память ядра и ошибке защиты. Поэтому если мы хотим в будущем пользоваться не только самописными программами, разумно отдать приложению как можно больший кусок памяти около ноля, а образ ядра разместить повыше.

Вот этот кусок понять не смог.
Линкер собирает программу с опорой на BaseAddress, который в общем случае, может быть любым. Нам ведь никто не запрещает разместить ядро по адресу, скажем, 1000h (нулевая страница — guard), а все прикладные программы компоновать с адресом загрузки 80000000h.

Проблема будет лишь в том случае, если вы хотите запустить программу, написанную и собранную под другую ОС без перекомпоновки (что возможно только если ваш API полностью бинарно совместим, а это вряд ли).

Главное, чем хочу поделиться — страницы это не сегменты! Пожалуйста, не повторяйте мою ошибку и не грузите адрес таблицы страниц в GDTR! Для таблицы страниц предназначен регистр CR3!

Даже затрудняюсь представить, как можно было так подумать…

для простоты работы (чтобы иметь только одну таблицу страниц), я выбрал размер в 4 МиБ за счет включения PSE.

А как же потери при небольших размещениях? Не велика гранулярность для 32 бит?
Можно ведь вроде вообще не использовать страницы, они нужны только для реализации виртуальной памяти (свопа, грубо говоря).
Да, можно инициализировать сегменты сначала, а страничную адресацию — потом, или вовсе ею не пользоваться.
Нет, не только для свопа. ВАП нужно, в первую очередь (имхо), для 1) расположения некоторых модулей по пересекающимся адресам, 2)реализации поведения copy-on-write, 3) для преодоления фрагментации физической памяти. При страничной адресации у вас по-прежнему может фрагментироваться ВАП одного процесса, но это будут лишь его личне половые проблемы. Без страничной адресации вы быстро попадаете на ситуацию вида:
1. гигабайт — занят
2. гигабайт — свободен
3. гигабайт — занят
4. гигабайт — свободен

У вас 2 гига свободной памяти, а дать программе буффер в 1.5 гига вы не можете.

4) guard pages для стеков и для поимки null-pointer dereference


Вот этот кусок понять не смог.
Линкер собирает программу с опорой на BaseAddress, который в общем случае, может быть любым. Нам ведь никто не запрещает разместить ядро по адресу, скажем, 1000h (нулевая страница — guard), а все прикладные программы компоновать с адресом загрузки 80000000h.

Проблема будет лишь в том случае, если вы хотите запустить программу, написанную и собранную под другую ОС без перекомпоновки (что возможно только если ваш API полностью бинарно совместим, а это вряд ли).

Совершенно верно. Однако, это специфические случаи, требующие скармливания дополнительных инструкций линкеру. В самом общем случае под большинство ОС программы предпочитают начинаться с начала адресного пространства. В том же Windows дела обстоят так: 0x00000000 — 0x0000FFFF: нулевые указатели, 0x00010000 — 0x7FFEFFFF: память программы, 0x80000000 — 0xFFFFFFFF: память ядра.

А как же потери при небольших размещениях? Не велика гранулярность для 32 бит?

Велика, конечно. Надо брать 4 КиБ. Когда-нибудь у меня дойдут руки и до 4 КиБ. На этом этапе я захотел сделать жизнь чуть проще, оставив один уровень таблиц, благо PSE это позволяет.
требующие скармливания дополнительных инструкций линкеру. В самом общем случае под большинство ОС программы предпочитают начинаться с начала адресного пространства. В том же Windows дела обстоят так: 0x00000000 — 0x0000FFFF: нулевые указатели, 0x00010000 — 0x7FFEFFFF: память программы, 0x80000000 — 0xFFFFFFFF: память ядра.

Ну, положим, то, где начинается память, зависит от того, где ОС ее выдаст, тут линкер ни при чем. Линкер всего-навсего поменяет base address, это один дополнительный ключ.
Про нулевые указатели — guard page — я писал выше и так
Зачем тратить место под guard page?
Rust же супер надежный и безопасный :)

У нескольких циклов статей на хабре встречал оглавление по уже вышедшим частям в начале каждой статьи, так открываешь ленту, видишь четвертую часть, и можешь сразу пойти читать пропущенные ранее.


А по теме, что-то подумалось, а не перепишет ли в ближайшем будущем кто-нибудь, чисто по приколу, DOS на rust?

Grub та еще шляпа. К сожалению, по личному опыту, были большие проблемы с работоспособностью под USB 1.0
Если КиБ и ГиБ ещё можно как то понять, то что значит МиБ? Мигабайт? Ну в целом статья полезная, информации по этой теме очень мало.
Вам сюда. Я использую двоичные приставки, идеологически.
Тогда из текста стоит убрать все «мегабайты».
Наплыв комментариев вынудил меня пойти копаться в ГОСТах и поправках, и вот что обнаружилось. КБ — 1024 байт, кБ — 1000 байт, и так далее. С другой стороны, в западных стандартах склоняются к KiB, MiB, etc… Сложный, в общем, вопрос. Убрал со всех статей КиБ, Миб, ГиБ, дабы никому глаз не резало и не мешало сути.
И заменить на «метры».
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории