- 论坛徽章:
- 0
|
首先要说的就是!这个是我写给我的一个业余的小组的新组员的,如果有什么不对的地方希望大家多多指点!因为是菜鸟,可能会有很多不对的地方!前辈们不要笑偶,指点指点,谢谢!
正文:
首先说一说如何对计算机接近硬件层进行学习!首先要有一种好问的思想,也就是说要经常问为什么!比如我们写一段代码:
- #include<stdio.h>
- int main(void)
- {
- printf(“hello world!”);
- }
复制代码
不要看上面是一个简简单单的hello world!的输出语句!如果仔细的朋友,会发现,就这么简单的一句hello world会站用我们的1k的空间!为什么会这样呢?这么几行就站用了1k的空间。
因为我们调用了一个头文件<stdio.h>里的一个函数printf。也许有的人学了很久的c语言,用了数以万次的printf函数!但是这个printf函数是怎么来的呢?能否自己写出来一个printf函数呢?那么printf函数里面会不会有去调用别的函数了呢?这个应该很少有人去问了,因为目前大多数写代码的人都是因为写代码赚钱多才加入这个行列的!很少有人愿意去想这些了,只要有现成的东西,拿来用就是了,这种精神,不适合学底层的开发!因为想要把底层学好,是必须要知道很多的!就比如printf函数!在操作系统诞生不久后,当时还没有一个编译器呢,那时候有printf函数?就像是我们的dos里面常用的中断int 21h一样!我们在dos里的中断号是21h那么在Linux里呢?应该不是21h了吧?那如果没有操作系统时,会不会还是21h呢?答案是肯定不会是21的,是intel写好的,而intel公司开发的芯片是硬件,不在我们的研究之内,就像是我们的操作系统为什么开机上电,自检后会把引导加载在内存的07c00处呢?这个是开发硬件的时候规定的!非我们可以改变的!这种硬件是怎么被开发出来的呢?当然是数字电路,就我所知道的数字电路设计的语言,有一个叫VHDL的语言!这个语言可以设计出一个像CPU一样的芯片!想在以后开发硬件的朋友可以看一看!
要以敢兴趣的态度去学习,不应该被钱所迷惑!是!做软件开发赚钱,但是再赚钱也没有去中关村当妓男或者当妓女赚钱,为什么不去当妓男或者妓女呢?既然做了,就应该喜欢他,就应该对他敢兴趣。比如我,我之所以想去做底层开发,完全是因为我对这个感兴趣!在两年前我用VB写软件的时候,记得当时我根本不知道button是怎么被做出来的,于是不久后我慢慢的就开始去对button产生好奇感,想知道他是怎么来的,后来听说用c语言可以画出来,那怎么画呢?在Turbo C里有一个头文件叫graphics.h,这个头文件里有很多作图的函数,比如circle();是用来画圆的,画出来一个红色的圆之后很开心,后来又试着用C语言编写一个动态的可以流动的字体,也很轻松的做出来了,用的是delay();函数和printf函数和几个颜色的枚举变量,这样,我就先告落了一段时间。当然学习是没有止境的,对于喜欢问为什么的我,这点小成就哪能满足我?我开始问自己,问别人,delay函数是怎么来的呢?printf函数是怎么来的呢?我就不断的去琢磨这么几个函数,经过一段时间的学习,和朋友的不断的提醒下,我知道printf函数是怎么来的了,原来printf函数也是通过调用几个函数来实现的,代码如下:
- #include <stddef.h>
- #include <stdarg.h>
- static char printbuf[1024];
- static int printf(const char *fmt, ...)
- {
- va_list args;
- int i;
- va_start(args, fmt);
- write(1,printbuf,i=vsprintf(printbuf, fmt, args));
- va_end(args);
- return i;
- }
复制代码
这样就把printf函数给写出来了,那么可以看到,printf函数里调用了两个函数,一个vsprintf函数,一个write函数,其实write函数是一个系统调用函数,vsprintf函数代码如下:
- int vsprintf(char *buf, const char *fmt, va_list args)
- {
- int len;
- int i;
- char * str;
- char *s;
- int *ip;
- int flags; /* flags to number() */
- int field_width; /* width of output field */
- int precision; /* min. # of digits for integers; max
- number of chars for from string */
- int qualifier; /* 'h', 'l', or 'L' for integer fields */
- for (str=buf ; *fmt ; ++fmt) {
- if (*fmt != '%') {
- *str++ = *fmt;
- continue;
- }
-
- /* process flags */
- flags = 0;
- repeat:
- ++fmt; /* this also skips first '%' */
- switch (*fmt) {
- case '-': flags |= LEFT; goto repeat;
- case '+': flags |= PLUS; goto repeat;
- case ' ': flags |= SPACE; goto repeat;
- case '#': flags |= SPECIAL; goto repeat;
- case '0': flags |= ZEROPAD; goto repeat;
- }
-
- /* get field width */
- field_width = -1;
- if (is_digit(*fmt))
- field_width = skip_atoi(&fmt);
- else if (*fmt == '*') {
- /* it's the next argument */
- field_width = va_arg(args, int);
- if (field_width < 0) {
- field_width = -field_width;
- flags |= LEFT;
- }
- }
- /* get the precision */
- precision = -1;
- if (*fmt == '.') {
- ++fmt;
- if (is_digit(*fmt))
- precision = skip_atoi(&fmt);
- else if (*fmt == '*') {
- /* it's the next argument */
- precision = va_arg(args, int);
- }
- if (precision < 0)
- precision = 0;
- }
- /* get the conversion qualifier */
- qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
- qualifier = *fmt;
- ++fmt;
- }
- switch (*fmt) {
- case 'c':
- if (!(flags & LEFT))
- while (--field_width > 0)
- *str++ = ' ';
- *str++ = (unsigned char) va_arg(args, int);
- while (--field_width > 0)
- *str++ = ' ';
- break;
- case 's':
- s = va_arg(args, char *);
- len = strlen(s);
- if (precision < 0)
- precision = len;
- else if (len > precision)
- len = precision;
- if (!(flags & LEFT))
- while (len < field_width--)
- *str++ = ' ';
- for (i = 0; i < len; ++i)
- *str++ = *s++;
- while (len < field_width--)
- *str++ = ' ';
- break;
- case 'o':
- str = number(str, va_arg(args, unsigned long), 8,
- field_width, precision, flags);
- break;
- case 'p':
- if (field_width == -1) {
- field_width = 8;
- flags |= ZEROPAD;
- }
- str = number(str,
- (unsigned long) va_arg(args, void *), 16,
- field_width, precision, flags);
- break;
- case 'x':
- flags |= SMALL;
- case 'X':
- str = number(str, va_arg(args, unsigned long), 16,
- field_width, precision, flags);
- break;
- case 'd':
- case 'i':
- flags |= SIGN;
- case 'u':
- str = number(str, va_arg(args, unsigned long), 10,
- field_width, precision, flags);
- break;
- case 'n':
- ip = va_arg(args, int *);
- *ip = (str - buf);
- break;
- default:
- if (*fmt != '%')
- *str++ = '%';
- if (*fmt)
- *str++ = *fmt;
- else
- --fmt;
- break;
- }
- }
- *str = '\0';
- return str-buf;
- }
复制代码
这里vsprintf函数也调用了不少的函数,总而言之,最后都是那么短短的几句汇编语言来实现的。
如果想知道更多的函数是怎么来的,这个就需要去阅读操作系统的源代码!比如linux 的源代码。其实想学习系统内核的编写也不是需要看大量的操作系统书籍,只要会c语言和汇编语言就应该差不多了,当然还学要有一个很好的思维。这些都是在不断的学习中积累起来的。有很多初学者对C语言的评价是做不了什么!那是因为没有看到C语言强的一部分,C语言可以写出来一个操作系统,也就是说,只要学得好,完全可以自己去设计出一个简单的内核,除了一些极端的技术需要用到汇编,其他的时候用C语言就完全可以实现。相信大多数人都应该知道.net了,那么.net是怎么来的呢?他应该是用c/c++开发出来的吧?那么C/C++是怎么来的呢?这个是我观察和学习得出的结论也许并不对,我发现c/c++和汇编语言有着很大的关联,比如goto 某个标志处,就和jmp某个标志处很相似,这个就是高级语言和汇编语言的关联之处,很多地方还是相同的,那么汇编语言是什么呢?汇编语言实际上是机器语言的助记符,例如nop的机器码是90,那么90这个机器码就不用再问怎么来的了吧?90应该是2进制转换成十六进制后得到的结果,这个是我理解的,也许有问题,如果发现有问题请指正!
在不断的问这些函数是怎么来的同时我还有一个疑问,那就是操作系统是怎么被引导起来的呢?写出一个操作系统一定很有意思。后来有位朋友告诉我,写一个内核绝对不是去用别人printf函数,绝对不是去用dos的int 21,而是自己去写printf函数,是自己去实现int 21一样的中断,这就是写操作系统,没有文件系统,自己写文件系统,没有内存管理,自己写内存管理,有了以上的条件,那么接下来想用这个内核怎么办?这个时候就要自己实现,编写键盘驱动,鼠标驱动等等,还有进程,要知道一个单任务的系统是基本上没有人愿意用的,就连自己用都不爽,那么就要学习如何设计多任务的内核,如何实现多现成!自己写函数来实现。这个就是学习底层开发的必备的心理和条件!
那么说一说想实现一个简单的嵌入式系统都需要什么样的环境:
- 1. 要有一颗爱问为什么和这个是怎么来的的心
- 2. 手头要有一个虚拟机。如(vmware)
- 3. 手头要有一个好的编译器,如(nasm)
- 4. 要学会一点汇编语言。
- 5. 要学一点C语言
复制代码
有了以上的条件就足够了,也就是说,写一个嵌入式的计算器是没有问题!只要计算器写得不超过512个字节就什么问题都没有的。而计算器与引导加起来草不到1K。而且还是实模式下的。至于什么是实模式,就要看intel公司提供的ia-32手册,这种手册是可以向intel公司order的!intel公司是支持我们对他们的产品进行学习的。IA32手册order的地址,当你填完了表之后大约一个星期左右就会有联邦快递公司给你打电话叫你去提取或者他会通过ems发到你指定的地点,order的地址是:http://www.intel.com/design/pentium4/manuals/index2.htm
当看完intel Architecture手册之后,对于intel的结构就会有一个大概的了解了,ia-32手册的第3卷讲得也很详细,相信大多数的操作系统教程会从该卷中摘抄点东西的!而想学习汇编语言可以不去买大量的汇编语言书籍,只要把IA32手册的第2卷从头到尾看一遍就会有很大的提高的,因为大多数的汇编语言教程的书中讲得不太详细,而且讲得操作指令也不全面,毕竟是intel指令嘛!他公司自己写的能少了嘛,占了两本书呢,很厚的啊!以上也就是我想要说的了。还有就是有问题多在google里找找,如果是在win下做嵌入就多看看msdn如果是在linux或unix下开发就多看看man,很有好处的,会学习才是最重要的! |
|