(1):准备好Linux主机环境,安装好开发工具链(说明低版本gcc的安装过程):
本次实验我使用的主机环境是Ubuntu10.04,其自带的内核是2.6.26。需要的工具有gcc4.1.3,qemu和SourceInsight。
低版本的gcc安装过程 :
首先,在终端里输入:sudo apt-get install gcc-4.1 g++4.1 linux-headers-$(uname -r)
然后运行一个脚本文件
这样就可以把linux默认的gcc版本换成gcc4.1.3.
(2):下载并缺省编译Linux-2.6.38,成功:
操作如下:
第一步从https://www.kernel.org/ 网址下载2.6.38的内核并解压缩;
第二步从终端进入到linux-2.6.38中,输入:make menuconfig,不过马上会出现一个缺少库文件的错误,此时输入:sudo apt-get install libncurses5-dev,就可以顺利安装好;
第三步是从进入系统本身的/boot文件夹中,使用查看隐藏文件的操作将其中的一个隐藏文件config-2.6.32-38-generic文件copy到下载下来的2.6.38的/boot文件夹中,并修改文件名为.config;
第四步是在终端里进入linux-2.6.38中,按顺序依次输入:make, make modules(编译内核模块), make modules_install(安装内核模块), mkinitramfs -o initrd.img-2.6.38 2.6.38,最后更新一下grub即可,输入:sudo update-grub。
(3):安装源代码阅读工具,推荐SourceInsight,并基于编译过的Linux-2.6.26源代码,建立Linux-2.6.26的源代码工程:
- 若使用SourceInsight,建立利用SourceInsight的文件管理功能,去除arch目录和include目录下非x86的其他体系结构的源代码
- 使用其他源码阅读工具,可是可以的
- 要能看到若干Makefile文件
- 要能看到若干*.lds文件
(4):使用主机环境中的工具重新编译test.c并反汇编,观察函数调用框架的形成、参数的传递、返回值的传递和局部变量的定义方法,比较与课堂上讲解的有什么区别:
反汇编代码,首先是进行拆分区域初始化,将初始化数据进行压栈操作
之后还是编辑程序,首先对寄存器esp清零,之后进入test的main函数体中,首先调用Add函数
mov %eax,-0xc(%ebp)
mov -0xc(%ebp),%eax
mov %eax,0x4(%esp)
movl $0xb,(%esp)
执行完之后返回到主函数,将结果返回到寄存器eax中,然后调用printf函数打印结果。之后对esp进行赋值找到下面要运行代码地址。然后接着调用Minus
函数。
通过观察反汇编可知,反汇编代码先进行初始化数据的压栈,然后对链接进行编译,之后开始执行主函数,在函数内再调用其他函数,形成函数调用框架,以及对数据进行压栈出栈操作,运算完毕返回主函数,将结果赋给通用寄存器,返回现场继续执行。
而函数框架为分区进行初始化,调用函数顺序,和结束处理。参数传递是运用栈操作,和move函数。而值得返回也是通过move操作传给寄存器输出。局部变量会赋给通用寄存器,当数据不再使用会将通用寄存器的值弹出或是重新赋值。
(5):对gcc的优化编译进行尝试,对采用不同优化编译选项得到的可执行文件,使用time命令来获得它们各自的运行时间并进行简单比较:
下载$ time ./m0
real 0m18.474s
user 0m18.397s
sys 0m0.024s
xby@ubuntu:~/下载$ time ./m1
real 0m0.001s
user 0m0.000s
sys 0m0.000s
xby@ubuntu:~/下载$ time ./m2
real 0m0.001s
user 0m0.000s
sys 0m0.000s
xby@ubuntu:~/下载$ time ./m3
real 0m0.001s
user 0m0.000s
sys 0m0.000
由此可见,优化编译确实可以给程序的运行效率带来很大提升,在用了m1的优化后,是效率提升最明显的,后面的m2,m3的效率提升就不是很大。我分析原因可能在于test程序的过于简单,使得系统优化不能完全起到应有的效果。