函数参数入栈分析以及带参数的汇编函数的写法
随便找个函数调用,看看调用函数时,编译器做了什么。
看看uc/os在vc实现的代码,调试时,同时打开汇编功能,可以看到下面情况
- 63: OSTaskCreate(TaskStart, 0, &TaskStk[0][TASK_STK_SIZE-1], TaskStart_Prio);
- 004162D7 push 1
- 004162D9 push offset _TaskStk+1FFCh (0044609c)
- 004162DE push 0
- 004162E0 push offset @ILT+860(_TaskStart) (00401361)
- 004162E5 call @ILT+40(_OSTaskCreate) (0040102d)
- 004162EA add esp,10h
从汇编可以看出,程序调用OSTaskCreate函数时所做的事情,四个push操作,分别对应四个参数,从右到左。
关于这一句004162E5 call @ILT+40(_OSTaskCreate) (0040102d) 可以看看这几个链接的解释
call指令同时将ip压入栈。
进入OSTaskCreate函数后,要把那几个参数找出来。但栈存的不只是那四个参数,因此不能用pop指令,可以使用ebp,来找到参数取
出,先看看刚进入函数,编译器所做的操作
- 156: INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
- 157: {
- 00406F20 push ebp
- 00406F21 mov ebp,esp
- 00406F23 sub esp,48h
- 00406F26 push ebx
- 00406F27 push esi
- 00406F28 push edi
- 00406F29 lea edi,[ebp-48h]
- 00406F2C mov ecx,12h
- 00406F31 mov eax,0CCCCCCCCh
- 00406F36 rep stos dword ptr [edi]
这只是保存了要用到寄存器的信息,并没有找到那几个参数。实际上再向后看,当用到这些参数时,才将参数从栈中取出
00406F38 mov eax,dword ptr [ebp+14h] ;取prio
00406F87 mov eax,dword ptr [ebp+10h] ;取ptos
00406F8B mov ecx,dword ptr [ebp+0Ch] ;pdata
00406F8F mov edx,dword ptr [ebp+8] ;task
这就是四个参数的取出方式。
所以我们写自己的带参数汇编函数时,就可以仿照上面来写,先保存ebp,几个寄存器,再取参数。
下面这段汇编就是这样实现的 取自《自己动手写操作系统》。
- ; ------------------------------------------------------------------------
- ; 内存拷贝,仿 memcpy
- ; ------------------------------------------------------------------------
- ; void* MemCpy(void* es:pDest, void* ds:pSrc, int iSize);
- ; ------------------------------------------------------------------------
- MemCpy:
- push ebp
- mov ebp, esp
- push esi
- push edi
- push ecx
- mov edi, [ebp + 8] ; es:pDest
- mov esi, [ebp + 12] ; ds:pSrc
- mov ecx, [ebp + 16] ; iSize