独自の印刷機能を実装する

序文

このブログは、「オペレーティングシステムの真実還元」第6章の実験の動作を記録したものです~

実験環境:ubuntu18.04+VMware、Bochsをダウンロードしてインストール

実験内容

  1. put_char 単一文字印刷出力関数を実装します。
  2. put_str 文字列出力関数を実装します。
  3. put_int 整数文字列出力関数を実装します。

前提知識

この章の実験では C 言語とアセンブリ言語を組み合わせてプログラミングする必要があるため、アセンブリ言語の呼び出し規約を使用する必要があります。C 言語で使用される呼び出し規則はcdecl であり、 cdelc に似ていますstdcall(興味のある読者はさらに簡単に学ぶことができます)

アセンブリ言語と C 言語の混合プログラミングは、大きく 2 つのカテゴリに分類できます。

  1. 別々のアセンブリコードファイルと別々のC言語ファイルをそれぞれオブジェクトファイルにコンパイルした後、それらをリンクして実行可能なプログラム(マスタリー)を作成します(原書P260参照)。
  2. インライン アセンブリ: C 言語にアセンブリ コードを埋め込み、直接コンパイルして実行可能プログラムを生成します。

コードの説明

単一文字の印刷

/lib/kernel/print.S

  1. ステップ
(1)备份寄存器现场。
(2)获取光标坐标值,光标坐标值是下一个可打印字符的位置。
(3)获取待打印的字符。
(4)判断字符是否为控制字符,若是回车符、换行符、退格符三种控制字符之一,则进入相应的处理
流程。否则,其余字符都被粗暴地认为是可见字符,进入输出流程处理。
(5)判断是否需要滚屏。
(6)更新光标坐标值,使其指向下一个打印字符的位置。
(7)恢复寄存器现场,退出。
  1. 原理
    put_char の印刷原理は、ビデオ メモリに直接書き込むことです。

/lib/kernel/print.h

#ifndef __LIB_KERNEL_PRINT_H
#define __LIB_KERNEL_PRINT_H
#include "stdint.h"
void put_char(uint8_t char_asci);
#endif
  1. 条件付きコンパイル ディレクティブ #ifndef および #endif の役割: ヘッダー ファイルが繰り返しインクルードされるのを防ぎ、ヘッダー ファイル内で変数が繰り返し定義されるのを防ぎます。
  2. #include "stdint.h": これは、システム ヘッダー ファイルが配置されているディレクトリでインクルード ファイルを検索するようにコンパイラに指示します。このディレクトリは通常、/usr/include です。
  3. void put_char(uint8_t char_asci);: put_char 関数のプロトタイプを与える単純な宣言 (アセンブリ言語で記述)。

/kernel/main.c

ヘッダーファイルを導入してプログラムを作成できる

#include "print.h"
int main() {
    
    
    put_char('k');
    while(1);
}

実験運用

単一文字の印刷

まず、ファイルをより適切に管理するために、lib ディレクトリに user と kernel の 2 つのサブディレクトリを作成できます。下部lib/kernel/にはカーネルが使用するライブラリファイルが格納され、lib/user/中央にはユーザープロセスが使用するライブラリファイルが格納されます。

まず、lib/kernel に print.S ファイルと print.h ファイルを作成します。

