您的位置:首页 > 运维架构 > Linux

Linux内核学习(1)_C程序执行过程

2015-03-13 23:24 239 查看

理论预备知识

存储程序计算机工作模型

冯诺依曼结构透明计算颠覆了冯诺依曼结构
存储程序
计算机(指硬件)应由运算器、存储器、控制器、输入设备和输出设备五大基本部件组成;
计算机内部采用二进制来表示指令和数据;
将编好的程序和原始数据事先存入存储器中,然后启动计算机工作,这就是存储程序的基本含义.

指令和数据都是二进制信息是没有什么区别的,指令和数据只是应用上的含义,那内存中的数据什么情况下是指令,什么情况下是数据呢? (1)任何时刻,CPU将CS:EIP指向的内容当做指令执行;(2)任何时刻,CPU将DS:[内存地址]指向的内容当做数据,内存地址的获取可以有多种寻址方式;(3)对于栈,任何时刻,SS:ESP指向栈顶元素,一般使用EBP指向栈底。

CPU中的寄存器



寻址方式

处理器根据指令中给出的地址信息来寻找物理地址的方式。在实模式下,简单总结如下(摘自王爽《汇编语言》,注意AT&T语法会有所不同):



在8086的实模式下,把某一段寄存器左移4位,然后与地址ADDR相加后被直接送到内存总线上,这个相加后的地址就是内存单元的物理地址,而程序中的这个地址就叫逻辑地址(或叫虚地址)。在IA32的保护模式下,这个逻辑地址不是被直接送到内存总线而是被送到内存管理单元(MMU)。MMU由一个或一组芯片组成,其功能是把逻辑地址映射为物理地址,即进行地址转换。如下图:



在保护模式下,我们使用三种地址:
逻辑地址:

机器语言指令仍用这种地址指定一个操作数的地址或一条指令的地址。这种寻址方式在Intel的分段结构中表现得尤为具体,它使得程序员把程序分为若干段。每个逻辑地址都由一个段和偏移量组成。

线性地址:

线性地址是一个32位的无符号整数,可以表达高达4GB的地址。通常用16进制表示线性地址,其取值范围为0x00000000~0xffffffff。

物理地址:

也就是内存单元的实际地址,用于芯片级内存单元寻址。物理地址也由32位无符号整数表示。
MMU是一种硬件电路,它包含两个部件,一个是分段部件,一个是分页部件,在此,我们把它们分别叫做分段机制和分页机制,以利于从逻辑的角度来理解硬件的实现机制。分段机制把一个逻辑地址转换为线性地址;接着,分页机制把一个线性地址转换为物理地址。如下图所示:



实验预备知识

gcc

gcc编译的背后 简化后参考下图(使用equil
smartpen2绘制):

编译分了四步:预处理(cpp)、编译(ccl)、汇编(as)、链接(ld)。使用gcc编译时gcc -E 调用cpp,gcc -S 调用ccl,gcc -c 调用as,gcc -O 调用ld。 这四步gcc的参数可以简记为ESc, 生成中间文件的后缀可以简记为iso.

qemu

QEMU使用

截屏

linux下的截屏软件scrot

AT&intel与汇编

linux下gcc采用的是AT&T的汇编格式,而windows下都是采用Intel汇编格式,他们之间的差别主要如下:

寄存器命名: AT&T中寄存器名字前带%,如%eax,而intel不带%,如eax

源,目的操作数顺序 : AT&T中源在前,目的在后,如 mov src,dst ; intel则相反

操作数长度 : AT&T中每个操作都有一个长度后缀,如movb (字节),movl(双字),movw(字),而intel则没有这种后缀

立即数格式: AT&T中立即数前有$,如$0x01;intel则没有$,如0x01

间接寻址的语法 : INTEL 中基地址使用“[” 、“]” ,而在 AT&T 中使用“(”、“)”

一些主要汇编指令的等价指令如下:





栈的使用

对于一个进程而言,它的虚拟地址空间(32位)结构大致如下:





在虚拟地址空间中有一段空间比较特殊 — 栈。其他部分都是向高地址方向增长,唯独栈是以相反的方式增长。栈在计算机中最常见的用处就是函数调用了,比如下面这段代码:

实验过程

编译代码vi main.c

<span style="font-family:SimSun;font-size:14px;">int g(int x)
{
return x+3;
}
int f(int x){
return g(x);
}
int main(void){
return f(8)+1;
}
</span>


编译main.c文件生成main.s汇编文件 gcc -S main.c -o main.s -m32

也可以objump -a main.c得到汇编代码

对生成的汇编代码删去.开头的部分,如下图



对汇编代码分析草稿图,如下



对汇编代码逐步分析

eip(x)表示指令指针指向的位置

ebp(x)实质是指栈的第x位置的指针

栈的存储单元 sp,bp指向位置

