以下代码实现了一个C++ command buffer,代码在VC80调试通过,支持_cdecl,_stdcall,_thiscall三种调用
1)参数存储:为了便于参数压栈,参数采用DWORD块存储,并且按照从右到左的顺序排列
2)参数进栈:使用计数循环,让每一个DWORD进栈
3)函数执行:对于_cdecl 需要手动退栈,_stdcall 和 _thiscall 自动退栈
4)未实现 check esp 和 sse优化
1
#define
OBJECT_ADDR_BIT (31)
2
#define
OBJECT_ADDR_MASK (1<<OBJECT_ADDR_BIT)
3
4
#define
AUTO_STACK_BIT (30)
5
#define
AUTO_STACK_MASK (1<<AUTO_STACK_BIT)
6
7
#define
PARAM_BLOCK_MASK (0xffff)
8
9
unsigned
int
command_buffer[
1024
*
1024
]
=
{
0
};
10
unsigned
int
command_buffer_pos
=
0
;
11
12
void
test_cmd(
int
a,
int
b)
13
{
14
int
c
=
a
+
b;
15
}
16
17
void
test_object_cmd( unsigned
int
object_addr,unsigned
int
func_addr,
int
a,
int
b )
18
{
19
int
c
=
a
+
b;
20
}
21
22
void
test_stdcall_cmd_record(
int
a,
int
b )
23
{
24
command_buffer[command_buffer_pos
++
]
=
(
2
&
PARAM_BLOCK_MASK)
|
(AUTO_STACK_MASK);
//
参数块占有DWORD个数
25
command_buffer[command_buffer_pos
++
]
=
(unsigned
int
)(
void
*
)
&
glVertex2i;
//
执行函数地址
26
/*
参数块按照倒序从右往左顺序排列
*/
27
command_buffer[command_buffer_pos
++
]
=
b;
//
参数2
28
command_buffer[command_buffer_pos
++
]
=
a;
//
参数1
29
}
30
31
void
test_cmd_record(
int
a,
int
b )
32
{
33
command_buffer[command_buffer_pos
++
]
=
(
2
&
PARAM_BLOCK_MASK)
|
(AUTO_STACK_MASK);
//
参数块占有DWORD个数
34
command_buffer[command_buffer_pos
++
]
=
(unsigned
int
)(
void
*
)
&
test_cmd;
//
执行函数地址
35
/*
参数块按照倒序从右往左顺序排列
*/
36
command_buffer[command_buffer_pos
++
]
=
b;
//
参数2
37
command_buffer[command_buffer_pos
++
]
=
a;
//
参数1
38
}
39
40
void
test_object_cmd_record( unsigned
int
object_addr,unsigned
int
func_addr,
int
a,
int
b)
41
{
42
command_buffer[command_buffer_pos
++
]
=
(
2
&
PARAM_BLOCK_MASK)
|
OBJECT_ADDR_MASK
|
AUTO_STACK_MASK;
//
最高位表示是否包含对象地址
43
command_buffer[command_buffer_pos
++
]
=
func_addr;
//
执行函数地址
44
/*
参数块按照倒序从右往左顺序排列
*/
45
command_buffer[command_buffer_pos
++
]
=
b;
//
参数2
46
command_buffer[command_buffer_pos
++
]
=
a;
//
参数1
47
command_buffer[command_buffer_pos
++
]
=
object_addr;
//
对象地址
48
}
49
50
void
exec_command_buffer()
51
{
52
int
i
=
0
;
53
int
c_command
=
0
;
54
55
while
( i
<
command_buffer_pos )
56
{
57
/*
第一个DWORD 的高16位表示是否包含对象地址,以及是否需要自动退栈;低16位表示 参数块所占用的DWORD数量
*/
58
unsigned
int
cc
=
command_buffer[i];
59
60
/*
参数块所占用的DWORD数量
*/
61
int
c
=
cc
&
0xffff
;
62
63
/*
第31位表示是否包含对象地址,如果包含对象地址,c1将用作1个DWORD的增量
*/
64
unsigned
int
c1
=
(cc
&
0x80000000
)
>>
31
;
65
66
/*
第30位表示是否需要手动退栈
*/
67
unsigned
int
c2
=
(cc
&
0x40000000
)
>>
30
;
68
69
int
func_addr
=
command_buffer[i
+
1
];
70
71
/*
如果是_cdecl 调用,将用作esp增量
*/
72
int
n
=
c
*
4
;
73
74
/*
对象地址
*/
75
int
obj_addr
=
0
;
76
77
/*
判断是否包含对象地址
*/
78
if
( c1 )
79
{
80
/*
对象地址包含在参数块的后面
*/
81
obj_addr
=
command_buffer[i
+
c
+
2
];
82
}
83
84
_asm
85
{
86
mov eax,
0
87
mov ecx,c
88
/*
参数进栈
*/
89
TARGET1:
90
91
cmp eax,ecx
92
jge TARGET2
93
mov ebx,i
94
add ebx,
2
95
add ebx,eax
96
/*
将一个DWORD进栈
*/
97
push dword ptr command_buffer[ebx
*
4
]
98
/*
计数循环并且跳转 TARGET1
*/
99
add eax,
1
100
jmp TARGET1
101
/*
处理 _thiscall 的对象地址
*/
102
TARGET2:
103
104
mov ecx,c1
105
cmp ecx,
0
106
je TARGET3
107
/*
_thiscall 需要把对象地址放入ecx
*/
108
lea ecx,obj_addr
109
TARGET3:
110
111
call func_addr
112
/*
对于_thiscall和_stdcall不需要增加esp
*/
113
mov ecx,c2
114
cmp ecx,
0
115
jne TARGET4
116
/*
_cdecl 不需要增加esp
*/
117
add esp,n
118
TARGET4:
119
120
nop
121
}
122
123
/*
移动 buffer pos
*/
124
i
+=
c
+
2
+
c1;
125
126
/*
命令计数
*/
127
c_command
++
;
128
}
129
}
130
131
132