关于字符打印代码编译时遇到的状况:
由于我的环境是 Linux 64位子系统。
所以这章节的编译为:
nasm -f elf -o kernel/print.o kernel/print.asm \
&& clang -I kernel/ -m32 -c -o kernel/main.o kernel/main.c \
&& ld -m elf_i386 -Ttext 0xc0001500 -e main -o kernel.bin kernel/main.o kernel/print.o \
&& dd if=kernel.bin of=hd60M.img bs=512 count=200 seek=9 conv=notrunc
尤其要注意的是在链接的时候,main.o 和 print.o 的顺序不能颠倒,因为 main.o 中调用了 print.o 中的实现,所以main.o要在前,print.o要在后。并且这两种情况的编译出的文件大小还不一样,运行时如果不遵守这种情况情况运行还会报错。调用在前,实现在后
当 main.o print.o 时候,编译大小为:2656 bytes
当 print.o main.o 时候,编译大小为:2660 bytes
代码部分:
print.h
#ifndef __LIB_KERNEL_PRINT_H
#define __LIB_KERNEL_PRINT_H
#include "stdint.h"
void put_char(uint8_t char_asci);
#endif
print.asm
;boot.inc
TI_GDT equ 0
RPL0 equ 0
SELECTOR_VIDEO equ (0x0003<<3)+TI_GDT+RPL0
[bits 32]
section .text
;---put_char---
global put_char
put_char:
pushad
mov ax,SELECTOR_VIDEO
mov gs,ax
;---获取当前光标位置
mov dx,0x03d4
mov al,0x0e
out dx,al
mov dx, 0x03d5 ;获取高8bit
in al,dx
mov ah,al
;再获取低8位
mov dx,0x03d4
mov al,0x0f
out dx,al
mov dx,0x03d5
in al,dx
;将光标存入bx
mov bx,ax
;再栈中获取待打印的字符
mov ecx,[esp+36];4字节*8=32字节
;主调函数是4个字节
cmp cl,0xd ;CR 回车
jz .is_carriage_return
cmp cl,0xa ;LF 空格
jz .is_line_feed
cmp cl,0x8
jz .is_backspace
jmp .put_other
.is_backspace:
cmp bx,0
jz .set_cursor
dec bx
shl bx,1
mov byte [gs:bx],0x20
inc bx
mov byte [gs:bx],0x07
shr bx,1
jmp .set_cursor
.put_other:
shl bx,1
mov [gs:bx],cl
inc bx
mov byte [gs:bx],0x07
shr bx,1
inc bx
cmp bx,2000
jl .set_cursor;超过视野就滚屏
.is_line_feed: ;换行LF \n
.is_carriage_return:;回车CR \r
;如果是CR 只要将光标转移到行首就可以了
;但这里统一按照Linux处理方式,都换到下一行开头
xor dx,dx
mov ax,bx
mov si,80
div si
sub bx,dx ;总数减去余数
.is_carriage_return_end:
add bx,80
cmp bx,2000
.is_line_feed_end: ;换到下一行
jl .set_cursor
.roll_screen:
cld
mov ecx,960; 2000-80=1920; 1920*2=3940; 3940/4=960;
mov esi,0xc00b80a0
mov edi,0xc00b8000
rep movsd
mov ebx,3840
mov ecx,80 ;最后一行清零
.cls:
mov word [gs:ebx],0x0720
add ebx,2
loop .cls
mov bx,1920
.set_cursor:
;高8位
mov dx,0x03d4
mov al,0x0e
out dx,al
mov dx,0x03d5
mov al,bh
out dx,al
;低8位
mov dx,0x03d4
mov al,0x0f
out dx,al
mov dx,0x03d5
mov al,bl
out dx,al
.put_char_done:
popad
ret
main.c
#include "print.h"
int main(void){
put_char('6');
put_char(' ');
put_char('k');
put_char('e');
put_char('r');
put_char('n');
put_char('e');
put_char('l');
put_char('\n');
put_char('1');
put_char('2');
put_char('\b');
put_char('3');
while (1);
return 0;
}
加入打印字符串部分
global put_str
put_str:
push ebx
push ecx
xor ecx,ecx
mov ebx,[esp+12]
.goon:
mov cl,[ebx]
cmp cl,0
jz .put_str_over
push ecx
call put_char
add esp,4
inc ebx
jmp .goon
.put_str_over:
pop ecx
pop ebx
ret