|   eip(pre)   | esp ebp 1
|——————————————|         2  eip=main
|——————————————|         3
|——————————————|         4
|——————————————|         5
|——————————————|         6
|——————————————|         7
|——————————————|         8
|——————————————|         9
|——————————————|         10
|——————————————|         11
|——————————————|         12
pushl %ebp
movl %esp %ebp
|   eip(pre)   |          1
|   ebp(1)     | esp ebp  2 eip=main+2
|——————————————|          3
|——————————————|          4
|——————————————|          5
|——————————————|          6
|——————————————|          7
|——————————————|          8
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
subl $4,%esp
mov $8,(%esp)
|    eip(pre)  |          1
|    ebp(1)    |  ebp     2 eip=main+4
|      8       |  esp     3
|——————————————|          4
|——————————————|          5
|——————————————|          6
|——————————————|          7
|——————————————|          8
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
call f
|    eip(pre)  |          1
|    ebp(1)    |   ebp    2
|    8         |          3
|    eip(main) |   esp    4      eip=f(指令指针指向汇编代码f:处)
|——————————————|          5
|——————————————|          6
|——————————————|          7
|——————————————|          8
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
进入f函数
pushl %ebp
mov %esp,%ebp
call f
|   eip(pre)   |          1
|   ebp(1)     |          2
|   8          |          3
|   eip(main)  |          4      eip=f+2
|   ebp(2)     | esp ebp  5
|——————————————|          6
|——————————————|          7
|——————————————|          8
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
subl  $4,%esp
movl  8(%ebp),%eax
|    eip(pre)  |          1
|    ebp(1)    |          2
|    8         |          3
|    eip(main) |          4      eip=f+4
|    ebp(2)    | ebp      5
|——————————————| esp      6      eax=8
|——————————————|          7
|——————————————|          8
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
movl  %eax,(%esp)
|    eip(pre)  |          1
|    ebp(1)    |          2
|    8         |          3
|    eip(main) |          4      eip=f+5
|    ebp(2)    |    ebp   5
|    8         |    esp   6      eax=8
|——————————————|          7
|——————————————|          8
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
call  g
|   eip(pre)   |          1
|   ebp(1)     |          2
|   8          |          3
|   eip(main)  |          4
|   ebp(2)     | ebp      5
|   8          |          6      eax=8
|   eip(f)     | esp      7      eip=g(指令指针指向汇编代码g:处)
|——————————————|          8
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
进入g函数
pushl %ebp
pushl %esp,%ebp
|   eip(pre)   |          1
|   ebp(1)     |          2
|   8          |          3
|   eip(main)  |          4
|   ebp(2)     | ebp      5
|   8          |          6      eax=8
|   eip(f)     |          7      eip=g+2
|   ebp(5)     | ebp esp  8
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
movl   8(%ebp),%eax
addl  $3,%eax
|    eip(pre)  |          1
|    ebp(1)    |          2
|    8         |          3
|    eip(main) |          4
|    ebp(2)    |          5
|    8         |          6
|    eip(f)    |          7      eip=g+4
|    ebp(5)    | ebp esp  8   eax=12=8+3
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
popl %ebp
|    eip(pre)  |          1
|    ebp(1)    |          2
|    8         |          3
|    eip(main) |          4
|    ebp(2)    | ebp      5
|    8         |          6
|    eip(f)    | esp      7      eip=g+5
|    ebp(5)    |          8   eax=12=8+3
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
ret
|    eip(pre)  |          1
|    ebp(1)    |          2
|    8         |          3
|    eip(main) |          4
|    ebp(2)    | ebp      5
|    8         | esp      6
|    eip(f)    |          7      eip=f+7
|    ebp(5)    |          8      eax=12=8+3
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
leave
|    eip(pre)  |          1
|    ebp(1)    |  ebp     2
|    8         |          3
|    eip(main) |  esp     4
|    ebp(2)    |          5
|    8         |          6
|    eip(f)    |          7      eip=f+8
|    ebp(5)    |          8      eax=12=8+3
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
ret
|    eip(pre)  |          1
|    ebp(1)    |  ebp     2
|    8         |          3
|    eip(main) |  esp     4      eip=main+6
|    ebp(2)    |          5
|    8         |          6
|    eip(f)    |          7
|    ebp(5)    |          8      eax=12=8+3
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
addl  $1,%eax
leave
|    eip(pre)  |  ebp esp 1
|    ebp(1)    |          2
|    8         |          3
|    eip(main) |          4      eip=main+8
|    ebp(2)    |          5
|    8         |          6
|    eip(f)    |          7
|    ebp(5)    |          8      eax=13=8+3+1
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12
ret
|    eip(pre)  |          1     eip=precious function
|    ebp(1)    |          2
|    8         |          3
|    eip(main) |          4
|    ebp(2)    |          5
|    8         |          6
|    eip(f)    |          7
|    ebp(5)    |          8      eax=13=8+3+1
|——————————————|          9
|——————————————|          10
|——————————————|          11
|——————————————|          12


总结

.这次实验先前的版本是草草了事,看到别人对这次实验写的博客详细备至,深感惭愧,就从新撰写,人与人的差距是比较中的。

.对linux内核的底层分析,需要一步步执行的分析,才能透彻,分析代码觉得会如何运行不如实际调试的真实运行

.函数参数传递机制和局部变量的存储是依靠栈的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: