函数的底层机制

一.从寻址方式的角度看函数的调用

提出问题:

  • D3 FF FF FF07E1080h有什么关系?
C++
int z = Add(1, 2);
汇编代码
007E10A4 push        2  
007E10A6 push        1  
007E10A8 call        Add (07E1080h)  
007E10AD add         esp,8  
007E10B0 mov         dword ptr [z],eax
机器码
6A 02
6A 01
E8 D3 FF FF FF 
83 C4 08
89 45 FC
猜测:D3 FF FF FF是具有符号的偏移量
实证:计算器
D3 FF FF FF
11111111111111111111111111010011
00000000000000000000000000101100 0x2C
00000000000000000000000000101101 0x2D
00C110ADh - 0C11080h = 2D

发现规律:

  • call指的偏移量寻址计算公式:偏移量 = 转跳到的地址 - call指令后一条指令的起始地址
二.从指令的效果看的函数的调用

CALL指令相当于push指令jmp指令的组合

push 返回地址
jmp 函数入口地址
三.从参数的传递和获取参数的方式看函数调用
C++
int Add(int x, int y) {
    int num = x + y;
    return num;
}
汇编语言
00FC17C0 push        ebp  
00FC17C1 mov         ebp,esp  
00FC17C3 sub         esp,0CCh  //分配局部变量
00FC17C9 push        ebx  
00FC17CA push        esi  
00FC17CB push        edi  
00FC17CC lea         edi,[ebp+FFFFFF34h]  
00FC17D2 mov         ecx,33h  
00FC17D7 mov         eax,0CCCCCCCCh  
00FC17DC rep stos    dword ptr es:[edi]  
00FC17DE mov         ecx,0FCC02Ch  
00FC17E3 call        00FC1339  
  
00FC17E8 mov         eax,dword ptr [ebp+8]  
00FC17EB add         eax,dword ptr [ebp+0Ch]  
00FC17EE mov         dword ptr [ebp-8],eax  
    
00FC17F1 mov         eax,dword ptr [ebp-8]  

00FC17F4 pop         edi  
00FC17F5 pop         esi  
00FC17F6 pop         ebx  
00FC17F7 add         esp,0CCh  
00FC17FD cmp         ebp,esp  
00FC17FF call        00FC1258  
00FC1804 mov         esp,ebp //局部变量不存在了
00FC1806 pop         ebp  
00FC1807 ret
提出问题:
  • 怎么获取到栈上存储的参数1和2呢?
  • 函数是通过哪一条指令局部变量消失的呢?
  • 这个函数从传递参数开始一共执行了多少条连续的push指令呢?

猜测:通过寄存器保存esp里面的地址,然后寄存器+偏移量去访问实参
实证: 函数开头一定有以下指令

push        ebp  
mov         ebp,esp
...
pop         ebp

发现规律:

  • 参数的传递是通过push 参数1传递,参数传递时,栈顶地址会不断减少
  • 获取参数的方式是通过**[ebp+偏移量]的方式去访问参数**,通过**[ebp-偏移量]的方式访问局部变量**
  • 函数里面的局部变量在执行完 } 后就不存在了,不能再使用了
四.返回值

但返回值小于或等于4字节时,通过寄存器存储返回值

 mov         eax,dword ptr [ebp-8] 

提出问题:当返回值超过4字节如何存储返回值呢?

设计实验:

C++代码

struct myrd
{
    int i1;
    int i2;
};
myrd myfunc() {
    myrd r1;
    r1.i1 = 1;
    r1.i2 = 2;
    return r1;
};
int main()
{
    myrd r;
    r = myfunc();
}

汇编代码
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值