关于naked (C++)

匡翰
2023-12-01

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 thenaked attribute is only valid on x86, and is not available on x64 or Itanium.


在网上搜了些资料后不是很理解,写了测试代码并反汇编了下:

#include <stdio.h>

void call_me(int x, int y)
{
	int a = x;
	static int b;
	int c;
	b = y;
	c = a+b;
}

void __declspec (naked) kkk(int a, int b) {
	static int c;
	int d;
	c = a + b;
	d = c;
	call_me(a, d);
}

void aaa(int a, int b) {
	static int c;
	int d;
	c = a + b;
	d = c;
	call_me(a, d);
}

int main()
{
	kkk(5, 6);
	aaa(5, 6);
	getchar();
	return 1;
}

主要想看看函数编译后,函数中栈的情况变化以及nakedshu属性的函数中,进行函数调用的情况,反汇编后如下:

 
.text:00401000 sub_401000      proc near               ; CODE XREF: .text:0040104Cp
.text:00401000                                         ; sub_401060+20p
.text:00401000
.text:00401000 var_8           = dword ptr -8
.text:00401000 var_4           = dword ptr -4
.text:00401000 arg_0           = dword ptr  8
.text:00401000 arg_4           = dword ptr  0Ch
.text:00401000
.text:00401000                 push    ebp
.text:00401001                 mov     ebp, esp
.text:00401003                 sub     esp, 8
.text:00401006                 mov     eax, [ebp+arg_0]
.text:00401009                 mov     [ebp+var_4], eax
.text:0040100C                 mov     ecx, [ebp+arg_4]
.text:0040100F                 mov     dword_4033B4, ecx
.text:00401015                 mov     edx, [ebp+var_4]
.text:00401018                 add     edx, dword_4033B4
.text:0040101E                 mov     [ebp+var_8], edx
.text:00401021                 mov     esp, ebp
.text:00401023                 pop     ebp
.text:00401024                 retn
.text:00401024 sub_401000      endp
.text:00401024
.text:00401024 ; ---------------------------------------------------------------------------
.text:00401025                 align 10h
.text:00401030
.text:00401030 loc_401030:                             ; CODE XREF: _main+7p
.text:00401030                 mov     eax, [ebp+8]
.text:00401033                 add     eax, [ebp+0Ch]
.text:00401036                 mov     dword_4033B0, eax
.text:0040103B                 mov     ecx, dword_4033B0
.text:00401041                 mov     [ebp-4], ecx
.text:00401044                 mov     edx, [ebp-4]
.text:00401047                 push    edx
.text:00401048                 mov     eax, [ebp+8]
.text:0040104B                 push    eax
.text:0040104C                 call    sub_401000
.text:00401051                 add     esp, 8
.text:00401051 ; ---------------------------------------------------------------------------
.text:00401054                 db 0Ch dup(0CCh)
.text:00401060
.text:00401060 ; =============== S U B R O U T I N E =======================================
.text:00401060
.text:00401060 ; Attributes: bp-based frame
.text:00401060
.text:00401060 sub_401060      proc near               ; CODE XREF: _main+13p
.text:00401060
.text:00401060 var_4           = dword ptr -4
.text:00401060 arg_0           = dword ptr  8
.text:00401060 arg_4           = dword ptr  0Ch
.text:00401060
.text:00401060                 push    ebp
.text:00401061                 mov     ebp, esp
.text:00401063                 push    ecx
.text:00401064                 mov     eax, [ebp+arg_0]
.text:00401067                 add     eax, [ebp+arg_4]
.text:0040106A                 mov     dword_4033AC, eax
.text:0040106F                 mov     ecx, dword_4033AC
.text:00401075                 mov     [ebp+var_4], ecx
.text:00401078                 mov     edx, [ebp+var_4]
.text:0040107B                 push    edx
.text:0040107C                 mov     eax, [ebp+arg_0]
.text:0040107F                 push    eax
.text:00401080                 call    sub_401000
.text:00401085                 add     esp, 8
.text:00401088                 mov     esp, ebp
.text:0040108A                 pop     ebp
.text:0040108B                 retn
.text:0040108B sub_401060      endp
.text:0040108B
.text:0040108B ; ---------------------------------------------------------------------------
.text:0040108C                 align 10h
.text:00401090
.text:00401090 ; =============== S U B R O U T I N E =======================================
.text:00401090
.text:00401090 ; Attributes: bp-based frame
.text:00401090
.text:00401090 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00401090 _main           proc near               ; CODE XREF: ___tmainCRTStartup+10Ap
.text:00401090
.text:00401090 argc            = dword ptr  8
.text:00401090 argv            = dword ptr  0Ch
.text:00401090 envp            = dword ptr  10h
.text:00401090
.text:00401090                 push    ebp
.text:00401091                 mov     ebp, esp
.text:00401093                 push    6
.text:00401095                 push    5
.text:00401097                 call    loc_401030
.text:0040109C                 add     esp, 8
.text:0040109F                 push    6
.text:004010A1                 push    5
.text:004010A3                 call    sub_401060
.text:004010A8                 add     esp, 8
.text:004010AB                 call    ds:getchar
.text:004010B1                 mov     eax, 1
.text:004010B6                 pop     ebp
.text:004010B7                 retn
.text:004010B7 _main           endp


仔细阅读汇编代码,可以知道:

1.naked声明的函数,编译后缺少prolog and epilog code,见代码红色部分。

2.naked声明的函数,不会进行局部变量的栈空间分配(没有push cx),而是直接进行使用(mov [ebp-4], ecx),对比代码绿色部分。

3.naked声明的函数,不会影响编译器对它所调用的函数的栈平衡,见代码紫色部分。

4.naked声明的函数,因为缺少epilog code,没有ret,所以函数必须是void类型。在实际操作中,可在依据需要在函数中自己加入ret指令。


编译工具是VS2008,设置属性如下:

/Ob1 /GL /D "_AFXDLL" /D "_UNICODE" /D "UNICODE" /FD /MD /GS- /Gy /FAs /Fa"Release\\" /Fo"Release\\" /Fd"Release\vc90.pdb" /W3 /nologo /c /Zi /Gd /TC /errorReport:prompt

 类似资料: