《真象还原》读书笔记——第六章 完善内核(打印字符代码部分)

关于字符打印代码编译时遇到的状况:

由于我的环境是 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 
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值