七、调用函数
内联汇编调用C/C++(www.cppentry.com)函数必须自己清除堆栈,下面是一个调用C/C++(www.cppentry.com)函数例子:
#include
char szformat[] = "%s %s\n"; char szHello[] = "Hello"; char szWorld[] = " world"; void main() { __asm { MOV EAX, OFFSET szWorld PUSH EAX MOV EAX, OFFSET szHello PUSH EAX MOV EAX, OFFSET szformat PUSH EAX CALL printf
//内联汇编调用C函数必须自己清除堆栈 //用不使用的EBX寄存器清除堆栈,或ADD ESP, 12 POP EBX POP EBX POP EBX } } |
注意:函数参数是从右向左压栈。
不能够访问C++(www.cppentry.com)中的类成员函数,但是可以访问extern "C"函数。
如果调用Windows API函数,则不需要自己清除堆栈,因为API的返回指令是RET n,会自动清除堆栈
比如下面的例子:
#include
char szAppName[] = "API Test";
void main() { char szHello[] = "Hello, world!";
__asm { PUSH MB_OK OR MB_ICONINformATION PUSH OFFSET szAppName ; 全局变量用OFFSET LEA EAX, szHello ; 局部变量用LEA PUSH EAX PUSH 0 CALL DWORD PTR [MessageBoxA] ; 注意这里,我费了好大周折才发现不是CALL MessageBoxA } } |
一般来说,在Visual C++(www.cppentry.com)中使用内联汇编是为了提高速度,因此这些函数调用尽可能用C/C++(www.cppentry.com)写。
八、一个例子
下面的例子是在VS.NET(即VC7)中C语言写的。先建一个工程,将下列代码放到工程中的.c文件中编译,无需作特别的设置,即可编译通过。
//////////////////////////////////////////////////////////////////////// //预处理 #include ///////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////// //全局变量 HWND g_hWnd; HINSTANCE g_hInst;
TCHAR szTemp[1024];
TCHAR szAppName[] = "CRC32 Sample"; /////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////// //函数声明 DWORD GetCRC32(const BYTE *pbData, int nSize); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow); LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); /////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////// //主函数 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) { MSG msg; WNDCLASSEX wndClassEx;
g_hInst = hInstance;
wndClassEx.cbSize = sizeof(WNDCLASSEX); wndClassEx.style = CS_VREDRAW | CS_HREDRAW; wndClassEx.lpfnWndProc = (WNDPROC) WindowProc; wndClassEx.cbClsExtra = 0; wndClassEx.cbWndExtra = 0; wndClassEx.hInstance = g_hInst; wndClassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW); wndClassEx.hbrBackground = (HBRUSH) (COLOR_WINDOW); wndClassEx.lpszMenuName = NULL; wndClassEx.lpszClassName = szAppName; wndClassEx.hIconSm = NULL;
RegisterClassEx(&wndClassEx);
g_hWnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 300, 70, NULL, NULL, g_hInst, NULL);
ShowWindow(g_hWnd, iCmdShow); UpdateWindow(g_hWnd);
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return ((int) msg.wParam); } ///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////// //主窗口回调函数 LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_NOHIDESEL | WS_OVERLAPPED, 7, 12, 220, 22, hWnd, (HMENU)1000, g_hInst, NULL); CreateWindowEx(0, "BUTTON", "&OK", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_OVERLAPPED | BS_FLAT, 244, 12, 40, 20, hWnd, (HMENU)IDOK, g_hInst, NULL);
break;
case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: GetDlgItemText(g_hWnd, 1000, szTemp + 100, 800); wsprintf(szTemp, "当前文本框内的字符串的CRC32校验码是: 0x%lX", GetCRC32(szTemp + 100, (int)strlen(szTemp + 100))); MessageBox(g_hWnd, szTemp, szAppName, MB_OK|MB_ICONINformATION); } break;
case WM_DESTROY: PostQuitMessage(0); break;
default: return (DefWindowProc(hWnd, uMsg, wParam, lParam)); } return (0); } /////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////// //GetCRC32: 求字节流的CRC32校验码 //参数: // pbData: 指向字节流缓冲区首地址 // nSize: 字节流长度 // //返回值: // 字节流的CRC32校验码 // //这里使用查表法求CRC32校验码,这部分是参考老罗的文章《 矛与盾的较量(2)——CRC原理篇》该写的。 //原文的具体内容请参看: http://asp.7i24.com/netcool/laoluo/articles/show_article.asp Article_ID=15 // //下面使用内联汇编求CRC32校验码,充分使用了CPU中的寄存器,速度和方便性都是使用C/C++(www.cppentry.com)所不能比拟的 // DWORD GetCRC32(const BYTE *pbData, int nSize) { DWORD dwCRC32Table[256];
__asm //这片内联汇编是初始化CRC32表 { MOV ECX, 256
_NextTable: LEA EAX, [ECX-1] PUSH ECX MOV ECX, 8
_NextBit: SHR EAX, 1 JNC _NotCarry XOR EAX, 0xEDB88320 _NotCarry: DEC ECX JNZ _NextBit
POP ECX MOV [dwCRC32Table + ECX*4 - 4], EAX DEC ECX JNZ _NextTable }
__asm //下面是求CRC32校验码 { MOV EAX, -1 MOV EBX, pbData OR EBX, EBX JZ _Done MOV ECX, nSize OR ECX, ECX JZ _Done
_NextByte: MOV DL, [EBX]
XOR DL, AL MOVZX EDX, DL SHR EAX, 8 XOR EAX, [dwCRC32Table + EDX*4]
INC EBX LOOP _NextByte _Done: NOT EAX } } //////////////////////////////////////////////////////////////////////////// |
|