从汇编指令细看计算机程序的运行过程


“蔡刘平原创作品转载请注明出处 。《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 

一、相关知识点:

1、x86汇编中intel 语法与AT&T语法的区别:

X86 汇编存在两种不同的语法:inter语法和AT&T语法,在windows平台上通常使用的是inter语法,二在UNIX/linux平台的汇编器使用的则一直是AT&T语法。

inter语法相比,AT&T语法的特点有:

(1) 、寄存器前面用前缀来标识;

(2) 、指令中源操作数在前目的操作数在后;(与inter语法刚好相反)

(3) 、操作数的长度通过在指令字符后添加后缀来却定,表示 8位,表示16位,表示32位。例如:movl  %esp  %ebp,  表示将寄存器esp 中的值复制到 寄存   器ebp中。

(4) 、立即数用“$”来标识,例如:addl  $5  %eax  表示将寄存器eax 中的值加5

(5) 、变量前面加'$"表示不同的意义,例如:movl  $g  %eax   表示把 的地址存到eax中, 而 movl g  %eax 表示把变量的值存到eax中  (类似于函数参数传递   中的引用传递与值传递的区别)


2、push ,  pop , call , ret , enter , leave 等指令的等效形式:

从汇编指令细看计算机程序的运行过程_第1张图片

二、准备工作:

1、首先我们先写一个简单的C程序:

2、然后将这个C文件编译成汇编文件:gcc -S -o main.s main.c 

从汇编指令细看计算机程序的运行过程_第2张图片

3、去掉汇编文件中以点开头的标号和指令(用于连接)后得到干净的汇编代码,接下来我们将根据以下汇编代码来模拟计算机的指令执行过程。

从汇编指令细看计算机程序的运行过程_第3张图片

三、汇编代码分析:

1、从main函数开始执行,假设进入main函数之前,堆栈的栈底指针ebp指向2000,栈顶指针esp指向2000

从汇编指令细看计算机程序的运行过程_第4张图片


2、假设函数f 的入口地址为:0x1234,指令指针ip指向0x3456 

从汇编指令细看计算机程序的运行过程_第5张图片


3、ip指针指向了飞函数的入口地址后开始运行函数

         从汇编指令细看计算机程序的运行过程_第6张图片                   


4、接下来将跳转到函数g,假设函数g 的入口地址为:0x2234,此时指令指针指向:0x1248


从汇编指令细看计算机程序的运行过程_第7张图片

此时指令指针指向了0x1248,也就是回到调用函数g之前的那条指令的下一条指令(f函数中)


5、计算机又回到了函数 f 中:


从汇编指令细看计算机程序的运行过程_第8张图片

   此时指令指针指向了0x3456,也就是回到调用函数 f 之前的那条指令的下一条指令(main函数中)


6、计算机又回到了main函数中:

从汇编指令细看计算机程序的运行过程_第9张图片

因为eax 之前的值为13,所,现在eax=13+9=22


从汇编指令细看计算机程序的运行过程_第10张图片

此时经过ret 指令后,计算机退出了main 函数,进程结束。


总结:

通过以上的操作,完成了简单的从C语言到汇编语言,在模拟计算机执行汇编指令的全过程,编写的程序虽然很简单但很有代表性,包含了函数调用与参数传递,以及在程序运行中的堆栈变化,以及参数值在各个寄存器之间的传递与运算。

汇编语言不可否认要比C语言复杂、难写、难读,但是经过这样一个过程后,对汇编程序没有之前那么抵触。汇编与C语言在本质上也都一样,只是表达的形式不同。C语言中运用的是不同的变量来”存储“和传递参数,而汇编语言则是使用堆栈、寄存器来“保存”和传递参数,最终都是由运算器计算,C语言中的变量可以随意定义,但是汇编中堆栈空间和寄存器数量都有限,就像汉诺塔游戏中,给你无限多根柱子问题很容易就能解决,但是只给三根柱子问题就变得很繁琐。程序的最终目的不是解决问题,而应该是高效率的解决问题。所以一个写一个好的C语言程序只是第一步,还要有好的编译器等工具,为C程序最终要变成2进制代码交给计算机执行。




你可能感兴趣的:(汇编,堆栈,函数调用)