我试图使用NASM将osdev c kernel中列出的准系统内核转换为汇编语言。 c版本工作得很好但不知何故我搞砸了asm。
程序首先使用bg和fg颜色初始化视频缓冲区,然后尝试将2行字符串写入视频缓冲区,从0xB8000开始,然后停止。
我尝试将背景颜色更改为蓝色,将forecolor更改为白色似乎正常工作,这表明对 _term_init 的调用确实有效。但除此之外,似乎没有任何东西像我希望的那样起作用。
我在汇编语言方面真的很新,希望那里的英雄可以拯救我的日子......
提前致谢。
以下是我的3个asm文件,使用以下命令编译:
nasm -felf32 [input.asm] -o [output.o]
然后使用
链接i686-elf-gcc -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib [all object files] -lgcc
kernel.asm
[bits 32]
global kernel_main:function (kernel_main.end - kernel_main)
extern _term_writestring
extern _term_init
SECTION .text align=16
kernel_main:; Function begin
push ebp
mov ebp, esp
call _term_init
push version
call _term_writestring
add esp, 4
push cpright
call _term_writestring
add esp, 4
leave
ret
.end:
; kernel_main End of function
SECTION .data align=1
version db "Simple OS Version 0.0.3\n", 0
cpright db "Sin Hing 2017 all rights reserved\n", 0
SECTION .bss align=1
SECTION .rodata align=4
welcome_string: ; byte
db 53H, 69H, 6DH, 70H, 6CH, 65H, 20H, 4FH ; 0000 _ Simple O
db 53H, 20H, 56H, 65H, 72H, 73H, 69H, 6FH ; 0008 _ S Versio
db 6EH, 20H, 30H, 2EH, 30H, 2EH, 33H, 0AH ; 0010 _ n 0.0.3.
db 53H, 69H, 6EH, 20H, 48H, 69H, 6EH, 67H ; 0018 _ Sin Hing
db 20H, 61H, 6CH, 6CH, 20H, 72H, 69H, 67H ; 0020 _ all rig
db 68H, 74H, 73H, 20H, 72H, 65H, 73H, 65H ; 0028 _ hts rese
db 72H, 76H, 65H, 64H, 2EH, 0AH, 00H ; 0030 _ rved...
term.asm
[bits 32]
VGA_WIDTH equ 80
VGA_HEIGHT equ 25
global term_buffer
global term_col
global term_row
global _term_init:function (_term_init.end - _term_init) ; void _term_init(void)
global _term_setcolor:function (_term_setcolor.end - _term_setcolor) ; void _term_setcolor(char)
global _term_putentryat:function (_term_putentryat.end - _term_putentryat) ; void _term_putentryat(char, char, dword, dword)
global _term_putchar:function (_term_putchar.end - _term_putchar) ; void _term_putchar(char)
global _term_write:function (_term_write.end - _term_write) ; void _term_write(char*, dword)
global _term_writestring:function (_term_writestring.end - _term_writestring) ; void _term_writestring(char*)
extern _strlen ; near
SECTION .text align=16
; Function _term_init: Initialize terminal
_term_init:; Function begin
mov dword [term_row], 0 ; term_row = 0
mov dword [term_col], 0 ; term_col = 0
mov byte [term_color], 7 ; bg - 0(black), fg - 7(grey)
mov dword [term_buffer], 753664 ; [term_buffer] becoming origin or video mem
movzx edx, byte [term_color] ; set edx := term_color
mov eax, 753664 ; 0xB8000 - hardware video memory
shl edx, 8 ; edx ([term_color]) << 8
or edx, 0x20 ; 0x20=' '
.L1: mov word [eax], dx ; [eax] = ' '|bgfg
add eax, 2 ; 1 buffer = 1 word (2 byte)
cmp eax, 757664 ; 80*25*2byte = 4000byte + origin
jne .L1
ret
.end:
; term_init End of function
; Function _term_setcolor: Set terminal background and foreground color (fg | bg << 4)
_term_setcolor:; Function begin
mov eax, dword [esp+4]
mov byte [term_color], al
ret
.end:
; term_setcolor End of function
; Function _term_putentryat: Write an entry to terminal buffer
_term_putentryat:; Function begin
movzx edx, byte [esp+8] ; color
shl edx, 8
movzx eax, byte [esp+4] ; c
or edx, eax
mov eax, dword [esp+16] ; y
mov ebx, VGA_WIDTH
mul ebx ; y * 80
add eax, dword [esp+12] ; + x
mov ecx, dword [term_buffer]
mov word [ecx+eax*2], dx ; 2 byte per buffer
ret
.end:
; term_putentryat End of function
; Function _term_putchar: write a char into terminal buffer
_term_putchar:; Function begin
push ebp
mov ebp, esp
; Call _term_putentryat
mov eax, dword [term_row] ; y
push eax
mov eax, dword [term_col] ; x
push eax
movzx eax, byte [term_color]
push eax
movzx eax, byte [ebp+8] ; c
call _term_putentryat
add esp, 16
mov eax, dword [term_col] ; if (++term_col == 80)
inc eax
cmp eax, VGA_WIDTH
jne .leave
mov dword [term_col], 0 ; term_col = 0
; TODO: if reaching end of buffer, pop buffer top line into history, shift remaining
; lines 1 row up.
mov eax, dword [term_row] ; if (++term_row == 25)
inc eax
cmp eax, VGA_HEIGHT
jne .leave
mov dword [term_row], 0 ; term_col = 0
.leave: leave
ret
.end:
; term_putchar End of function
; Function _term_write: Write input buffer to terminal buffer for [size] long, at current x, y
_term_write:; Function begin
push ebp
mov ebp, esp
xor eax, eax
mov ecx, dword [ebp+12] ; size
mov edx, dword [ebp+8] ; data (const char*)
.for: push ecx ; keep the counter
movzx ebx, byte [edx+eax] ; edx+eax == data[i]
inc eax
push ebx
call _term_putchar
add esp, 4
pop ecx ; restore counter
loop .for
leave
ret ; 0133 _ C3
.end:
; term_write End of function
; Function _term_writesring: Write a string to terminal buffer at current x, y
_term_writestring:; Function begin
push ebp
mov ebp, esp
mov edx, dword [ebp+8] ; data (char*)
push edx
call _strlen
add esp, 4
test eax, eax ; leave if zero
jz .leave
push eax ; size
mov edx, dword [ebp+8]
push edx
call _term_write
add esp, 8
.leave: leave
ret
.end:
; term_writestring End of function
SECTION .data align=1 ; section number 2, data
SECTION .bss align=1 ; section number 3, bss
term_color:
resb 1
term_buffer:
resd 1
term_col:
resw 1
term_row:
resw 1
和最后一个stdlib.asm
[bits 32]
global _strlen:function (_strlen.end - _strlen)
SECTION .text align=16
; Function _strlen: Measure the length of given string, in number of char. (ANSI)
_strlen: ; Function begin - _strlen(const char *)
push ebp
mov ebp, esp
mov edx, dword [ebp+8] ; const char * (param)
xor eax, eax ; comparand = 0
.L1: inc eax
cmp byte [edx+eax-1], 0
jne .L1
leave
ret
.end:
; strlen End of function
;SECTION .data align=1 noexecute ; section number 2, data
;SECTION .bss align=1 noexecute ; section number 3, bss
编辑:添加链接描述文件以及如何运行 这是linker.ld
/* The bootloader will look at this image and start execution at the symbol
designated as the entry point. */
ENTRY(_start)
/* Tell where the various sections of the object files will be put in the final
kernel image. */
SECTIONS
{
/* Begin putting sections at 1 MiB, a conventional place for kernels to be
loaded at by the bootloader. */
. = 1M;
/* First put the multiboot header, as it is required to be put very early
early in the image or the bootloader won't recognize the file format.
Next we'll put the .text section. */
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
/* Read-only data. */
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
/* Read-write data (initialized) */
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
/* Read-write data (uninitialized) and stack */
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
/* The compiler may produce other sections, by default it will put them in
a segment with the same name. Simply add stuff here as needed. */
}
然后我使用grub-mkrescue和这个grub.cfg
创建一个multiboot isomenuentry "myos" {
multiboot /boot/myos.bin
}
最后,我使用qemu
测试它qemu-system-i386 -cdrom myos.bin