4.__declspec(naked) 生成纯汇编使用方法

__declspec(naked)是用来告诉编译器函数代码的汇编语言为自己的所写,不需要编译器添加任何汇编代码,通俗说可生成纯汇编。

MSDN搜naked关键字即可:

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 sequences using inline assembler code. Naked functions are particularly useful in writing virtual device drivers. Note that the naked attribute is only valid on x86, and is not available on x64 or Itanium.
示例:

#define  NAKED __declspec(naked) 
VOID NAKED MyFunc() 
{ 
	__asm 
	{ 
		ret 
	} 
} 

1.使用naked 关键字必须自己构建EBP 指针(如果用到了的话);

2.必须自己使用RET 或RET n 指令返回(除非使用VOID);

这是编译器直接拿来用的汇编函数代码,所以一定要记得在开始的时候保存上下文标志位(压栈),在结束的时候要记得恢复上下文(出栈)。并且在结尾要加上ret命令。

对于一般的汇编内嵌代码,不必保存上下文了,保存也不会有事,但是不能再加ret命令,因为编译器也会为其加一个,ret命令不能同时执行两次。会导致越界错误。

如以下代码:

C调用:

#define  NAKED __declspec(naked) 
int NAKED Add(int a,int b) 
{ 
	__asm 
	{ 
		mov eax, a
		add eax, b
		ret
	} 
} 

int _tmain(int argc, _TCHAR* argv[])
{
	Add(1,2);
	return 0;
}
这时调用汇编是:

	Add(1,2);
00A217EE  push        2    
00A217F0  push        1    
00A217F2  call        Add (0A21087h) 
00A217F7  add         esp,8 // C调用,外部平衡堆 
	return 0;
__stdcall调用:

#define  NAKED __declspec(naked) 
int NAKED __stdcall Add(int a,int b) 
{ 
	__asm 
	{ 
		mov eax, a
		add eax, b
		ret 8 //自己平衡
	} 
} 

int _tmain(int argc, _TCHAR* argv[])
{
	Add(1,2);
	return 0;
}
这时调用汇编是:
	Add(1,2);
00D117EE  push        2    
00D117F0  push        1    
00D117F2  call        Add (0D111D1h) 
	return 0;
如果调试细心,应该会发现前面的Add返回结果是错误的,

其debug汇编是这样的:

0:000:x86> u 01381380 
test1!Add [f:\test1\test1\test1.cpp @ 9]:
01381380 8b4508          mov     eax,dword ptr [ebp+8]
01381383 03450c          add     eax,dword ptr [ebp+0Ch]
01381386 c20800          ret     8
注意到了,[ebp+8]和[ebp+c]分别表示a和b,

而ebp在这里其实应该是esp的值,所以改写成

#define  NAKED __declspec(naked) 
int  NAKED __stdcall Add(int a,int b) 
{ 
	__asm 
	{ 
		push ebp
		mov ebp,esp
		mov eax, a
		add eax, b
		leave
		ret 8
	} 
} 

你可能感兴趣的:(汇编,function,语言,编译器)