实现自己的打印函数

前言

本博客记录《操作系统真象还原》第六章实验的操作~

实验环境: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 两个子目录。其中 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

出现Bug:

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指令。否则,ld: i386:x86-64 architecture of input file `kernel/main.o’ is incompatible with i386 output

链接 main.o 和 print.o

一行写不下的写法:

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

或者下面这种

全部写在一行的写法:

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

Bug

注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

启动Bochs

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

启动Bochs

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

  • 写入虚拟内存

  • 启动Bochs

sudo bin/bochs -f boot/bochsrc.disk

在这里插入图片描述
在这里插入图片描述

参考资料

猜你喜欢

转载自blog.csdn.net/weixin_42888638/article/details/128601347