vc6 中实现gcc 的__builtin_return_address 扩展

获取函数返回值:

gcc提供了获取当前函数的返回地址的一个关键字:

void * __builtin_return_address(int nLevel);

nlevel 参数指获取哪个函数的返回值,0表示当前函数,1表示当前函数的调用者的函数,为2依次类推;

下面是vc6的实现:

__declspec (naked) void* __builtin_return_address (int iLevel)
{
    __asm
    {
        push ebx;
		
        mov eax, ebp;
        mov ebx, DWORD PTR [esp + 8]; // iLevel
		
__Next:
        test ebx, ebx;
        je  __break;
        dec ebx;
        mov eax, DWORD PTR [eax];
        jmp __Next;
__break:
		
        mov eax, DWORD PTR [eax + 4];
        pop ebx;
        ret;
    }
} 

用一个测试例子来试一下:

int sum(int a,int b)
{
	void *add=__builtin_return_address(0);
	return a+b;
}
int main(int argc, char* argv[])
{


	int c=sum(1,4);
	
	return 0;
}

这里取得是当前函数的返回地址;调试过程中用汇编展开:

32:   int main(int argc, char* argv[])
33:   {
004010A0   push        ebp
004010A1   mov         ebp,esp
004010A3   sub         esp,44h
004010A6   push        ebx
004010A7   push        esi
004010A8   push        edi
004010A9   lea         edi,[ebp-44h]
004010AC   mov         ecx,11h
004010B1   mov         eax,0CCCCCCCCh
004010B6   rep stos    dword ptr [edi]
34:
35:
36:       int c=sum(1,4);
004010B8   push        4
004010BA   push        1
004010BC   call        @ILT+0(sum) (00401005)
004010C1   add         esp,8
004010C4   mov         dword ptr [ebp-4],eax
37:
38:       return 0;
004010C7   xor         eax,eax
39:   }


我们看到,sum函数的返回地址应该是004010C1, 然后跟进sum函数,查看执行后add的地址发现恰恰是004010C1,说明模仿成功。

 

__declspec (naked)关键字说明:

naked

Microsoft Specific —>

__declspec( naked ) declarator

For functions declared with the naked attribute, the compiler generates code without prolog and epilog code. You can use this feature to write your own prolog/epilog code using inline assembler code. Naked functions are particularly useful in writing virtual device drivers.



 

你可能感兴趣的:(MFC编程)