Команда IT специалистов выполнит подготовку инфраструктуры для вашего бизнеса.
Внедрение самых передовых решений и технологий.
Поддержка и сопровождение ваших сервисов.
Выполнение работ под "ключ", от покупки сервера, до настройки автоматизации процессов. 8(977)608-78-62 adm@nixm.ru
Внедрение самых передовых решений и технологий.
Поддержка и сопровождение ваших сервисов.
Выполнение работ под "ключ", от покупки сервера, до настройки автоматизации процессов. 8(977)608-78-62 adm@nixm.ru
gnu ассемблер и начальный загрузчик bootloader
gnu ассемблер и начальный загрузчик bootloader
Вступительная часть здесь
Немного о ассемблерах.
Самое интересное, что в век высокоуровневых, производительных языков
программирования опускаться на самое дно каменного века и вытаскивать
на свет божий даже не счеты а счетные палочки - ассемблер, дело
довольно не продуктивное но, извиняюсь крайне захватывающее. Сколько бы
мы не занимались другими важными вещами, работа процессора для нас без
знания ассемблера всегда будет представляться популярной абстракцией в виде
черного ящика. Соглашусь что для многих вещей этого вполне достаточно,
но для интересующихся людей к которым причисляю и себя, маловато будет.
Чем мне интересно программирование в линукс, это тем что все уровни
абстракции логичны и взаимно связанны. Познакомясь с линухом случайно
я оказалась как бы в середине происходящего без стенок, потолка и пола.
Двигаться в слепую в своем интересе можно было в любую выбранную сторону,
чем я по сути успешно и занималась до недавнего времени. Мир линукса на
столько многообразен и многогранен что совсем недавно я даже не подозревала
что смогу когда нибудь нащупать его границы. И вот совсем недавно я обнаружила
для себя дно - основание в виде гнутого ассемблера который предоставляет
фундаментальные понятия работы процессора и основы работы компьютера в целом.
Согласитесь стоя на фундаменте гораздо проще ознакомится со всем архитектурным
ансамблем. А раз так я предлагаю всем вместе заняться его строительством.
Вооружившись начальными знаниями по ассемблеру и несколькими ресурсами по
осиписательству я предлагаю вместе пройти проторенной дорожкой, постараться
не заблудится, а по возможности протоптать хоть что то свое. Сперва я хотела
сделать пару вводных статей об инструментах разработки, вируальных машинах и
базовой системе и подойти так сказать основательно к процессу, но вот у меня
сильно разболелся зуб и я подумала "ну все это нафик" будем подключать все по
мере пользования, то есть сразу в бой иначе интрига зачахнет и умрет.
И так, немного о дизайне предстоящего процесса.
Дайвайте сразу определимся с точкой входа, тоесть обозначим на временном
промежутке работы компьютера начало нашей будущей программы. Многие думают,
что начальный загрузчик и называется начальным потому, что ему достается
свободный процессор в его полное, распоряжение. Но не тут то было. На метеринской
плате есть постоянное место хранения специальной программы. Вот она то при
включении компьютера и загружается в оперативную память первая и в дальнейшем
начинает свое выполнение на процессоре. В то время когда начальный загрузчик
попадает в компьютер на нем уже во всю выполняется другая программа. Микросхема
биоса скопировала свое содержимое в оперативку и работа этой программы является
ни чем иным как работой ядра стартовой операционной системы.
В нашей программе нет даже драйверов что бы взаимодействовать с клавиатурой и
монитором на прямую и поэтому мы воспользуемся услугами драйверов запущенного
биоса что бы общатся с программой. В обычном дистрибутиве, когда запускаем
пользовательский код, мы можем взаимодействовать с ядром системы по средством
системных вызовов. Записываем нужные аргументы в определенные регистры или стек
и отправляем запрос на прерывание - выполнение, определенные в ассемблере
командами "int $0x80" в 32 битной и "syscall" в 64 битной версии для
x86 совместимых процессоров. Точно так же и в загруженное в оперативку
ядро-биос мы будем давать запрос на прерывание, а биос любезно будет
предоставлять нам свои возможности для выполнения наших заданий и в
тоже время с удовольствием поделится с нашим кодом процессорным временем
для наших нужд когда мы можем обойтись и силами собственного кода.
То есть наш код будет пользоваться процессором совместно с биосом и иногда
пользоваться некоторыми уже готовыми функциями биоса по нашим запросам.
И фактически мы напишем пользовательскую программу которая будет
работать в операционной системе БИОС.
Для этого стартапа свою домашнюю федору я забраковала и установила рядышком
дебиан тестинг, так как из за гонки за новизной имеется множество хвостов
которые заносить мне за этим драконом-федорой стало напряжно.
Начальный код загрузчика со страницы
http://www.independent-software.com/wri ... -system-2/
я переписала под синтаксис AT&T мне так привычней и исправила некоторые
ошибки или опечатки. Тем кто предпочитает синтаксис от intel и захочет
воспользоваться оригинальной версисией программы я предлагаю самому найти
неточности и думаю это будет интересно. Для всех остальных я привожу
переписанный код со всеми пока не использующимися переменными. Но разъяснения
по работе с начальным загрузчиком я решила построить на другом коде написанном
мною в результате разбора некоторых аналогичных проектов. Мой код является
учебным и не имеет продолжения, но на параллельном примере будет проще
разобраться с кодом из проекта. Что бы не растянутся в вечность в этом
посте я привожу первый код и примеры компиляции и запуска его.
[spoiler][/spoiler]
Перед сборкой надо установить компилятор:
Собираем код в объектный файл:
Линкуем:
Размер нашего бин файла должен составлять 512 байт
Сделаем образ дискеты:
или
Последняя команда в дебиан требует рут прав поэтому после создания необходимо
вернуть награбленное хозяину:
Записываем загрузочный сектор на образ дискеты:
В гипервизоре qemu-kvm бин файл можно запускать и так но в дальнейшем
работа с образом дискеты нам пригодится. Установим гипервизор и запустим
в нем наш загрузчик:
Этот загрузчик только и делает что выводит три строчки и перезагружает биос
по нажатию любой клавиши. В следующей части я приведу параллельный код и
детальный разбор полетов с учетом возможных обсуждений этой части. Мы научим
загрузчик понимать клавиатуру и делать выбор в программе загрузки, а так же
разберем несколько вариантов дебагера, дезассемблера, радактора объектных и
бинарных файлов и вообще помучием наш код и себя основательно.
[album]451[/album]
Немного о ассемблерах.
Самое интересное, что в век высокоуровневых, производительных языков
программирования опускаться на самое дно каменного века и вытаскивать
на свет божий даже не счеты а счетные палочки - ассемблер, дело
довольно не продуктивное но, извиняюсь крайне захватывающее. Сколько бы
мы не занимались другими важными вещами, работа процессора для нас без
знания ассемблера всегда будет представляться популярной абстракцией в виде
черного ящика. Соглашусь что для многих вещей этого вполне достаточно,
но для интересующихся людей к которым причисляю и себя, маловато будет.
Чем мне интересно программирование в линукс, это тем что все уровни
абстракции логичны и взаимно связанны. Познакомясь с линухом случайно
я оказалась как бы в середине происходящего без стенок, потолка и пола.
Двигаться в слепую в своем интересе можно было в любую выбранную сторону,
чем я по сути успешно и занималась до недавнего времени. Мир линукса на
столько многообразен и многогранен что совсем недавно я даже не подозревала
что смогу когда нибудь нащупать его границы. И вот совсем недавно я обнаружила
для себя дно - основание в виде гнутого ассемблера который предоставляет
фундаментальные понятия работы процессора и основы работы компьютера в целом.
Согласитесь стоя на фундаменте гораздо проще ознакомится со всем архитектурным
ансамблем. А раз так я предлагаю всем вместе заняться его строительством.
Вооружившись начальными знаниями по ассемблеру и несколькими ресурсами по
осиписательству я предлагаю вместе пройти проторенной дорожкой, постараться
не заблудится, а по возможности протоптать хоть что то свое. Сперва я хотела
сделать пару вводных статей об инструментах разработки, вируальных машинах и
базовой системе и подойти так сказать основательно к процессу, но вот у меня
сильно разболелся зуб и я подумала "ну все это нафик" будем подключать все по
мере пользования, то есть сразу в бой иначе интрига зачахнет и умрет.
И так, немного о дизайне предстоящего процесса.
Дайвайте сразу определимся с точкой входа, тоесть обозначим на временном
промежутке работы компьютера начало нашей будущей программы. Многие думают,
что начальный загрузчик и называется начальным потому, что ему достается
свободный процессор в его полное, распоряжение. Но не тут то было. На метеринской
плате есть постоянное место хранения специальной программы. Вот она то при
включении компьютера и загружается в оперативную память первая и в дальнейшем
начинает свое выполнение на процессоре. В то время когда начальный загрузчик
попадает в компьютер на нем уже во всю выполняется другая программа. Микросхема
биоса скопировала свое содержимое в оперативку и работа этой программы является
ни чем иным как работой ядра стартовой операционной системы.
В нашей программе нет даже драйверов что бы взаимодействовать с клавиатурой и
монитором на прямую и поэтому мы воспользуемся услугами драйверов запущенного
биоса что бы общатся с программой. В обычном дистрибутиве, когда запускаем
пользовательский код, мы можем взаимодействовать с ядром системы по средством
системных вызовов. Записываем нужные аргументы в определенные регистры или стек
и отправляем запрос на прерывание - выполнение, определенные в ассемблере
командами "int $0x80" в 32 битной и "syscall" в 64 битной версии для
x86 совместимых процессоров. Точно так же и в загруженное в оперативку
ядро-биос мы будем давать запрос на прерывание, а биос любезно будет
предоставлять нам свои возможности для выполнения наших заданий и в
тоже время с удовольствием поделится с нашим кодом процессорным временем
для наших нужд когда мы можем обойтись и силами собственного кода.
То есть наш код будет пользоваться процессором совместно с биосом и иногда
пользоваться некоторыми уже готовыми функциями биоса по нашим запросам.
И фактически мы напишем пользовательскую программу которая будет
работать в операционной системе БИОС.
Для этого стартапа свою домашнюю федору я забраковала и установила рядышком
дебиан тестинг, так как из за гонки за новизной имеется множество хвостов
которые заносить мне за этим драконом-федорой стало напряжно.
Начальный код загрузчика со страницы
http://www.independent-software.com/wri ... -system-2/
я переписала под синтаксис AT&T мне так привычней и исправила некоторые
ошибки или опечатки. Тем кто предпочитает синтаксис от intel и захочет
воспользоваться оригинальной версисией программы я предлагаю самому найти
неточности и думаю это будет интересно. Для всех остальных я привожу
переписанный код со всеми пока не использующимися переменными. Но разъяснения
по работе с начальным загрузчиком я решила построить на другом коде написанном
мною в результате разбора некоторых аналогичных проектов. Мой код является
учебным и не имеет продолжения, но на параллельном примере будет проще
разобраться с кодом из проекта. Что бы не растянутся в вечность в этом
посте я привожу первый код и примеры компиляции и запуска его.
[spoiler]
Код: Выделить всё
.code16
.att_syntax noprefix
.section .text
.org 0x0
LOAD_SEGMENT = 0x1000 # load the boot loader to segment 1000h
.global _start
_start:
jmp start # jump to beginning of code
nop
bootsector:
iOEM: .ascii "DevOS " # OEM String
iSectSize: .word 0x200 # bytes per sector
iClustSize: .byte 1 # sectors per cluster
iResSect: .word 1 # #of reserved sectors
iFatCnt: .byte 2 # #of FAT copies
iRootSize: .word 224 # size of root directory
iTotalSect: .word 2880 # total # of sectors if over 32 MB
iMedia: .byte 0xF0 # media Descriptor
iFatSize: .word 9 # size of each FAT
iTrackSect: .word 9 # sectors per track
iHeadCnt: .word 2 # number of read-write heads
iHiddenSect: .int 0 # number of hidden sectors
iSect32: .int 0 # # sectors for over 32 MB
iBootDrive: .byte 0 # holds drive that the boot sector came
from
iReserved: .byte 0 # reserved, empty
iBootSign: .byte 0x29 # extended boot sector signature
iVolID: .ascii "seri" # disk serial
acVolumeLabel: .ascii "MYVOLUME " # volume label
acFSType: .ascii "FAT16 " # file system type
.func
WriteString:
lodsb # load byte at ds:si into al (advancing
si)
or %al, %al # test if character is 0 (end)
jz WriteString_done # jump to end if 0.
mov $0xe, %ah # Subfunction 0xe of int 10h (video
teletype output)
mov $9, %bx # Set bh (page nr) to 0, and bl
(attribute) to white (9)
int $0x10 # call BIOS interrupt.
jmp WriteString # Repeat for next character.
WriteString_done:
retw
.endfunc
.func
Reboot:
lea rebootmsg, %si # Load address of reboot message into si
call WriteString # print the string
xor %ax, %ax # subfuction 0
int $0x16 # call bios to wait for key
.byte 0xEA # machine language to jump to FFFF:0000
(reboot)
.word 0x0000
.word 0xFFFF
.endfunc
start:
# Setup segments:
cli
mov %dl, iBootDrive # save what drive we booted from (should
be 0x0)
mov %cs, %ax # CS = 0x0, since that's where boot sector
is (0x07c00)
mov %ax, %ds # DS = CS = 0x0
mov %ax, %es # ES = CS = 0x0
mov %ax, %ss # SS = CS = 0x0
mov $0x7C00, %sp # Stack grows down from offset 0x7C00
toward 0x0000.
sti
# Display "loading" message:
lea loadmsg, %si
call WriteString
# Reset disk system.
# Jump to bootFailure on error.
mov iBootDrive, %dl # drive to reset
xor %ax, %ax # subfunction 0
int $0x13 # call interrupt 13h
jc bootFailure # display error message if carry set(error)
# End of loader, for now. Reboot.
call Reboot
bootFailure:
lea diskerror, %si
call WriteString
call Reboot
# PROGRAM DATA
loadmsg: .asciz "Loading OS...\r\n"
diskerror: .asciz "Disk error.\r\n"
rebootmsg: .asciz "Press any key to reboot..."
.fill (510 - ( . - _start )), 1, 0 # Pad with nulls up to 510 bytes
BootMagic: .word 0xAA55
Перед сборкой надо установить компилятор:
Код: Выделить всё
sudo apt install binutils
Код: Выделить всё
as -o boot.o boot.s
Код: Выделить всё
ld -Ttext 0x7c00 --oformat=binary -o boot.bin boot.o
Код: Выделить всё
ls -l
Код: Выделить всё
dd if=/dev/zero of=floppy.img bs=1024 count=1440
Код: Выделить всё
mkdosfs -C floppy.img 1440
вернуть награбленное хозяину:
Код: Выделить всё
sudo chown nez:nez floppy.img
Код: Выделить всё
dd if=boot.bin of=floppy.img bs=512 count=1 conv=notrunc
работа с образом дискеты нам пригодится. Установим гипервизор и запустим
в нем наш загрузчик:
Код: Выделить всё
sudo apt install qemu-system-i386
qemu-system-i386 -fda floppy.img -boot a
по нажатию любой клавиши. В следующей части я приведу параллельный код и
детальный разбор полетов с учетом возможных обсуждений этой части. Мы научим
загрузчик понимать клавиатуру и делать выбор в программе загрузки, а так же
разберем несколько вариантов дебагера, дезассемблера, радактора объектных и
бинарных файлов и вообще помучием наш код и себя основательно.
[album]451[/album]
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Re: gnu ассемблер и начальный загрузчик bootloader
Уточняем:
- sysenter существует как в 32-бит, так и в 64-бит процессоре...
- sysутеук появляется в процессорах Pentium IV и старше
- ... как, фактически, эквивалент int когда параметры ключевые параметры перехода (CS, SP, IP) теперь загружаются не из памяти, а из специальных внутренних регистров MSR (Model Specific Registers) с предопределёнными (0х174, 0х175, 0х176) номерами (из большого их общего числа), куда предварительно эти значения записываются, опять же, специальной новой командой процессора wmsr...
- сделано это из-за значительного проигрыша (рыночного) процессоров Pentium IV
- переход на команду вызова sysenter и возврат командой sysexit - это примерно 2008 год.
И ещё...
Разные операционные системы для системного вызова вызывают разные int, не обязательно 80h:
- MS DOS - 21h
- Windows - 2Eh
- Linux - 80h
- QNX - 21h
- Minix 3 - 21h
- команды int 80h и sysenter (через которые осуществляются системные вызовы и в Linux и в Windows)Записываем нужные аргументы в определенные регистры или стек
и отправляем запрос на прерывание - выполнение, определенные в ассемблере
командами "int $0x80" в 32 битной и "syscall" в 64 битной версии для
x86 совместимых процессоров.
- sysenter существует как в 32-бит, так и в 64-бит процессоре...
- sysутеук появляется в процессорах Pentium IV и старше
- ... как, фактически, эквивалент int когда параметры ключевые параметры перехода (CS, SP, IP) теперь загружаются не из памяти, а из специальных внутренних регистров MSR (Model Specific Registers) с предопределёнными (0х174, 0х175, 0х176) номерами (из большого их общего числа), куда предварительно эти значения записываются, опять же, специальной новой командой процессора wmsr...
- сделано это из-за значительного проигрыша (рыночного) процессоров Pentium IV
- переход на команду вызова sysenter и возврат командой sysexit - это примерно 2008 год.
И ещё...
Разные операционные системы для системного вызова вызывают разные int, не обязательно 80h:
- MS DOS - 21h
- Windows - 2Eh
- Linux - 80h
- QNX - 21h
- Minix 3 - 21h
Re: gnu ассемблер и начальный загрузчик bootloader
Это очень интересно...И фактически мы напишем пользовательскую программу которая будет
работать в операционной системе БИОС.
Но!
1. Это многократно, и уже давно, описано - ещё со времён публикаций Norton-а о MS-DOS.
2. Это не так сильно актуально, потому что BIOS отмирает ... и через 2-3 года вы не найдёте BIOS ни на одной современной модели.
Так же точно, как и загрузка (дальнейшая) с диска формата MBR, и вообще сам формат MBR.
Всё это - это уже экспонаты для политехнического музея.
Куда интереснее было бы, если подробно рассмотреть загрузку с UEFI ... и проделать, может, какие-то иллюстрационные примеры кода UEFI загрузки.
В этом был бы очень большой элемент новизны!
Re: gnu ассемблер и начальный загрузчик bootloader
Полностью согласна и с удовольствием в свое время с такой статьей бы познакомилась.Olej писал(а): Куда интереснее было бы, если подробно рассмотреть загрузку с UEFI ... и проделать, может, какие-то иллюстрационные примеры кода UEFI загрузки.
В этом был бы очень большой элемент новизны!
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Re: gnu ассемблер и начальный загрузчик bootloader
Olej. Не будучи экспертом в осеписательстве и даже в программировании
Я счиатю выбранный путь знакомство с ассемблером чрез биос
по следам выбранных мной публикаций правильным. По гнутому ассемблеру
не так много материала и он весь крайне разрознен, что бы одновременно
идти не по проторенной дорожке. Запуск систем с uefi на виртуальных машинах
тема для меня совершенно новая и сложная и тем более на bochs думаю даже не
возможная. Вобщем я описала все свои посылы и побудительные мотивы в первой
части. Все эти замечания совершенно правильные но мне кажется в данном случае
оторванные от реальности и все это только усложнит процесс. С другой стороны
я совсем не против если кто то возьмет на себя труд и захочет в этом проекте
по путям которого я задумала пройти переписать загрузчик на продвинутый и
органично это все встроить и я буду даже совсем не против совместно поломать
голову и по мере своих знаний помогу чем смогу. Опишите как это должно выглядеть
я попробую вникнуть и подстроится. Но имейте ввиду локомотивом будете именно вы,
потому, что я точно знаю сегодняшний предел своим имеющимся у меня знаниям.
Я счиатю выбранный путь знакомство с ассемблером чрез биос
по следам выбранных мной публикаций правильным. По гнутому ассемблеру
не так много материала и он весь крайне разрознен, что бы одновременно
идти не по проторенной дорожке. Запуск систем с uefi на виртуальных машинах
тема для меня совершенно новая и сложная и тем более на bochs думаю даже не
возможная. Вобщем я описала все свои посылы и побудительные мотивы в первой
части. Все эти замечания совершенно правильные но мне кажется в данном случае
оторванные от реальности и все это только усложнит процесс. С другой стороны
я совсем не против если кто то возьмет на себя труд и захочет в этом проекте
по путям которого я задумала пройти переписать загрузчик на продвинутый и
органично это все встроить и я буду даже совсем не против совместно поломать
голову и по мере своих знаний помогу чем смогу. Опишите как это должно выглядеть
я попробую вникнуть и подстроится. Но имейте ввиду локомотивом будете именно вы,
потому, что я точно знаю сегодняшний предел своим имеющимся у меня знаниям.
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Re: gnu ассемблер и начальный загрузчик bootloader
Я бы тоже с такой статьей с интересом познакомился, с готовой.nezabudka писал(а): Полностью согласна и с удовольствием в свое время с такой статьей бы познакомилась.
Но на заметку, для введения в предмет:
UEFI - проблемы и решения
BIOS & UEFI
GPT диски
Здесь можно последовательно проследить от начала: кто - кому - и как передаёт активность при загрузке.
Конечно, с какими-то вещами пришлось бы экспериментировать, выяснять экспериментальным путём.
А всё, что и как относится к BIOS - это всё настолько устаревшее, что такое занятие не будет иметь никакого продолжения.
Re: gnu ассемблер и начальный загрузчик bootloader
Я надеюсь, что вы понимаете, обратили внимание на то, что весь первичные загрузчик, с вызовами BIOS (int 13h и т.д.), а также и вторичный загрузчик (сильно предполагаю) LILO, GRUB, ... - всё выполняется в реальном режиме процессора x86. И начальная фаза загрузки Linux также происходит в реальном режиме: подготовка таблиц LDT, GDT, IDT, ... таблицы страниц MMU и др.nezabudka писал(а):По гнутому ассемблеру
не так много материала и он весь крайне разрознен, что бы одновременно
идти не по проторенной дорожке.
И только после этого происходит переключение в защищённый режим.
Это я напоминаю для того, что ассемблерный код реального и защищённого режима будут различаться (по виду).
А по поводу скудности материалов по GASM "гнутому ассемблеру", то обратите внимание:
- даже в коде ядра Linux из всего объёма ассемблерного кода не более 5-10% написано как отдельные файлы, компилирующиеся GASM
- а остальные 90-95% ассемблерного кода ядра написаны как инлайновые ассемблерные вставки (макрорасширения) языка C и компилятора GCC
- по инлайновому ассемблеру GCC тоже не так много материалов, но попадаются... вот здесь есть ссылки: inline assembler gcc
Возможно, эти дополнения вам чем-то помогут...