I. Advantages and disadvantages of inline compilation
Because using inline assembly in Visual C + + does not require additional compilers and connectors, and can handle something that cannot be handled in Visual C + +, it is convenient to use the variables in C + +. Inline assembly is mainly used for the following occasions:
1. Use assembly language to write functions;
2. Very high speed requirements of the code;
3. Direct access to hardware in the device driver;
4. Initialization and closing code for "Naked" call.
//(." Naked ", understand the meaning, but do not know how to translate the ^_^, probably is not need C + + compiler (SMART) generated function initialization and closure code, see MSDN" Naked Functions "description)
Inline assembler code is not easy to transplant, and if your program is intended to run on different types of machines (such as x86 and Alpha), you should avoid using inline assembly as much as possible. At this point you can use MASM because MASM supports more convenient macro directives and data indicators.
Ii. Inline Assembler Keywords
Using inline assembler in Visual C + + uses the __ASM keyword, which is used in two ways:
1. Simple __asm block
__asm { MOV AL, 2 MOV DX, 0xd007 Out AL, DX } |
2. Add __asm keyword before each assembly instruction
__asm MOV AL, 2 __asm MOV DX, 0xd007 __asm out AL, DX |
Because the __ASM keyword is a statement delimiter, you can put assembly instructions on the same line:
__asm mov al, 2 __asm mov DX, 0xd007 __asm out AL, DX
Obviously, the first method is consistent with the C + + style and has many other advantages, so the first method is recommended.
Unlike the "{}" in C + +, the __asm block's "{}" does not affect the scope of the C + + variable. Also, __asm blocks can be nested, and nesting does not affect the scope of the variables.
Third, the use of assembly language in the __ASM block
1. Inline assembly Instruction Set
The inline assembler fully supports the Intel 486 instruction set, allowing the use of MMX directives. Unsupported directives can be defined using the _emit pseudo-directive (_emit pseudo-instruction description, see below).
2.MASM-expression
An inline assembly can use an expression in MASM. For example: MOV EAX, 1.
3. Data indicators and operators
Although the data types and objects in C/A + + are allowed in __asm blocks, it is not possible to define data objects with MASM indicators and operators. It is noted here that the definition indicators in MASM are not allowed in the __ASM block: DB, DW, DD, DQ, DT, and DF, and the DUP and this operator are not allowed. MASM structures and records are no longer valid, and inline compilations do not accept Struc, record, width, or mask.
4.EVEN and align indicators
Although the inline assembly does not support most MASM indicators, it supports even and align, which, when needed, add a NOP (null operation) instruction to the assembly code to align the labels to a specific boundary. This enables some processors to be more efficient when taking instructions.
5.MASM Macro Indicator
Inline assembly is not a macro assembly, you cannot use the MASM macro indicator (macro, REPT, IRC, IRP, and ENDM) and macro operators (<> 、!、 &,%, and. TYPE).
6. Paragraph description
You must use a register to describe the segment, which must be explicitly stated, such as ES:[BX].
7. Type and Variable size
We can use length to get the number of elements in the array in C/T + +, and if it is not an array, the result is one. Use size to get the size of variables in C/s + +, where the size of a variable is the product of length and type. The type is used to get the size of a variable, if it is an array, it gets the size of a single element in an array.
8. Notes
You can use the comments of C + +, but it is recommended to use ASM annotations, i.e. ";" No.
9._emit pseudo-directive
_emit pseudo-directives are equivalent to DB in MASM, but only one byte at a time, such as:
__asm { JMP _codeofasm
_emit 0x00; Define data that is mixed in a code snippet _emit 0x01
_codeofasm: ; Here is the code _emit 0x90; NOP Instructions } |
Iv. using C + + language elements in __asm blocks
C + + and assembler can be mixed, in inline assembler you can use variables from C + + and many other C + + elements. The following C + + elements can be used in __asm blocks:
1. Symbols, including labels, variables and function names;
2. Constants, including symbolic constants and enum-type (enum) members;
3. Macro definition and preprocessing indicator;
4. Comments, including "" and "//";
5. Type name, including the legal type in all MASM
A generic operator such as a 6.typedef name, such as PTR, TYPE, a specific struct member, or enumeration member.
In the __asm block, you can use the cardinality notation of C + + or ASM (for example: 0x100 and 100H are equal).
__asm-C + + operators like << are not allowed in the block. C + + and MASM common operators, such as "*" and "[]" operators, are considered to be assembly-language operators. As an example:
int array[10];
__asm MOV array[6], BX; Store BX at array+6 (not scaled)
ARRAY[6] = 0; |
* Tips: Inline assembly, you can use the type operator to make it consistent with C. For example, the following two statements are the same:
__asm MOV array[6 * TYPE int], 0; Store 0 at Array + 12
ARRAY[6] = 0; |
Inline assembly can be used to directly refer to C + + variables by changing two. Any symbol, including the variable name, can be referenced in a __asm block.
If a class, struct, or enumeration member in a C + + + has a unique name, if the "." Operator does not specify a variable or typedef name before the __ASM, the member name can only be referenced in the block. However, if the member is not unique, you must be in the "." Operator is preceded by a variable or typedef name. For example, the following two structures have same_name this member variable:
struct First_type { Char *weasel; int same_name; };
struct Second_type { int wonton; Long Same_name; }; |
If you declare a variable as follows:
struct First_type hal; struct Second_type oat; |
Then, all references to Same_name members must use the variable name, because Same_name is not unique. In addition, the above weasel variable has a unique name, and you can simply use its member name to refer to it:
__asm { MOV EBX, OFFSET Hal MOV ECX, [Ebx]hal.same_name; Must use ' HAL ' MOV ESI, [Ebx].weasel; Can omit ' Hal ' } |
Note that omitting the variable name is just for the convenience of writing the code, and the resulting assembly instruction is the same. The
has unrestricted access to C + + member variables, but cannot invoke the C + + member functions.
Five, register use
Generally speaking, when the __asm block starts, the register is empty and the value of the register cannot be saved between two __asm. (This is what MSDN says, and I found it when I was actually using it, not like that.) But it's saying "General", I'm Special:)
If a function is declared as __fastcall, its parameters are placed in the register, which poses a problem for the management of the Register. Therefore, if you want to declare a function as __fastcall, you must save the ECX register. In order to avoid the above conflicts, do not have __asm blocks in the function declared as __fastcall. If you use the/GR compilation option (which becomes __fastcall globally), declare each function as __cdecl or __stdcall, which tells the compiler the traditional C method.
If you use EAX, EBX, ECX, EDX, ESI, and EDI registers, you do not need to save it, but if you use DS, SS, SP, BP, and flag registers, you should push to save the registers.
If you change the direction flag for STD and CLD in your program, you must restore it to its original value.
Six, jump
You can use Goto in C to the label in the __asm block, or in the __asm block to jump into the __asm block inside and outside the label. The labels within the __ASM block are case-insensitive (directives, indicators, and so on are also case insensitive). Example:
void Func () { Goto C_dest; Goto C_dest;
Goto A_dest; Goto A_dest;
__asm { JMP c_dest; Legal JMP c_dest; It's legit on MSDN, but I compiled it in vs.net, and I think it's illegal.
JMP a_dest; Legal JMP a_dest; Legal
A_dest:; __asm Marking }
C_dest: Return } |
Do not use the function name as a label, otherwise it will jump to the function execution instead of the label. As shown below:
; Error: Using function name as label JNE exit . . . Exit ; The following is more ASM code |
The dollar sign $ is used to specify the current position, as used below, and is commonly used for conditional jumps:
JNE $+5; The length of the following instruction is 5 bytes JMP Farlabel ; $+5, jump here. . . . Farlabel: |
Seven, call the function
The inline assembly calls the C + + function to clean up the stack itself, and here is an example of a C + + function call:
#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
Inline assembly call C function must purge stack itself Clear the stack with unused ebx registers, or add ESP, 12 POP EBX POP EBX POP EBX } } |
Note: Function parameters are stacked from right to left.
You cannot access class member functions in C + +, but you can access the extern "C" function.
If you call a Windows API function, you do not need to clear the stack yourself, because the API's return instruction is ret n, which automatically clears the stack
For example, the following:
#include
Char szappname[] = "API Test";
void Main () { Char szhello[] = "Hello, world!";
__asm { PUSH MB_OK OR mb_iconinformation PUSH OFFSET Szappname; Global variable with offset LEA EAX, Szhello; Local variables with Lea PUSH EAX PUSH 0 Call DWORD PTR [MessageBoxA]; Attention here, I took a lot of trouble to find not call MessageBoxA } } |
In general, inline assembly is used in Visual C + + to increase speed, so these function calls are written in C + + as much as possible.
八、一个 Example
The following example is written in the C language of vs.net (i.e., VC7). Build a project and put the following code in the. c file in the project and compile it without special settings.
//////////////////////////////////////////////////////////////////////// Pretreatment #include ///////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////// Global variables HWND G_hwnd; HINSTANCE G_hinst;
TCHAR sztemp[1024];
TCHAR szappname[] = "CRC32 Sample"; /////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////// function declaration 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); /////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////// Main function 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); } ///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////// Main Window callback function 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), 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, sztemp + 100, 800); wsprintf (Sztemp, "The CRC32 checksum of the string in the current text box is: 0x%lX", GetCRC32 (Sztemp +, (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 check code for Word stream Parameters: Pbdata: Point to byte throttle buffer first address NSize: Byte throttle length // return value: CRC32 check code for byte stream // Here use look-up table method to find CRC32 check code, this part is reference Lao Luo's article "Spear and Shield Contest (2)--CRC principle article" should write. Please refer to the specific contents of the original text: http://asp.7i24.com/netcool/laoluo/articles/show_article.asp?Article_ID=15 // The following use of inline assembly to find CRC32 check code, fully use the CPU registers, speed and convenience are not comparable to the use of C + + // DWORD GetCRC32 (const BYTE *pbdata, int nSize) { DWORD dwcrc32table[256];
__ASM//This inline assembly is the initialization of the CRC32 table { 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//The following is the CRC32 check code { 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 } } //////////////////////////////////////////////////////////////////////////// |
Using inline assembly in Visual C + +