通过汇编程序看函数调用过程中的原理

本文通过C++源代码和汇编指令,深入解析函数调用过程中的参数传递、局部变量销毁和返回值返回机制。重点讨论了lea、call、ret等指令的作用,并展示了函数调用的五个关键环节:传参、保存上下文、向返回值空间写值、恢复上下文和从临时空间拷贝数据。
摘要由CSDN通过智能技术生成

一、C++ 源代码,本文所有汇编、函数堆栈数据情况都是根据以下源代码得到的

int Add(int x,int y)
{
	int sum;
	sum = x+y;
	return sum;
}

int main(int argc, char * argv[])
{
	int z;

	z = Add(1,2);
}



二、需要知道的基础知识:


1、X86 寄存器基础


    (1)ESP:栈顶指针,X86中的栈是向下增长,所以入站push时 esp--,出栈pop时,esp++

    (2)EBP:函数的参数和局部变量都是存储在程序栈中,所以当一个函数想要获取它自己的参数或者局部变量时,想到的第一个方案就是使用(ESP寄存器的值+栈偏移量)推算出参数和局部变量的地址。但是栈顶指针的值会随着程序入栈和出栈操作不断变化。所以为了计算方便,可以将该值保存到另一个寄存器---EBP(extended base pointer,扩展基址寄存器)。这样获取参数可以用:EBP+偏移量,获取局部变量就可以用  EBP-偏移量了。(下图中的数据是根据第一部分的代码得到的)

            

    (3)EBX ,基址寄存器,在内存中寻址时使用。

    (4)ESI/EDI,源/目的地址寄存器,暂时不清楚有什么用

    (5)ECX,(extended counter )计数器寄存器,和rep和loop指令搭配使用。主要用来进行循环计数

2、汇编指令基础

        (1)lea指令,格式:lea + 目的寄存器+源操作数,作用:将源操作数的地址偏移量保存到目的寄存器中。学习lea指令可以和mov指令一起来记,他们格式相同,但mov指令是将操作数指向的内存中的数据保存到目的寄存器。

       (2)call 指令,格式 :call + 目标地址,作用:将程序调转到目标地址处执行。

                 call 指令使用的是相对寻址,所谓的相对寻址就是:基址+偏移量 = 最终地址。在call指令中,基址就是call指令的下一条指令的起始地址。偏移量就是call指令中后4字节的内容。

                 call指令返回地址会在指令执行过程中被压到程序栈中。

                 等价指令:push EIP+5 ,jmp 目标地址

       (3)ret指令,作用:将栈顶保存的地址弹入EIP指令寄存器,这个过程ESP要增大(因为执行了一次出栈操作)

       (4)rep 指令,格式 rep+其他指令,作用:重复rep后面的其他指令,重复次数记录在ECX寄存器中,每次循环ECX寄存器执行减减操作。

       (5)stos指令,格式 stos+目的地址,将寄存器EAX中的内容保存到目的地址处。目的地址格式 ES:[EDI] ,ES保存了段选择符,EDI保存了段偏移量。如果设置了direction flag, 那么EDI会在该指令执行后减小, 如果没有设置direction flag, 那么EDI的值会增加, 为下一次的存储做准备

三、正文,使用汇编分析函数调用并返回过程中的原理


        1、main函数反汇编:

int main(int argc, char * argv[])
{
001D1A70 55               push        ebp  
001D1A71 8B EC            mov         ebp,esp 
001D1A73 81 EC CC 00 00 00 sub         esp,0CCh 
001D1A79 53               push        ebx  
001D1A7
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值