作者:dawncold
发布时间:October 22, 2011
分类:技术
其实没有像标题中说的那么宏伟,只是需要写一个软件工程用的文档,就是一系列的需求分析、设计、开发、测试、维护文档,主题自定,我觉着看了很多国内的软件作品,动不动就是XXX系统,好象任何东西加上“系统”两个字之后都会变得无比金光闪闪,那我也来一个吧——“操作系统”。
虽然不需要实际编码,但还是需要参考很多资料,不可能一句代码都不出现,主要参考的是《Orange's一个操作系统的实现》(《自己动手写操作系统》的第二版),里面最大的难点就是过多的汇编语言,其实C的程序我还是没大有问题的,只要不让我设计什么深奥算法就好:)
学期末交上这个文档,已经分给了几个人去做,但他们可能感觉时间还早吧,到现在也没有动手,我不能等他们,我需要写好设计部分,现在就得深入阅读资料了。
作者:dawncold
发布时间:April 12, 2011
分类:技术
虽然可以使用优化编译器,但对于严谨的程序员来说,能够阅读和理解汇编代码仍然是一项很重要的技能。
gcc -O2 -o p p1.c p2.c
-O2是告诉编译器使用第二级优化。第二级优化是性能优化和使用方便之间的一种很好的妥协。 程序计数器(%eip)表示将要执行的下一条指令在存储器中的地址。 C中的聚集数据类型,例如数组和结构,在汇编代码中是用连续的字节表示的。即使是对标量数据类型,汇编代码也不区分有符号或者无符号整数,不区分各种类型的指针,甚至于不区分指针和整数。
gcc -O2 -S code.c
加上-S就能看到C编译器产生的汇编代码。
pushl %ebp
表示把寄存器ebp中的内容压入程序栈中。
机器实际执行的程序只是对一系列指令进行编码的字节序列,机器动产生这些指令的源代码几乎一无所知。
要查看目标代码文件的内容,反汇编器(disassembler)的价值无法估量。
在unix系统中,用objdump可以启动反汇编器。
IA32指令长度从1~15个字节不等。
指令格式是按照这样一种方式设计的,从某个给定位置开始,可以将字节唯一地译码成机器指令。例如pushl %ebp 是以字节值55开头的。
编译器有时会在代码中插入一条nop指令,是为了填充存储该过程的空间。
Intel术语“字”表示16位数据类型。 在过程(Procedures)处理中,对前三个寄存器(%eax,%ecx,%edx)的保存和恢复惯例将不同于接下来的三个(%ebx,%edi,%esi)。最后两个寄存器(%ebp,%esp)保存着只想程序栈中重要位置的指针,只有根据栈管理的标准惯例才能修改这两个寄存器中的值。
指令的操作数分为三类:
一、立即数($123,$-134),由一个$符号加上数字,数字可以是十六进制。
二、寄存器(%eax,%ebx)。
三、存储器,根据计算出来的存储器地址访问某个存储器位置。
一般寻址格式:Imm(E(b),E(i),s)其中Imm是立即数偏移,E(b)表示一个基址寄存器,E(i)表示变址寄存器或者叫索引寄存器,s是伸缩因子,只能取值1、2、4、8. 计算方法:Imm+E(b)+E(i)xS
IA32对于mov指令的要求是不允许两个操作数都是存储器位置。
movsbl、movzbl的区别:
%dh = 8D
%eax = 98765432
movb %dh,%al //%eax = 9876548D
movsbl %dh,%eax //%eax = FFFFFF8D
movzbl %dh,%eax //%eax = 0000008D movzbl用0填充eax的高24位;
movsbl用dh中的最高位填充eax的高24位。
至于为何是填充eax的高24位,原因是movsbl、movzbl的源操作数是字节长度(就是这里的dh),而这条指令会执行扩展32位,就是把目的操作数的高24位进行相应的扩展操作。
根据惯例,所有返回整数或指针值的函数都是通过将结果放在寄存器%eax中来打到目的的。
LEA指令是将有效地址计算出来放到目的操作数中而不是取出结果放入,虽然它看起来和mov的感觉差不多:) 在for循环中初始化一个变量比如int i = 0..汇编中一般是这样做的:xorl %edx,%edx因为变量与自身做异或总是得到0的。
乘除法相比较而言是比较高级的操作,一般乘法是把一个数放入%eax,再与另一个数相乘,如:imull 12(%ebp),此处假设另外一个乘数在%ebp偏移12的地方,结果分别放在%eax和%edx中,分别保存了结果的低32位和高32位,最好根据实际情况(机器大端、小端)压栈。
除法类似,只是结果中的商保存在%eax中,余数放在%edx中。
作者:dawncold
发布时间:April 10, 2011
分类:技术
2011年4月10日星期日,晚上有雨。
第一章
一个C语言程序从源代码阶段到可执行阶段需要经历这几个步骤:
源文件---->经过预处理器(cpp)成为*.i文件---->经过编译器(cc1)成为*.s文件---->经过汇编器(as)成为*.o文件,所有函数调用都成为*.o这样可重定向的目标程序---->最后由连接器(ld)链接成成为可执行文件。cc1这名字真好听:)
系统设计者的主要目标就是让信息在各种设备之间“拷贝速度”尽量快。显示一行“hello,world”的过程主要是从磁盘---->主存---->显示设备传递。
文件是对I/O设备的抽象表示,虚拟内存主要是对贮存和磁盘I/O设备的抽象表示,进程则是对处理器、主存和I/O设备的抽象表示。
一个进程下的多个线程共享这个进程的代码和全局数据,多线程之间比多进程之间更容易共享数据,因此线程一般比进程高效。
虚拟地址空间由多个区(area)构成:程序代码和数据、堆、共享库、栈、内核虚拟存储器(占有1/4/)。
第二章
计算机使用二进制对所有数据进行编码。(这就是为什么学计算机的同学们能够用两只手数到1024而非计算机专业的同学们只能数到10:)
这里有三种最重要的数字编码:无符号(unsigned)、二进制补码(two’s-complement)、浮点数(floating-point)。
大多数计算机采用8位的块(或者叫字节)作为最小的可寻址存储器单位。存储器就象是一个很大的数组,每一个元素就是一个字节。
十六进制的转化:把每个十六进制数分别转化为二进制即可。例如:0x173A4C
1:0001
7:0111
3:0011
A:1010
4:0100
C:1100
开头的0x是十六进制的标示,无需翻译。
二进制转化到十六进制是要从右侧开始,每4位二进制数换成一个十六进制,因为取的是4位二进制数,所以不可能超过15,就能够换算成十六进制的0~F。
用一个数除以2或者16取出余数就能得到相应的二进制或者十六进制编码,不过要倒序书写余数!!!
对于一个字长为n位的机器而言,虚拟地址范围是0~(2的n次方)减1,一共是2的n次方字节。所以32位计算机的内存最大是2的32次方,即4GB。
C语言中的指针使用机器的全字长,即可能是32位长度,占用4个字节(32位计算机)。
可移植性的一个方面就是使程序对不同数据类型的确切大小不敏感。
不同的计算机对于字节的存放顺序不同,分为大端法(big endian)、小端法(little endian),不同的处理器可能选择不同,还有一些处理器用哪种取决于CPU加电启动时确定的字节顺序,随机的:)比如0x01234567这个数字,大端法机器会这样存放:01、23、45、67。而小端法机器会这样存放:67、45、23、01(每一组数据还是正常的读法,只是要从右边开始读不同的组:)
~a不是a在|运算下的逆元(相信学完离散数学就知道什么意思了:)
是不是很……?!
交换两个数的值(技巧性炫耀,没有性能上提升):
void swap(int *x , int *y)
{
*x = *x ^ *y;
*y = *x ^ *y;
*x = *x ^ *y;
}移位运算要注意结核性,x<<j<<k的结核性是(x<<j)<<k,而且还要注意优先级,1<<5-1应该是这样计算的:1<<(5-1)!!!所以只要不确定就加上括号,这样肯定安全,而且可读性也是比较好的。
右移运算分两种:算术右移和逻辑右移。算术右移在左边补充n个最高有效位的拷贝,逻辑右移是在左边补充n个0.对于无符号数的右移必须是逻辑的(补0),而几乎所有的编译器/机器组合都对有符号数据使用算术右移(拷贝最高有效位)
(此处略去xxx行,实在不想学习各种数字的定义和表示方法,承认不愿意钻研数学。不过虽然数学很难懂,但数学是死的,今天学一点明天就会少一点:)
作者:dawncold
发布时间:March 23, 2011
分类:精致地生活
很简单,放弃很多不用的东西,专心研究操作系统以及相关的数据结构实现,手头上有《现代操作系统》、《系统程序员成长计划》、《一个操作系统的实现》、《Unix编程艺术》、汇编学习书籍、敏捷开发方法。放弃PHP这方面,不过有些冲突的是最近要做一个基于PHP+MySQL的网站出来,而且还得进行后期的维护,前端特效也得忙活,还好有几个人能分担一下工作。
只是这看起来有限的时间内,我该如何安排阅读、实践呢?!这是我很头疼的问题。
作者:dawncold
发布时间:March 22, 2011
分类:技术,哲思
OS的重要性不想再赘述,不过对于一个物理硬件,好的OS能够更大程度发挥其性能,这其中绝对不能缺乏好的设计模式以及优秀的各种调度算法。这里的一切几乎都是编程的理想学习材料,不过对于这样庞大的材料需要好好解读,否则可能根本领悟不到其中的真谛。
时间管理是我个人一直推崇的一种必备技能,自己也看过几本这方面的书,不过都不得要领,感觉书中讲得很多都无法在现在社会环境中普遍适应,所以读着读着就感觉那是作者在说教了。
那么在优秀的OS架构中我们除了能够学到高超的编程技巧外,还可以对里面的一些概念进行抽象,使其能够应用到更多的方面中来,比如我感觉有些东西就能够应用到时间管理上!
这里先说一点,以后如果有新的体会再分享。
目前在单核心的CPU中,OS还是只让CPU在某个时刻只允许处理1条指令,那么我们人也应该如此。你每天要做很多事情,但你只有一个大脑,虽然这个大脑的工作效率非常高,复杂度也远远高于OS的任何调度算法之和,但一次只处理一件事的思想还是应该采纳的。传说有人做过实验,当然是传说,不知道出处。如果同时做多件事情,所需要的时间会比一件件做多出30%,这已经不是一个小数目了。这条经验告诉我们,日常工作中应该集中力量完成当前的这件事情,然后才是下一件,否则你看上去像是在并发执行多项任务,最后实际算下来多花了很多时间,这样就很难保证质量了。而且人类和机器不太一样,人类容易遗忘,机器和我们一样需要记住某些已经计算过的数据,不过机器有PCB,我们有什么呢?读书的话应该是读书笔记吧,其他方面就是备忘录了,总之要保持单一工作就好了!
- 1