#assembly #gcc #x86 #nasm #osdev
# #сборка #gcc #x86 #nasm #экранное меню
Вопрос:
Я пытаюсь создать простую программу. Я использую windows10x64, qemu (x86_64), C и assembly-nasm. У меня нет опыта работы с asm. Я пытаюсь это понять. Я использую простые файлы boot.asm, kernel_entry.asm и loader.c. Я основывался на итоговой таблице.
boot.asm
;; memory offset where our kernel is located
KERNEL_OFFSET equ 0x1000
;; save the boot drive number
mov [BOOT_DRIVE], dl
;; update base and stack pointers
mov bp, 0x9000
mov sp, bp
init:
mov si, msg ; loads the address of "msg" into SI register
mov ah, 0x0e ; sets AH to 0xe (function teletype)
print_char:
lodsb ; loads the current byte from SI into AL and increments the address in SI
cmp al, 0 ; compares AL to zero
je done ; if AL == 0, jump to "done"
int 0x10 ; print to screen using function 0xe of interrupt 0x10
jmp print_char ; repeat with next byte
;; call routine that loads kernel into memory
call load_kernel_into_memory
;; switch to Protected Mode
call switch_to_pm
jmp $
;; routine reads kernel from disk into memory
load_kernel_into_memory:
;; store all register values
pusha
;; set up parameters for disk_read routine
mov bx, KERNEL_OFFSET
mov dh, 15
mov dl, [BOOT_DRIVE]
call disk_read
;; restore register values and ret
popa
ret
;
[bits 32]
begin_pm:
;; Check if we can move from Protected Mode to Long Mode
;; If something went wrong (detect_lm shouldnt return at all)
;; we call execute_kernel in x32 Protected Mode
call detect_lm
call execute_kernel
jmp $
[bits 64]
begin_lm:
;; In case, if detect_lm and switch_to_lm works fine, call kernel in x64 mode
call execute_kernel
jmp $
;
execute_kernel:
call KERNEL_OFFSET
jmp $
;
%include "disk/disk_read.asm";
%include "lm/detect_lm.asm";
%include "lm/switch_to_lm.asm";
%include "pm/gdt.asm"
%include "pm/switch_to_pm.asm"
%include "print/print_string.asm";
%include "print/print_nl.asm";
BOOT_DRIVE: db 0
done:
hlt ; stop execution
msg: db "PROGRAM STARTED", 0x0a; we need to explicitely put the zero byte here
;
times 510-($-$) db 0 ; fill the output file with zeroes until 510 bytes are full
dw 0xaa55 ; magic number that tells the BIOS this is bootable
kernel_entry.asm
global _start
global kernel_main
[bits 32]
[extern _kernel_main] ; I use "_" otherwise it will not compile. _kernel_main comes from "c" file.
;In there that is kernel_main
_start:
call _kernel_main
jmp $
loader.c
#include <stdio.h>
extern void kernel_main() {
//printf("test");
for (int i = 0; i < 26; i ) {
char c = 0x41 i;
asm(
"mov %0, %%al;"
"mov $0x0E, %%ah;"
"int $0x10;"
:
: "r" (c)
);
}
}
Я КОМПИЛИРУЮ НА WINx64 с помощью nasm-WINx64version и GCC-TDM.
МОИ ШАГИ:
nasm kernel_entry.asm -f elf32 -o loader_entry.o
gcc -O0 -g -ffreestanding -m32 -c C:/Users/_USR_/Desktop/nasm-2.15.05/loader.c -o C:/Users/_USR_/Desktop/nasm-2.15.05/loader.o
ld -o "C:/Users/_USR_/Desktop/nasm-2.15.05/loader.tmp" -m i386pe -Ttext 0x1000 -T NUL C:/Users/_USR_/Desktop/nasm-2.15.05/loader_entry.o C:/Users/_USR_/Desktop/nasm-2.15.05/loader.o
objcopy -O binary loader.tmp loader.bin
type boot.bin loader.bin > myboot.bin
В конце я запускаю его в QEMU и получаю вывод «программа запущена», но не сообщение на языке «C». Кроме того, я получаю необъявленную ошибку при использовании printf(«…»); . Еще одна вещь, если я добавлю параметр -lc в команду LD, я получу сообщение «не удается найти«. Похоже, он не распознает «C». В противном случае я запускаю программу aster, связывающуюся с «C» и asm. Я не получаю ошибок, но я также не получаю функции «C».
Что я здесь делаю не так?
Комментарии:
1. Библиотека C вам недоступна, поэтому printf недоступен, если вы его не напишете.. Вам придется создавать свои собственные. Я рекомендую использовать кросс-компилятор, а не собственный компилятор Windows GCC, поскольку это может вызвать нежелательные проблемы, которые могут сильно затруднить разработку ядра.
2. Ваша встроенная сборка имеет проблемы, а также блокирует регистры, не сообщая об этом компилятору. Ваш загрузчик предполагает, что сегментные регистры установлены в 0, но это может работать в эмуляторе, но на реальном оборудовании у вас могут возникнуть проблемы.
3. Одна из очень серьезных проблем, связанных с фактическим кодом во встроенной сборке, заключается в том, что он использует прерывания BIOS. Вы не можете использовать их в защищенном режиме. При достижении этого кода произойдет сбой процессора, что, вероятно, приведет к сбросу компьютера с тройной ошибкой.
4. Все это очень сомнительно. Где вы взяли этот урок? По крайней мере, вы должны перестать следовать ему.
5. Во-первых, @Michael Petch спасибо за советы. Это было полезно. комментарий 1.) Я не использую Linux, но исходники в основном основаны на Linux. Поэтому я подумал, что могу использовать учебник для этого, но это была очень плохая идея. Как вы думаете, я могу получить лучшие результаты с версией Linux?, с утверждением «Библиотека C вам недоступна» вы имеете в виду, что у меня нет clib? GCC должен иметь его, но почему-то у него нет библиотеки. 2) вы имеете в виду, что я не отключал прерывания? 3) спасибо за предупреждение, я понял.
Ответ №1:
После того, как я просмотрел много документов, я обнаружил, что создание загрузчика очень сложно, но в то же время не сложно. Да, писать все из stratch для меня невозможно. Комментарии были правильными, это может работать в эмуляторе, но вызовет много проблем на реальном оборудовании. Я не могу с этим справиться. В конце концов, я обнаружил, что у intel был EFI. Теперь это UEFI. Тем не менее, я не утверждаю, что что-то знаю. Но, по крайней мере, я многому научился после поиска. Во-первых, переход с Windows на Linux прост в уме, но трудно осуществить на самом деле. Изменить свои привычки невозможно. Сначала я искал версию UEFI для Linux. Было много проблем с версиями. Затем я искал версию WIN. Надеюсь, я нашел vs2019 совместимую версию среды uefi. У проекта не было исходного кода в «gnu-efi» и при сборке выдавалась ошибка. Я искал «gnu-efi-3.0.12» на основе информации и скачал ее. Я помещаю файлы внутри основной папки в «gnu-efi». Затем вернемся к vs2019. Построил его, и сборка прошла успешно. Я запустил его в режиме отладки на платформе aa64. Я получил сообщение Windows о том, что оно загрузит qemu один раз. Это загрузилось само по себе, и я получил страницу qemu с соответствующими сообщениями, такими как:
Print(L"n%H*** UEFI:HI I AM GOMI ***%Nnn");
Print(L"%EPRESS ANY KEY AND EXIT.%Nn");
Я также проверил папку debug и нашел файлы «.efi». Я не уверен, создам ли я настоящее загрузочное USB-устройство и помещу скомпилированные файлы, которые будут работать.
Однако, поскольку это efi, я думаю, это должно загрузиться.
Исходные страницы, которые я нашел полезными
Хороший сайт для uefi: https://wiki.osdev.org /
проект, совместимый с vs2019: https://github.com/pbatard/uefi-simple