я починил эту ос, теперь хотел понемногу добавлять C, т.к. на чистом ассемблере далеко не уйдешь. Если получится запустить хоть Hello, World! - буду очень благодарен
make run
и введя команду hello
в консоли внутри qemu.Может надо сделать их объектными elf файлами, затем скомпоновать и зачистить формат?
gcc
для компиляции исходников на С (*.c
) и ассемблере (*.S
), gcc
или ld
для линковки, objcopy
для преобразования ELF-файла с выхода линковщика в бинарник.Почему у меня не хотят работать корректно цепные команды?
mov ax,Data2
mov es,ax ; запис адреси data2 в ds
...
lea si, node1 ; <---
node1
находится в сегменте Data2
, адрес которого загружен в es
, но команда lodsb
загружает данные из ds:si
.@finish_cycle_namex:
inc I_struc ;+1 до ітерації
add si, 5
si
? si
указывает на область памяти в которой лежит массив 5-символьных имён, внутренний цикл как раз перемещает si
на следующее имя. Почему от добавления функций помимо main() в начало кода ядро перестает работать?
i686-elf-ld -Ttext 0x7E00 --oformat binary kernel.o -o kernel -e main
; Jump to the kernel's entry point
JMP 0x0000:0x7E00
-e main
?main()
. Чтобы поместить нужный код в нужное место собранного образа обычно используют скрипт линковщика.// Получаю ошибку:
7FFF0000: The instruction at 0x7FFF0000 referenced memory at 0x7FFF0000. The memory could not be executed -> 7FFF0000 (exc.code c0000005, tid 6332)
В чем проблема?
7FFF0000
-- не исполняемая.Как починить?
7FFF0000
исполняемой. После этого вывод в лог должен заработать, но будет падать после него, потому что функция mySuperFunction
не возвращается. $ gcc -m32 boot.s -nodefaultlibs -nostartfiles -Wl,-Tlinker.ld -no-pie -o boot.elf
$ readelf -S boot.elf
There are 8 section headers, starting at offset 0x3140:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .note.gnu.bu[...] NOTE 00100000 001000 000024 00 A 0 0 4
[ 2] .multiboot PROGBITS 00101000 003000 00000c 00 0 0 4096
[ 3] .text PROGBITS 00102000 002000 000009 00 AX 0 0 4096
[ 4] .bss NOBITS 00103000 003000 004000 00 WA 0 0 4096
[ 5] .symtab SYMTAB 00000000 00300c 0000a0 10 6 9 4
[ 6] .strtab STRTAB 00000000 0030ac 00004d 00 0 0 1
[ 7] .shstrtab STRTAB 00000000 0030f9 000044 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)
.multiboot
оказалась по смещению 0x3000. movw $0x4F02, %ax
movb $0x03, %bl
int $0x10
bh
остался мусор, а этот вызов принимает аргумент в bx
. возможно, я неправильно использую sf флаг?
mov al, mas[si] cmp ax, ax jns positiveOut ;;;;
cmp ax, ax
сравнивает ax с самим собой, результат немного предсказуем: они равны, т.е. sf = 0, zf = 1. Чтобы узнать знак числа нужно либо сравнивать его с нулём, либо использовать вместо cmp
логическую операцию -- test
, or
или and
.mov al, mas[si]
загружает из памяти только al, в ah остаётся мусор от предыдущих операций. По-нормальному после mov нужно сделать знаковое расширение al в ax, если собираешься дальше работать с ax, например так:mov al, mas[si]
cbw
sub ax, 1 not ax
neg ax
? traverse_loop
держит указатель на текущую запись в eax
, но первый же вызов PrintName
портит почти все регистры и не восстанавливает их, поэтому первый же movzx esi, byte [eax + 10h]
после этого вызова обращается мимо памяти и вызывает segfault. Проще всего это исправить каким-нибудь pusha
/ popa
вокруг тела PrintName
. После этого ты доберёшься до вызова PrintMark
, где увидишь, что эта функция ожидает в eax + 10h
текстового представления оценки, а у тебя пока есть только двоичное. что не так
mov ecx, 5 ; Загружает количество гласных
…
inc ecx ; Увеличивает счетчик гласных
…
loop checkVowels ; Переходит к проверке следующей гласной
…
test ecx, ecx ; Проверяет, содержится ли гласная буква в слове
; Вывод суммы элементов выше главной диагонали mov ah, 2 mov dl, cl int 21h
Что же сделает программа на чистом ассемблере?
у меня получилось найти только…
cs * 10h + ip
. В твоём случае получается 48ff9
.Почему не переписать вместо этого
add ebx,dword ptr [rbp+ECX*4+10h]
add ebx,dword ptr [rbp+rcx*4+10h]
, но для этого счётчик цикла должен был бы быть 64-битным, а он, как мы видим, 32-битный (int i
). Т.е. ответ на вопрос "для чего это": для беззнакового расширения 32-битного счётчика цикла в регистр, который можно использовать для доступа к памяти.i
не выходит из диапазона 0..9, так что разницы между ecx и rcx нет и не может быть. Возможно я что-то упускаю и у компилятора другое мнение на этот счёт, но может быть он просто туповат и не имеет кода который бы мог использовать эту возможность оптимизации, а может такая оптимизация и есть, но она не была включена во время генерации этого кода. я так понял, происходит прыжок в никуда?
почему может не работать?
0:7c00
, но ты загрузил в ds 7c00
вместо нуля. Что не так
/AT
командной строки: Enables tiny-memory-model support.
Enables error messages for code constructs
that violate the requirements for .com format files.