(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ sudo vim print.S
(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ sudo vim print.h

print.S をコンパイルします。

(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ ls
print.h  print.S
(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ sudo nasm -f elf -o  print.o print.S
(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ ls
print.h  print.o  print.S

main.c をコンパイルします。

sudo gcc -m32 -I lib/kernel/ -c -o kernel/main.o kernel/main.c
(base) user@ubuntu:/home/cooiboi/bochs$ sudo gcc -m32 -I lib/kernel/ -c -o kernel/main.o kernel/main.c

バグが発生します:

In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdint.h:9:0,
                 from lib/kernel/print.h:3,
                 from kernel/main.c:1:
/usr/include/stdint.h:26:36: fatal error: bits/libc-header-start.h: No such file or directory
 #include <bits/libc-header-start.h>
                                    ^
compilation terminated.

解決

sudo apt-get install gcc-multilib

注記]:-m32指示を追加する必要があります。それ以外の場合、入力ファイル `kernel/main.o' の ld: i386:x86-64 アーキテクチャは i386 出力と互換性がありません

main.o と print.o をリンクする

1 行に収まらない書き方:

sudo ld -m elf_i386  -Ttext 0xc0001500 -e main -o kernel/kernel.bin\
> kernel/main.o lib/kernel/print.o

またはこのようなもの

すべてを 1 行で記述します。

sudo ld -m elf_i386  -Ttext 0xc0001500 -e main -o kernel/kernel.bin kernel/main.o lib/kernel/print.o

バグ

注1】次のプロンプトが表示され、mian.o のコンパイルに問題があるため、再コンパイルする必要があることを示しています。

(base) user@ubuntu:/home/cooiboi/bochs$ sudo ld -m elf_i386  -Ttext 0xc0001500 -e main -o kernel/kernel.bin > kernel/main.o lib/kernel/print.o
ld: warning: cannot find entry symbol main; defaulting to 00000000c000150

注2】:需要添加-m elf_i386命令。ld: i386 architecture of input file `lib/kernel/print.o’ is incompatible with i386:x86-64 output

仮想メモリへの書き込み

sudo dd if=/home/cooiboi/bochs/kernel/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc
(base) user@ubuntu:/home/cooiboi/bochs$ sudo dd if=/home/cooiboi/bochs/kernel/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc
4+1 records in
4+1 records out
2352 bytes (2.4 kB, 2.3 KiB) copied, 0.000127066 s, 18.5 MB/s

スタートボックス

sudo bin/bochs -f boot/bochsrc.disk
(base) user@ubuntu:/home/cooiboi/bochs$ sudo bin/bochs -f boot/bochsrc.disk

ここに画像の説明を挿入します
ここに画像の説明を挿入します

文字列印刷

まず、print.S ファイルと print.h ファイルを変更します。

(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ sudo vim  print.S
(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ sudo vim  print.h

print.S をコンパイルします。

sudo nasm -f elf -o  print.o print.S
(base) user@ubuntu:/home/cooiboi/bochs/lib/kernel$ sudo nasm -f elf -o  print.o print.S

main.c ファイルを変更し、同時にコンパイルします。

(base) user@ubuntu:/home/cooiboi/bochs/kernel$ sudo vim main.c

ここに画像の説明を挿入します

sudo gcc -m32 -I lib/kernel/ -c -o kernel/main.o kernel/main.c
(base) user@ubuntu:/home/cooiboi/bochs$ sudo gcc -m32 -I lib/kernel/ -c -o kernel/main.o kernel/main.c

main.o と print.o をリンクする

sudo ld -m elf_i386  -Ttext 0xc0001500 -e main -o kernel/kernel.bin kernel/main.o lib/kernel/print.o
(base) user@ubuntu:/home/cooiboi/bochs$ sudo ld -m elf_i386  -Ttext 0xc0001500 -e main -o kernel/kernel.bin kernel/main.o lib/kernel/print.o

仮想メモリへの書き込み

sudo dd if=/home/cooiboi/bochs/kernel/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc
(base) user@ubuntu:/home/cooiboi/bochs$ sudo dd if=/home/cooiboi/bochs/kernel/kernel.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=200 seek=9 conv=notrunc
5+1 records in
5+1 records out
2820 bytes (2.8 kB, 2.8 KiB) copied, 0.000134415 s, 21.0 MB/s

スタートボックス

sudo bin/bochs -f boot/bochsrc.disk
(base) user@ubuntu:/home/cooiboi/bochs$ sudo bin/bochs -f boot/bochsrc.disk

ここに画像の説明を挿入します
ここに画像の説明を挿入します

統合された文字列印刷

整数文字の印刷方法は文字列の印刷方法と似ており、主な手順は次のとおりです。

  • /home/cooiboi/bochs/lib/kernel ディレクトリ内の print.S および print.h ファイルを変更します。

  • print.S をコンパイルします。

  • main.c ファイルを変更し、同時にコンパイルします。
    ここに画像の説明を挿入します

  • main.o と print.o をリンクする

  • 仮想メモリへの書き込み

  • スタートボックス

sudo bin/bochs -f boot/bochsrc.disk

ここに画像の説明を挿入します
ここに画像の説明を挿入します

参考文献

おすすめ

転載: blog.csdn.net/weixin_42888638/article/details/128601347