Bran的内核开发教程(bkerndev)-04 创建main函数和链接C文件
创建main函数和链接C文件??一般C语言使用main()函数作为程序的入口点,为了符合我们平时的编程习惯,这里我们也使用main()函数作为C代码的入口点,并在"start.asm"文件中添加中断服务程序来调用C函数。 ??在这一节教程,我们将尝试创建一个"main.c"文件和一个包含常用函数原型的头文件"system.h"。"main.c"中包含mian()函数,它将作为你C代码的入口。在内核开发中,我们一般不从main()函数返回。多数操作系统在main中初始化内核和子程序、加载shell,然后main函数会进入空循环中。在多任务系统中,当没有其他需要运行的任务时,将一直执行这个空循环。下面是"main.c"文件的示例,其中包含了最基本的main()函数和一些我们以后会用到的函数体。
#include <system.h> /* 你将要自己完成这些代码 */ unsigned char *memcpy(unsigned char *dest,const unsigned char *src,int count) { /* 在此处添加代码,将'src'中count字节的数据复制到'dest'中,* 最后返回'dest' */ } unsigned char *memset(unsigned char *dest,unsigned char val,将'dest'中的count字节全部设置成值'val',* 最后返回'dest' */ } unsigned short *memsetw(unsigned short *dest,unsigned short val,将'dest'中的count双字节设置成值'val',* 最后返回'dest' * 注意'val'是双字节 16-bit*/ } int strlen(const char *str) { /* 返回字符串的长度 * 遇到某个字节的值为0x00结束 */ } /* 我们之后将使用这个函数通过IO端口从设备读取数据,如键盘等 * 我们使用内联汇编代码(inline assembly)实现该功能 */ unsigned char inportb (unsigned short _port) { unsigned char rv; __asm__ __volatile__ ("inb %1,%0" : "=a" (rv) : "dN" (_port)); return rv; } /* 我们将使用这个函数通过I/O端口向设备写数据 * 用来修改文本模式和光标位置 * 同样,我们使用内联汇编来实现这个单用C无法实现的功能 */ void outportb (unsigned short _port,unsigned char _data) { __asm__ __volatile__ ("outb %1,%0" : : "dN" (_port),"a" (_data)); } /* 这是一个非常简单的main函数,它内部仅进行死循环 */ void main() { /* 你可以在这里添加语句 */ /* 保留此循环 * 不过,在'start.asm'里也有一个无限循环,防止你不小心删除了下面这一行*/ for (;;); } ??在你编译之前,我们需要在‘start.asm‘中添加2行代码。我们需要让编译器知道main()在外部文件中,我们还需要从‘start.asm‘文件中调用main()函数。打开‘start.asm‘文件,在 extern _main call _main ??先等等编译, ??现在我们还缺少一个"system.h"文件。创建一个名为"include"的文件夹,在该文件加下创建一个名为"system.h"的空白文本文件,将
#ifndef __SYSTEM_H #define __SYSTEM_H /* MAIN.C */ extern unsigned char *memcpy(unsigned char *dest,int count); extern unsigned char *memset(unsigned char *dest,int count); extern unsigned short *memsetw(unsigned short *dest,int count); extern int strlen(const char *str); extern unsigned char inportb (unsigned short _port); extern void outportb (unsigned short _port,unsigned char _data); #endif ??接下来,我们要来编译这些文件。打开之前的"build.bat"文件,添加下面一行命令来编译你的"main.c"。这个命令运行了gcc编译器,
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o main.o main.c ??别忘了,按照"build.bat"文件中的指示,把"main.o"添加到链接文件的列表中去。像这样: ld -T link.ld -o kernel.bin start.o main.o ??当前完整的"build.bat"文件内容如下:
echo Now assembling,compiling,and linking your kernel: nasm -f aout -o start.o start.asm rem Remember this spot here: We will add 'gcc' commands here to compile C sources gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o main.o main.c rem This links all your files. Remember that as you add *.o files,you need to rem add them after start.o. If you don't add them at all,they won't be in your kernel! ld -T link.ld -o kernel.bin start.o main.o echo Done! pause ??最后,如果你不知道该怎么实现那些附加函数,如 #include <system.h> unsigned char *memcpy(unsigned char *dest,int count) { const unsigned char *sp = (const unsigned char *)src; unsigned char *dp = dest; for(; count != 0; count--) *dp++ = *sp++; return dest; } unsigned char *memset(unsigned char *dest,int count) { unsigned char *temp = (unsigned char *)dest; for( ; count != 0; count--) *temp++ = val; return dest; } unsigned short *memsetw(unsigned short *dest,int count) { unsigned short *temp = (unsigned short *)dest; for( ; count != 0; count--) *temp++ = val; return dest; } int strlen(const char *str) { int retval; for(retval = 0; *str != ' '; str++) retval++; return retval; } /* 我们之后将使用这个函数通过IO端口从设备读取数据,防止你不小心删除了下面这一行*/ for (;;); } PS: 下面是我自己写的Win10安装gcc编译器??Win10安装gcc、g++、make: https://www.cnblogs.com/raina/p/10656106.html 本节教程对应的Linux下的编译脚本echo "Now assembling,and linking your kernel:" nasm -f elf64 -o start.o start.asm # Remember this spot here: We will add 'gcc' commands here to compile C sources gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o main.o main.c # This links all your files. Remember that as you add *.o files,you need to # add them after start.o. If you don't add them at all,they won't be in your kernel! ld -T link.ld -o kernel.bin start.o main.o echo "Done!" read -p "Press a key to continue..." _main的问题??我的gcc版本是7.4.0,在编译C程序时并没有在函数和变量名前面自己加下划线,所以按照原教程写的汇编代码,编译后会报下面的错误:
把"start.asm"里 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |