Using inline assembly in Visual C + +

Source: Internet
Author: User
Tags crc32 crc32 checksum goto

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 (&AMP;MSG);
DispatchMessage (&AMP;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 + +

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.