Немного о ассемблерах.
Самое интересное, что в век высокоуровневых, производительных языков
программирования опускаться на самое дно каменного века и вытаскивать
на свет божий даже не счеты а счетные палочки - ассемблер, дело
довольно не продуктивное но, извиняюсь крайне захватывающее. Сколько бы
мы не занимались другими важными вещами, работа процессора для нас без
знания ассемблера всегда будет представляться популярной абстракцией в виде
черного ящика. Соглашусь что для многих вещей этого вполне достаточно,
но для интересующихся людей к которым причисляю и себя, маловато будет.
Чем мне интересно программирование в линукс, это тем что все уровни
абстракции логичны и взаимно связанны. Познакомясь с линухом случайно
я оказалась как бы в середине происходящего без стенок, потолка и пола.
Двигаться в слепую в своем интересе можно было в любую выбранную сторону,
чем я по сути успешно и занималась до недавнего времени. Мир линукса на
столько многообразен и многогранен что совсем недавно я даже не подозревала
что смогу когда нибудь нащупать его границы. И вот совсем недавно я обнаружила
для себя дно - основание в виде гнутого ассемблера который предоставляет
фундаментальные понятия работы процессора и основы работы компьютера в целом.
Согласитесь стоя на фундаменте гораздо проще ознакомится со всем архитектурным
ансамблем. А раз так я предлагаю всем вместе заняться его строительством.
Вооружившись начальными знаниями по ассемблеру и несколькими ресурсами по
осиписательству я предлагаю вместе пройти проторенной дорожкой, постараться
не заблудится, а по возможности протоптать хоть что то свое. Сперва я хотела
сделать пару вводных статей об инструментах разработки, вируальных машинах и
базовой системе и подойти так сказать основательно к процессу, но вот у меня
сильно разболелся зуб и я подумала "ну все это нафик" будем подключать все по
мере пользования, то есть сразу в бой иначе интрига зачахнет и умрет.
И так, немного о дизайне предстоящего процесса.
Дайвайте сразу определимся с точкой входа, тоесть обозначим на временном
промежутке работы компьютера начало нашей будущей программы. Многие думают,
что начальный загрузчик и называется начальным потому, что ему достается
свободный процессор в его полное, распоряжение. Но не тут то было. На метеринской
плате есть постоянное место хранения специальной программы. Вот она то при
включении компьютера и загружается в оперативную память первая и в дальнейшем
начинает свое выполнение на процессоре. В то время когда начальный загрузчик
попадает в компьютер на нем уже во всю выполняется другая программа. Микросхема
биоса скопировала свое содержимое в оперативку и работа этой программы является
ни чем иным как работой ядра стартовой операционной системы.
В нашей программе нет даже драйверов что бы взаимодействовать с клавиатурой и
монитором на прямую и поэтому мы воспользуемся услугами драйверов запущенного
биоса что бы общатся с программой. В обычном дистрибутиве, когда запускаем
пользовательский код, мы можем взаимодействовать с ядром системы по средством
системных вызовов. Записываем нужные аргументы в определенные регистры или стек
и отправляем запрос на прерывание - выполнение, определенные в ассемблере
командами "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]
