__asm { MOV AL, 2 MOV DX, 0XD007 OUT AL, DX } |
__asm MOV AL, 2 __asm MOV DX, 0xD007 __asm OUT AL, DX |
__asm { JMP _CodeOfAsm _EMIT 0x00 ; 定义混合在代码段的数据 _EMIT 0x01 _CodeOfAsm: ; 这里是代码 _EMIT 0x90 ; NOP指令 } |
四、在__asm块中使用C/C++语言元素
C/C++与汇编可以混合使用,在内联汇编可以使用C/C++的变量和很多其它C/C++的元素。在__asm块中可以使用以下C/C++元素:
1.符号,包括标号、变量和函数名;
2.常量,包括符号常量和枚举型(enum)成员;
3.宏定义和预处理指示符;
4.注释,包括"/**/"和"//";
5.类型名,包括所有MASM中合法的类型
6.typedef名称, 像PTR、TYPE、特定的结构成员或枚举成员这样的通用操作符。
在__asm块中,可以使用C/C++或ASM的基数计数法(比如: 0x100和100H是相等的)。
__asm块中不能使用像<<一类的C/C++操作符。C/C++和MASM通用的操作符,比如"*"和"[]"操作符,都被认为是汇编语言的操作符。举个例子:
int array[10]; __asm MOV array[6], BX ; Store BX at array+6 (not scaled) array[6] = 0; /* Store 0 at array+12 (scaled) */ |
__asm MOV array[6 * TYPE int], 0 ; Store 0 at array + 12 array[6] = 0; /* Store 0 at array + 12 */ |
struct first_type { char *weasel; int same_name; }; struct second_type { int wonton; long same_name; }; |
struct first_type hal; struct second_type oat; |
__asm { MOV EBX, OFFSET hal MOV ECX, [EBX]hal.same_name ; 必须使用 'hal' MOV ESI, [EBX].weasel ; 可以省略 'hal' } |
void func() { goto C_Dest; /* 合法 */ goto c_dest; /* 错误 */ goto A_Dest; /* 合法 */ goto a_dest; /* 合法 */ __asm { JMP C_Dest ; 合法 JMP c_dest ; MSDN上说合法,但是我在VS.NET中编译,认为这样不合法 JMP A_Dest ; 合法 JMP a_dest ; 合法 a_dest: ; __asm 标号 } C_Dest: /* C的标号 */ return; } |
; 错误: 使用函数名作为标号 JNE exit . . . exit: ; 下面是更多的ASM代码 |
JNE $+5 ; 下面这条指令的长度是5个字节 JMP farlabel ;$+5,跳到了这里 . . . farlabel: |
七、调用函数
内联汇编调用C/C++函数必须自己清除堆栈,下面是一个调用C/C++函数例子:
#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 } } |
#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 } } |
//////////////////////////////////////////////////////////////////////// //预处理 #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++所不能比拟的 // 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 } } //////////////////////////////////////////////////////////////////////////// |