实验一:计算机是怎样工作的
一、实验目的
请使用Example的c代码分别生成.cpp,.s,.o和ELF可执行文件,并加载运行,分析.s汇编代码在CPU上的执行过程。
通过实验解释单任务计算机是怎样工作的,并在此基础上讨论分析多任务计算机是怎样工作的。
二、实验步骤
1. Example中的c代码
int g(int x)
{
return x+3;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(8)+1;
}
2. C代码的预处理(.cpp)文件生成
# 1 "main.c"
# 1 ""
# 1 ""
# 1 "main.c"
int g(int x)
{
return x+3;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(8)+1;
}
指令:-gcc -E -o main.cpp main.c
执行程序的预处理阶段,预处理器根据以字符“#”开头的命令,修改原始的C程序。预编译过程主要处理那些源代码文件中的以“#”开始的预编译指令,主要处理的规则有:
将所有的“#include”删除,并且展开所有的宏定义;
处理所有的条件预编译指令,比如“#if”、“#ifdef”、“#elif”、“#else”、“#endif”;
处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件;
删除所有的注释“//”和“”;
删除行号和文件名标识,比如#2“hello.c”2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号;
保留所有的#pragma编译器指令,因为编译器需要使用它们。
3. C代码的汇编程序(.s)生成
.file "main.c"
.text
.globl g
.type g, @function
g: //程序指针跳到g函数
pushl �p //栈底指针ebp入栈
movl %esp, �p //将栈顶指针esp的值放入ebp里
movl 8(�p), �x //将ebp的值加8,并把结果付给eax累加器
addl $3, �x //把eax的值再加3
popl �p
ret //相当于popl %eip
.size g, .-g
.globl f
.type f, @function
f: //程序指针跳到f函数
pushl �p //栈底指针ebp入栈
movl %esp, �p //将栈顶指针esp的值放入ebp里
subl $4, %esp //栈顶指针esp减去4,即先预留出4字节空间
movl 8(�p), �x //将ebp的值加8,并把结果付给eax累加器
movl �x, (%esp) //把当前eax的值,即8压入堆栈
call g //相当于pushl %eip;movl $g的地址,%eip
leave //相当于movl �p,%esp;popl �p
ret
.size f, .-f
.globl main
.type main, @function
main: //程序指针首先指向main函数,即先执行main函数
pushl �p //栈底指针ebp入栈
movl %esp, �p //将栈顶指针esp的值放入ebp里
subl $4, %esp //栈顶指针esp减去4,即先预留出4字节空间
movl $8, (%esp) //将8压入堆栈
call f //调用f函数
addl $1, �x //eax寄存器中的值+1
leave
ret