文章目录
- 前言
- 前置知识
- 代码说明
- 实验操作
- 单字符打印
- 字符串打印
- 整形字符串打印
前言
本博客记录《操作系统真象还原》第六章实验的操作~
实验环境:ubuntu18.04+VMware , Bochs下载安装
实验内容:
- 实现 put_char 单字符打印输出函数。
- 实现 put_str 字符串打印输出函数。
- 实现 put_int 整形字符串打印输出函数 。
前置知识
由于本章实验我们需要将C语言和汇编语言进行结合一起使用编程,因此需要给汇编语言进行使用调用约定。C语言遵循的调用约定是cdec
l,和cdelc类似的stdcall
。(感兴趣的读者可以简单了解)
汇编语言和 C 语言混合编程可分为2大类
- 单独的汇编代码文件与单独的 C 语言文件分别编译成目标文件后,一起链接成可执行程序(掌握)见原书 P260
- 内联汇编:在 C 语言中嵌入汇编代码,直接编译生成可执行程序。
代码说明
单字符打印
/lib/kernel/print.S
- 步骤
(1)备份寄存器现场。
(2)获取光标坐标值,光标坐标值是下一个可打印字符的位置。
(3)获取待打印的字符。
(4)判断字符是否为控制字符,若是回车符、换行符、退格符三种控制字符之一,则进入相应的处理
流程。否则,其余字符都被粗暴地认为是可见字符,进入输出流程处理。
(5)判断是否需要滚屏。
(6)更新光标坐标值,使其指向下一个打印字符的位置。
(7)恢复寄存器现场,退出。
- 原理
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
- 条件编译指令#ifndef和#endif的作用:为防止头文件被重复包含,避免头文件中的变量等出现重复定义的情况。
#include "stdint.h"
:这是让编译器到系统头文件所在的目录中找所包含的文件,这个目录通常是/usr/include。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
参考资料
- 《操作系统真象还原》
- 《操作系统真象还原》第六章 ---- 开启c语言编写函数时代 首挑打印函数小试牛刀 费心讨力重回gcc降级 终尝多日调试之喜悦
- 《操作系统-真象还原》阅读总结/遗憾离场/加倍努力 出人头地