0
点赞
收藏
分享

微信扫一扫

30天OS学习笔记开篇

静守幸福 2022-03-15 阅读 78

  最近,我在学习着日本作家川合秀实30天制作操作系统的书。看到书上的内容,我就想要自己也仿照其中的代码,将其改编为流行的编译器可以编译和运行的代码。

  写操作系统代码,需要用C语言与汇编语言。C语言方面,一般地,大家都是选择用GCC编译器来编译C语言。在汇编语言方面,一般地,大家都是选择用nasm汇编语言。

  我这次改编川合的代码,并未采用nasm的语法,而是采用了GCC所支持的GNU AS语法,也就是用了AT&T汇编语言。

  之所以选择用AT&T汇编语言,那是因为,Linux内核,本来就是用AT&T汇编语言写的。我觉得,若是采用AT&T汇编语言的话,可以很方便地去阅读现有的Linux内核。

  而对于nasm汇编语言,我觉得,需要了解其语法,因为,许多的写微型内核的作者,许多国内的学习与开发者,都是在用nasm汇编语言的。

  我呢,我觉得,我只是需要去了解nasm的语法,并不想在这里耗费太多的精力。

  为了学习GNU AS汇编,为了学习内核的知识,我还需要将流行的微型内核的nasm代码,改编为GNU AS语法的。

  在这样的一种改编之中,我自己,算是学到了好多的知识。

  目前,算是正在学习中。我的学习,还尚未成型。我想要去改编Linux 0.12内核,结果呢,里面有一些bug,我至今未能够解决。

  因为原版的0.12内核我没有能够成功地改编,所以就想要去试着改编流行的微型内核。希望在学习流行的微型内核的过程中,逐渐地积累内核的知识。

  目前,我是在尝试着去改编川合先生的代码。

  在改编的过程中,我发现,川合先生的代码是有点坑人啊。里面的一些个代码,用川合先生自己开发的编译器,是能够编译的。而用流行的编译器去编译的时候,就不行了。

  比如说,川合的书上有一个 jmp 0xC200的代码。这样的代码,其实在英特尔汇编里面,是没有这样的语法的。而川合的书里面出现了这样的语法。这样的东西,那就是只适合川合先生自己设计的编译器。汇编入门教材,王爽老师的16位汇编里面,也不支持这样的语法的。

  再比如,在CPU从实模式切换为保护模式的时候,需要一个跳转指令来刷新流水线。此时,在流行的汇编语言里面,它需要的是一条远跳转指令。

  这样的远跳转指令,用nasm来描述的话,它的格式如下。

  jmp   dword   segment_selector:offset 

  而在川合先生的书里面,他用的是一个短跳转指令,jmp后面直接跟的是offset的地址标号。

  这样的坑点,还真的是有啊。

  不管是在川合先生的书里面,还是在国内的教材的学习当中,我遇到的坑点,都是不少的。

  最近,我在改编川合先生的代码的时候,在进行到了显示字符与字符串的课节的时候。川合先生说,想要显示全部的ASCII码字符,需要编译作者提供的hankaku.txt文件。编译的时候,需要用到作者那里提供的一些个编编译软件。 

  作者提供的东西,在Windows里面可用。Linux里面,是不能够直接作者提供的Windows的工具软件的。作者的网站里面,其实是提供了Linux系统下面的工具软件的。不过啊,人家的官网用的是日语啊,我看不懂啊。所以呢,有这种好用的Linux软件,我也用不了。

  为了能够在改编的内核里面显示字符与字符串,我就得是自己来想办法了。

  咋办呢?我看了看作者给出的hankaku.txt文件,里面呢,大部分内容都是256个ASCII码字符的十六进制数据,并且,这些个重要数据,与作者的说明的内容并不混淆。作者在说明部分,没有用到英文句号与星号,而这个字体文件,在描述的时候,全都用的是英文句号与星号。

  想来想去,我是决定着,自己来编写程序,将作者的这个hankaku.txt文件,转码输出为C语言头文件。

  在头文件里面,声明一个大的数组,用来包含全部的ASCII码字符的字体数据。

  按照作者川合先生的设计,每一个字符用16字节的数字来表示,一共有256个字符,16乘以256,等于4096.这样,声明一个4096字节的数组,每一个元素为unsigned char类型的,应该就可以了。

  在选择程序语言的时候,我可以选择的语言有两种。第一种是C语言,第二种是C++。C语言,我手边没有书,所以,起初,我是想要采用C++的。我去查找手边的谭浩强教授的C++教材,结果发现,用不了。里面介绍的一些个语法知识是错误的。还有一些个语法,书上还没有介绍,我的要求就没有达到。

  没办法啊,C++用不了,我就用c语言来写程序呗。

  其实C语言挺好的,虽说只是面向过程的语言,但是呢,它的语法,简洁,流畅,又功能强大,实在是一个很好的编程语言。

  虽说C语言很好,可是,我手边没有书啊,好多的语法,我都给忘记了。所以呢,我还得是去网上找相关的语法讲解。

  讲解是找到了。我照着网上的语法讲解,来设计程序代码。经过几次调试,算是成功地写出了能够转换hankaku,txt的编码的程序。我将这个程序,命名为make_font.exe。源代码,我将其命名为make_font.c。

  这是一个典型的C语言文件。

  接下来,我将源码贴在这里,欢迎有需要的网友下载和使用。

#include <stdio.h>
#include <stdlib.h>

