C语言进行函数调用时的汇编代码浅析

一、什么是汇编语言

       汇编语言, 即第二代计算机语言,用一些容易理解和记忆的字母,单词来代替一个特定的指令。是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。(摘自百度百科)

        简单来说,汇编语言就是一种底层的、面向机器的程序设计语言。我们可以通过阅读这种语言来加深对计算机工作原理的的理解,对计算机内部操作有一个更加清晰的认知。

二、一些简单的汇编指令

1、PUSH X;

     将执行如下操作:

         a.将X的值入系统堆栈;

         b.对esp(栈顶指针)自动减X的长度,通常为4.

2、POP X;

     将执行如下操作:

         a.将系统堆栈栈顶元素的值赋值给X;

         b.将esp(栈顶指针)自动加X所占用的长度,通常是4.

3、call XXX(函数名);

     该函数名的本质是这个函数的入口地址

     将执行如下操作:

          a.将call指令的下一条指令的首地址入系统堆栈,esp减小;

          b.以将要执行的函数表达的首地址为下一条指令地址,更改CPU的IP寄存器(指令指针寄存器,这个寄存器直接决定了当前程序到底执行哪里的代码);

4、ret;

     返回到主调函数(父函数)

     将执行如下操作:

           a.取得栈顶元素的值;

            b.并赋值给IP寄存器.

三、C语言函数调用时对应的汇编语言解析

 下面用一个简单的例子来阐明与C语言其对应的汇编代码在操作系统中是如何执行的:

1、 C语言主函数代码:

int main()
{
	int mainLocalVar = 30;
	int var2 = 17;

	mainLocalVar = functionOne(mainLocalVar, var2);

	return 0;
}

   汇编语言代码(汇编代码中LIne x表明对应的C语言代码的行数): 

_mainLocalVar$ = -4      //定义了该变量的偏移量为-4
_var2$ = -8              //定义了该变量的偏移量为-8
_main	PROC NEAR
; Line 17
	push	ebp              //栈底指针的值入系统堆栈
	mov	ebp, esp         //栈底指针和栈顶指针指向同一个地方
	sub	esp, 8           //栈顶指针的值减8
; Line 18
	mov	DWORD PTR _mainLocalVar$[ebp], 30	; 0000001eH   //把30赋值给栈底指针向下的0到4字节的位置
; Line 19
	mov	DWORD PTR _var2$[ebp], 17		; 00000011H   //把17赋值给栈底指针向下的第5到第8个字节
; Line 21
	mov	eax, DWORD PTR _var2$[ebp]             //把var2变量的值放进eax寄存器
	push	eax                                    //eax入栈
	mov	ecx, DWORD PTR _mainLocalVar$[ebp]     //把mainLocalVar变量的值放进ecx寄存器
	push	ecx                                    //ecx入栈
	call	_functionOne                           //先把下一条语句的首地址放入系统堆栈,再执行functionOne函数
	add	esp, 8                                 //栈顶元素的值加8
	mov	DWORD PTR _mainLocalVar$[ebp], eax     //eax的值赋值给mainLocalVar
; Line 23
	xor	eax, eax             //对两个值进行或异运算
; Line 24
	mov	esp, ebp             //ebp esp指向同一位置
	pop	ebp                  //把栈顶元素的值赋值给ebp
	ret	0                    //返回父函数
_main	ENDP

2、functionOne函数C语言代码:

int functionOne(int formalVarInt, int formalVArShort) {
	static int staticVarInt = 20;

	staticVarInt += formalVarInt + formalVArShort;
	++globolVar;

	return globolVar + staticVarInt;
}

functionOne函数汇编代码:

_formalVarInt$ = 8                  //定义formalVarInt的偏移量为8
_formalVArShort$ = 12               //定义formalVarShort的偏移量为12
_functionOne PROC NEAR
; File aboutSysStack.c
; Line 7
	push	ebp                  //栈底指针ebp的值入栈
	mov	ebp, esp             //ebp和esp指向同一位置
; Line 10
	mov	eax, DWORD PTR _formalVarInt$[ebp]           //formalVarInt的值放入eax寄存器
	add	eax, DWORD PTR _formalVArShort$[ebp]         //formalVarShort的值与寄存器eax的值相加
	mov	ecx, DWORD PTR _?staticVarInt@?1??functionOne@@9@9    //staticVarInt的值放入寄存器ecx
	add	ecx, eax                                     //eax和ecx的值相加
	mov	DWORD PTR _?staticVarInt@?1??functionOne@@9@9, ecx   //ecx的值赋值给staticVarInt
; Line 11
	mov	edx, DWORD PTR _globolVar         //变量globalVar入栈
	add	edx, 1                            //edx的值加1
	mov	DWORD PTR _globolVar, edx         //将edx的值赋值给globalVar
; Line 13
	mov	eax, DWORD PTR _globolVar         //globalVar的值入eax寄存器
	add	eax, DWORD PTR _?staticVarInt@?1??functionOne@@9@9  //staticVarInt的值与eax的值相加
; Line 14
	pop	ebp           //将栈顶元素的值赋值给ebp
	ret	0             //返回到主调函数
_functionOne ENDP

    下面给出图解:

C语言进行函数调用时的汇编代码浅析_第1张图片  四、总结                   

    从以上的C语言源代码与汇编语言代码的比较,可以得到如下结论:

    1、全局变量与静态存储类变量的空间,是exe文件就制定好的空间,即数据段空间。

    2、局部变量和形参变量占用的是系统堆栈空间。

    3、形参与实参的关系:

          a.实参表达式的值,将被"入栈"到系统堆栈空间;

          b. 形参变量所占用的空间,其实就是对应的实参的值在系统的空间,这就是“值传递”的过程。

   4、函数调用是存在系统消耗的。事实上,对于一个无参且无局部变量的函数的调用,至少需要消耗8B的系统堆栈空间。而系   统堆栈空间是极其有限的,因此,无度的递归调用,会使系统堆栈空间迅速消耗殆尽,并使得系统崩溃。      

以上文章中若有讲解不周或有误的地方,欢迎各位大佬指正。              

你可能感兴趣的:(C语言,汇编语言,数据结构,汇编语言与C语言)