Команда IT специалистов выполнит подготовку инфраструктуры для вашего бизнеса.
Внедрение самых передовых решений и технологий.
Поддержка и сопровождение ваших сервисов.
Выполнение работ под "ключ", от покупки сервера, до настройки автоматизации процессов.
8(977)608-78-62 adm@nixm.ru

gnu ассемблер и начальный загрузчик bootloader

Ответить
Аватара пользователя
nezabudka
Местный говорун
Местный говорун
Сообщения: 618
Зарегистрирован: 18 апр 2015, 06:13
Откуда: Ростов на Дону

gnu ассемблер и начальный загрузчик bootloader

Сообщение nezabudka »

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

Перед сборкой надо установить компилятор:

Код: Выделить всё

sudo apt install binutils
Собираем код в объектный файл:

Код: Выделить всё

as -o boot.o boot.s
Линкуем:

Код: Выделить всё

ld -Ttext 0x7c00 --oformat=binary -o boot.bin boot.o
Размер нашего бин файла должен составлять 512 байт Сделаем образ дискеты:

Код: Выделить всё

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
В гипервизоре qemu-kvm бин файл можно запускать и так но в дальнейшем
работа с образом дискеты нам пригодится. Установим гипервизор и запустим
в нем наш загрузчик:

Код: Выделить всё

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
Olej

Re: gnu ассемблер и начальный загрузчик bootloader

Сообщение Olej »

Уточняем:
Записываем нужные аргументы в определенные регистры или стек
и отправляем запрос на прерывание - выполнение, определенные в ассемблере
командами "int $0x80" в 32 битной и "syscall" в 64 битной версии для
x86 совместимых процессоров.
- команды int 80h и sysenter (через которые осуществляются системные вызовы и в Linux и в Windows)
- 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
Olej

Re: gnu ассемблер и начальный загрузчик bootloader

Сообщение Olej »

И фактически мы напишем пользовательскую программу которая будет
работать в операционной системе БИОС.
Это очень интересно...
Но!

1. Это многократно, и уже давно, описано - ещё со времён публикаций Norton-а о MS-DOS.

2. Это не так сильно актуально, потому что BIOS отмирает ... и через 2-3 года вы не найдёте BIOS ни на одной современной модели.
Так же точно, как и загрузка (дальнейшая) с диска формата MBR, и вообще сам формат MBR.
Всё это - это уже экспонаты для политехнического музея.

Куда интереснее было бы, если подробно рассмотреть загрузку с UEFI ... и проделать, может, какие-то иллюстрационные примеры кода UEFI загрузки.
В этом был бы очень большой элемент новизны!
Аватара пользователя
nezabudka
Местный говорун
Местный говорун
Сообщения: 618
Зарегистрирован: 18 апр 2015, 06:13
Откуда: Ростов на Дону

Re: gnu ассемблер и начальный загрузчик bootloader

Сообщение nezabudka »

Olej писал(а): Куда интереснее было бы, если подробно рассмотреть загрузку с UEFI ... и проделать, может, какие-то иллюстрационные примеры кода UEFI загрузки.
В этом был бы очень большой элемент новизны!
Полностью согласна и с удовольствием в свое время с такой статьей бы познакомилась.
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Аватара пользователя
nezabudka
Местный говорун
Местный говорун
Сообщения: 618
Зарегистрирован: 18 апр 2015, 06:13
Откуда: Ростов на Дону

Re: gnu ассемблер и начальный загрузчик bootloader

Сообщение nezabudka »

Olej. Не будучи экспертом в осеписательстве и даже в программировании
Я счиатю выбранный путь знакомство с ассемблером чрез биос
по следам выбранных мной публикаций правильным. По гнутому ассемблеру
не так много материала и он весь крайне разрознен, что бы одновременно
идти не по проторенной дорожке. Запуск систем с uefi на виртуальных машинах
тема для меня совершенно новая и сложная и тем более на bochs думаю даже не
возможная. Вобщем я описала все свои посылы и побудительные мотивы в первой
части. Все эти замечания совершенно правильные но мне кажется в данном случае
оторванные от реальности и все это только усложнит процесс. С другой стороны
я совсем не против если кто то возьмет на себя труд и захочет в этом проекте
по путям которого я задумала пройти переписать загрузчик на продвинутый и
органично это все встроить и я буду даже совсем не против совместно поломать
голову и по мере своих знаний помогу чем смогу. Опишите как это должно выглядеть
я попробую вникнуть и подстроится. Но имейте ввиду локомотивом будете именно вы,
потому, что я точно знаю сегодняшний предел своим имеющимся у меня знаниям.
"I invented the term Object-Oriented and I can tell you I did not have C++ in mind." - Alan Kay
Olej

Re: gnu ассемблер и начальный загрузчик bootloader

Сообщение Olej »

nezabudka писал(а): Полностью согласна и с удовольствием в свое время с такой статьей бы познакомилась.
Я бы тоже с такой статьей с интересом познакомился, с готовой. :)
Но на заметку, для введения в предмет:
UEFI - проблемы и решения
BIOS & UEFI
GPT диски
Здесь можно последовательно проследить от начала: кто - кому - и как передаёт активность при загрузке.
Конечно, с какими-то вещами пришлось бы экспериментировать, выяснять экспериментальным путём.

А всё, что и как относится к BIOS - это всё настолько устаревшее, что такое занятие не будет иметь никакого продолжения.
Olej

Re: gnu ассемблер и начальный загрузчик bootloader

Сообщение Olej »

nezabudka писал(а):По гнутому ассемблеру
не так много материала и он весь крайне разрознен, что бы одновременно
идти не по проторенной дорожке.
Я надеюсь, что вы понимаете, обратили внимание на то, что весь первичные загрузчик, с вызовами BIOS (int 13h и т.д.), а также и вторичный загрузчик (сильно предполагаю) LILO, GRUB, ... - всё выполняется в реальном режиме процессора x86. И начальная фаза загрузки Linux также происходит в реальном режиме: подготовка таблиц LDT, GDT, IDT, ... таблицы страниц MMU и др.
И только после этого происходит переключение в защищённый режим.
Это я напоминаю для того, что ассемблерный код реального и защищённого режима будут различаться (по виду).

А по поводу скудности материалов по GASM "гнутому ассемблеру", то обратите внимание:
- даже в коде ядра Linux из всего объёма ассемблерного кода не более 5-10% написано как отдельные файлы, компилирующиеся GASM
- а остальные 90-95% ассемблерного кода ядра написаны как инлайновые ассемблерные вставки (макрорасширения) языка C и компилятора GCC
- по инлайновому ассемблеру GCC тоже не так много материалов, но попадаются... вот здесь есть ссылки: inline assembler gcc

Возможно, эти дополнения вам чем-то помогут...
Ответить

Вернуться в «Другие языки»