int a[8] = {128, 64, 32, 16, 8, 4, 2, 1};
int main(void)
{
	FILE * fp_in, *fp_out;
	char ch;
	int i, j;
	int n;
	char infile_name[60] = "hankaku.txt";
	char outfile_name[60] = "hankaku.h";
	
	i = 0;
	j = 0;
	n = 0;
	
	fp_in = fopen(infile_name, "r");
	fp_out = fopen(outfile_name, "w+");
	if (!fp_in || !fp_out)
	{
		printf("open file fail.\n\n");
		exit(0);
	}
	else
	{
		printf("open file successfully.\n\n");
	}
	
	fprintf(fp_out, "#ifndef _HANKAKU_H_\n");
	fprintf(fp_out, "#define _HANKAKU_H_\n\n");
	fprintf(fp_out, "unsigned char hankaku[4096] = {\n");
	while ((ch = fgetc(fp_in)) != EOF)
	{
		if (ch == '.')
		{
			n += a[i] * 0;
			i++;
		}
		else if (ch == '*')
		{
			n += a[i] * 1;
			i++;
		}
		else
		{
			continue;
		}
		
		if (i >= 8)
		{
			fprintf(fp_out, "0x%X", n);
			n = 0;
			i = 0;
			j++;
		}
		else
		{
			continue;
		}
		
		if (j >= 4096)
		{
			printf("this task is done.\n");
			printf("happy every day.\n\n");
			break;
		}
		else if (j % 16 == 0)
		{
			fprintf(fp_out, ",\n\n");
		}
		else if (j % 4 == 0)
		{
			fprintf(fp_out, ",\n");
		}
		else
		{
			fprintf(fp_out, ",\t");
		}		
	}

	fprintf(fp_out, "\n};\n\n");
	fprintf(fp_out, "#endif\n\n\n");	
	
	fclose(fp_in);
	fclose(fp_out);

	printf("task is ok.\n\n");	
	if (j < 4096)
	{
		printf("this is a test file, not a real task.\n\n");
		printf("You can pratice it next time.");
	}
	else
	{	
		printf("this is a real task.\n");
		printf("good job.\n");
		printf("Hope you success.\n\n\n");
	}
	
	return 0;
}

  全部的代码都在上面了。

  作者提供的字体库文件名为hankaku.txt,我自己在转码这个文件的时候,将目标文件命名为hankaku.h。

  命名的目标文件的名字,代码里面有。

	char infile_name[60] = "hankaku.txt";
	char outfile_name[60] = "hankaku.h";

  在代码文件的开头,有这样的两行代码。上面的一行代码,是输入文件的名字,也就是要被转换编码的文件,是作者的那个hankaku.txt。而下面的一行代码,写了输出文件的名字,hankaku.h。

  hankaku.h是一个C语言头文件。

  运行了程序以后,hankaku.h的开头部分是下面这样的。

#ifndef _HANKAKU_H_
#define _HANKAKU_H_

unsigned char hankaku[4096] = {
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,

0x0,	0x0,	0x38,	0x44,
0x82,	0xAA,	0xAA,	0x82,
0x82,	0xAA,	0x92,	0x44,
0x38,	0x0,	0x0,	0x0,

  结尾部分,是下面这样的。

0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,

0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,

0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0,
0x0,	0x0,	0x0,	0x0
};

#endif

  从输出文件上,大家可以看到,在输出代码里,我是声明了一个大数组.unsigned char hankaku[4096]。在输出的格式调整上,我让每一行放置4个数字,每一个数字,都是16进制的。每当输出了4个数,就换行。

  由于一个字符占用着16个字节,因此,每当输出了16个数字以后,我就插入两个换行。这样,每一个字符的数字编码,就很容易看清楚了。

  最后呢,所有的元素都输出完毕以后,写上大括号的右半部分。

  大括号后面,还得加一个分号。这个分号,我就曾经给忘记加了。写这个程序的时候,我才想起来,数组声明了以后,是要使用分号的。

  数组,结构体,声明完了之后,是否需要加分号,这样的零散知识,我是容易搞错的。

  最后呢,写上#endif。

  这个代码,就是我自己写的制作字体的程序了。

  目前,我只是改编到作者的第五章,显示字符串。再往后,就还没有改编。

  后面,还会有显示文字的程序代码。作者原书是说,要显示日文。而国人在翻译的时候,将其转换为了显示中文。

  还不知道,到时候,这个显示中文的程序,我能否成功地改编出来。但愿,这个显示中文的部分,里面的字库文件的转换工作,不是很难。

  现在,我还没有进行到那里,原书,我也没有学习到显示中文或日文的章节。

  看情况了,若是到时候,我能够成功地改编作者的程序,将中文字库给转换出来,并且在川合先生开发的系统里面,成功地显示了中文字符,到时候,我再来发文帖我的代码好了。

  这次的代码,就先贴这些了。

  我还想说一说,作者的那个进入保护模式的部分的汇编代码,用现有的编译器,它编译不了啊。

  作者提供的描述符是有问题的,不符合英特尔处理器的描述符格式。而这样的代码,它居然能够成功地编译,这是说明,作者提供的自制的编译器,或者是提供的qemu配套软件,是作出了特殊的处理。

  学习的时候,我是觉得,操作系统内核的学习,实在是坑多啊。

  也不知道,后面又会踩上多少坑。现在阶段的学习,难度上,还是很大的。

  只好是慢慢地来学习了。学习编程,也许,就是需要去填平很多的坑点了。 

举报

相关推荐

0 条评论