今天有點(diǎn)時(shí)間,重新改下了下,為避免因編譯器和平臺(tái)實(shí)現(xiàn)而出現(xiàn)的問(wèn)題,我寫(xiě)了三個(gè)版本,分別是windows下vc6.0,windows下mingw和cygwin和linux下的gcc/g++。
主要從事網(wǎng)頁(yè)設(shè)計(jì)、PC網(wǎng)站建設(shè)(電腦版網(wǎng)站建設(shè))、wap網(wǎng)站建設(shè)(手機(jī)版網(wǎng)站建設(shè))、響應(yīng)式網(wǎng)站建設(shè)、程序開(kāi)發(fā)、微網(wǎng)站、小程序制作等,憑借多年來(lái)在互聯(lián)網(wǎng)的打拼,我們?cè)诨ヂ?lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)積累了豐富的成都網(wǎng)站建設(shè)、做網(wǎng)站、網(wǎng)絡(luò)營(yíng)銷(xiāo)經(jīng)驗(yàn),集策劃、開(kāi)發(fā)、設(shè)計(jì)、營(yíng)銷(xiāo)、管理等多方位專(zhuān)業(yè)化運(yùn)作于一體,具備承接不同規(guī)模與類(lèi)型的建設(shè)項(xiàng)目的能力。
vc6.0:
#include stdio.h
const char* input = "%d";
const char* output = "%d\n";
int n;
int main()
{
__asm
{
lea eax, n
push eax
push input
loopx:
call scanf
cmp eax, 1
jne end
mov ecx, n
jecxz end
dec ecx
push ecx
push output
call printf
add esp, 8
jmp loopx
end:
add esp, 8
}
return 0;
}
mingw/cygwin:
#include stdio.h
const char* input = "%d";
const char* output = "%d\n";
int n;
int main()
{
__asm__
(
"loop: \n"
"pushl $_n \n"
"pushl _input \n"
"call _scanf \n"
"addl $8, %esp \n"
"cmpl $1, %eax \n"
"jne end \n"
"movl _n, %ecx \n"
"jecxz end \n"
"decl %ecx \n"
"pushl %ecx \n"
"pushl _output \n"
"call _printf \n"
"addl $8, %esp \n"
"jmp loop \n"
"end:"
);
return 0;
}
linux gcc/g++:
#include stdio.h
const char* input = "%d";
const char* output = "%d\n";
int n;
int main()
{
__asm__
(
"pushl $n \n"
"pushl input \n"
"loop: \n"
"call scanf \n"
"cmp $1, %eax \n"
"jne end \n"
"movl n, %ecx \n"
"jecxz end \n"
"decl %ecx \n"
"pushl %ecx \n"
"pushl output \n"
"call printf \n"
"addl $8, %esp \n"
"jmp loop \n"
"end: \n"
"addl $8, %esp \n");
return 0;
}
1、在 C 文件中要嵌入?yún)R編代碼片以如下方式加入?yún)R編代碼:
#pragma ASM
; Assembler Code Here
#pragma ENDASM
2、在 Project 窗口中包含匯編代碼的 C 文件上右鍵,選擇“Options for ...”,點(diǎn)擊右邊的“Generate Assembler SRC File”
和“Assemble SRC File”,使檢查框由灰色變成黑色(有效)狀態(tài);
3、根據(jù)選擇的編譯模式,把相應(yīng)的庫(kù)文件(如 Small 模式時(shí),是 Keil\C51\Lib\C51S.Lib)加入工程中, 該文件必須作為工程的最
后文件;
啥CPU???
unsigned long Div(unsigned long X, unsigned long Y)
{
return X/Y;
}
要用匯編調(diào)用,需要學(xué)習(xí)對(duì)應(yīng)CPU的C語(yǔ)言實(shí)現(xiàn)!
在 Visual C++ 中使用內(nèi)聯(lián)匯編- -
使用內(nèi)聯(lián)匯編可以在 C/C++ 代碼中嵌入?yún)R編語(yǔ)言指令,而且不需要額外的匯編和連接步驟。在 Visual C++ 中,內(nèi)聯(lián)匯編是內(nèi)置的編譯器,因此不需要配置諸如 MASM 一類(lèi)的獨(dú)立匯編工具。這里,我們就以 Visual Studio .NET 2003 為背景,介紹在 Visual C++ 中使用內(nèi)聯(lián)匯的相關(guān)知識(shí)(如果是早期的版本,可能會(huì)有些許出入)。
內(nèi)聯(lián)匯編代碼可以使用 C/C++ 變量和函數(shù),因此它能非常容易地整合到 C/C++ 代碼中。它能做一些對(duì)于單獨(dú)使用 C/C++ 來(lái)說(shuō)非常笨重或不可能完成的任務(wù)。
一、 優(yōu)點(diǎn)
使用內(nèi)聯(lián)匯編可以在 C/C++ 代碼中嵌入?yún)R編語(yǔ)言指令,而且不需要額外的匯編和連接步驟。在 Visual C++ 中,內(nèi)聯(lián)匯編是內(nèi)置的編譯器,因此不需要配置諸如 MASM 一類(lèi)的獨(dú)立匯編工具。這里,我們就以 Visual Studio .NET 2003 為背景,介紹在 Visual C++ 中使用內(nèi)聯(lián)匯的相關(guān)知識(shí)(如果是早期的版本,可能會(huì)有些許出入)。
內(nèi)聯(lián)匯編代碼可以使用 C/C++ 變量和函數(shù),因此它能非常容易地整合到 C/C++ 代碼中。它能做一些對(duì)于單獨(dú)使用 C/C++ 來(lái)說(shuō)非常笨重或不可能完成的任務(wù)。
內(nèi)聯(lián)匯編的用途包括:
使用匯編語(yǔ)言編寫(xiě)特定的函數(shù);
編寫(xiě)對(duì)速度要求非常較高的代碼;
在設(shè)備驅(qū)動(dòng)程序中直接訪(fǎng)問(wèn)硬件;
編寫(xiě) naked 函數(shù)的初始化和結(jié)束代碼。
二、 關(guān)鍵字
使用內(nèi)聯(lián)匯編要用到 __asm 關(guān)鍵字,它可以出現(xiàn)在任何允許 C/C++ 語(yǔ)句出現(xiàn)的地方。我們來(lái)看一些例子:
簡(jiǎn)單的 __asm 塊:
__asm
{
MOV AL, 2
MOV DX, 0xD007
OUT AL, DX
}
在每條匯編指令之前加 __asm 關(guān)鍵字:
__asm MOV AL, 2
__asm MOV DX, 0xD007
__asm OUT AL, DX
因?yàn)?__asm 關(guān)鍵字是語(yǔ)句分隔符,所以可以把多條匯編指令放在同一行:
__asm MOV AL, 2 __asm MOV DX, 0xD007 __asm OUT AL, DX
顯然,第一種方法與 C/C++ 的風(fēng)格很一致,并且把匯編代碼和 C/C++ 代碼清楚地分開(kāi),還避免了重復(fù)輸入 __asm 關(guān)鍵字,因此推薦使用第一種方法。
不像在 C/C++ 中的"{ }",__asm 塊的"{ }"不會(huì)影響 C/C++ 變量的作用范圍。同時(shí),__asm 塊可以嵌套,而且嵌套也不會(huì)影響變量的作用范圍。
為了與低版本的 Visual C++ 兼容,_asm 和 __asm 具有相同的意義。另外,Visual C++ 支持標(biāo)準(zhǔn) C++ 的 asm 關(guān)鍵字,但是它不會(huì)生成任何指令,它的作用僅限于使編譯器不會(huì)出現(xiàn)編譯錯(cuò)誤。要使用內(nèi)聯(lián)匯編,必須使用 __asm 而不是 asm 關(guān)鍵字。
三、 匯編語(yǔ)言
1. 指令集
內(nèi)聯(lián)匯編支持 Intel Pentium 4 和 AMD Athlon 的所有指令。更多其它處理器的指令可以通過(guò) _EMIT 偽指令來(lái)創(chuàng)建(_EMIT 偽指令說(shuō)明見(jiàn)下文)。
2. MASM 表達(dá)式
在內(nèi)聯(lián)匯編代碼中,可以使用所有的 MASM 表達(dá)式(MASM 表達(dá)式是指用來(lái)計(jì)算一個(gè)數(shù)值或一個(gè)地址的操作符和操作數(shù)的組合)。
3. 數(shù)據(jù)指示符和操作符
雖然 __asm 塊中允許使用 C/C++ 的數(shù)據(jù)類(lèi)型和對(duì)象,但它不能使用 MASM 指示符和操作符來(lái)定義數(shù)據(jù)對(duì)象。這里特別指出,__asm 塊中不允許 MASM 中的定義指示符(DB、DW、DD、DQ、DT 和 DF),也不允許使用 DUP 和 THIS 操作符。MASM 中的結(jié)構(gòu)和記錄也不再有效,內(nèi)聯(lián)匯編不接受 STRUC、RECORD、WIDTH 或者 MASK。
4. EVEN 和 ALIGN 指示符
盡管內(nèi)聯(lián)匯編不支持大多數(shù) MASM 指示符,但它支持 EVEN 和 ALIGN。當(dāng)需要的時(shí)候,這些指示符在匯編代碼里面加入 NOP 指令(空操作)使標(biāo)號(hào)對(duì)齊到特定邊界。這樣可以使某些處理器取指令時(shí)具有更高的效率。
5. MASM 宏指示符
內(nèi)聯(lián)匯編不是宏匯編,不能使用 MASM 宏指示符(MACRO、REPT、IRC、IRP 和 ENDM)和宏操作符(、!、、% 和 .TYPE)。
6. 段
必須使用寄存器而不是名稱(chēng)來(lái)指明段(段名稱(chēng)"_TEXT"是無(wú)效的)。并且,段跨越必須顯式地說(shuō)明,如 ES:[EBX]。
7. 類(lèi)型和變量大小
在內(nèi)聯(lián)匯編中,可以用 LENGTH、SIZE 和 TYPE 來(lái)獲取 C/C++ 變量和類(lèi)型的大大小。
* LENGTH 操作符用來(lái)取得 C/C++ 中數(shù)組的元素個(gè)數(shù)(如果不是一個(gè)數(shù)組,則結(jié)果為 1)。
* SIZE 操作符可以獲取 C/C++ 變量的大?。ㄒ粋€(gè)變量的大小是 LENGTH 和 TYPE 的乘積)。
* TYPE 操作符可以返回 C/C++ 類(lèi)型和變量的大?。ㄈ绻兞渴且粋€(gè)數(shù)組,它得到的是數(shù)組中單個(gè)元素的大小)。
例如,程序中定義了一個(gè) 8 維的整數(shù)型變量:
int iArray[8];
下面是 C 和匯編表達(dá)式中得到的 iArray 及其元素的相關(guān)值:
__asm C Size
LENGTH iArray sizeof(iArray)/sizeof(iArray[0]) 8
SIZE iArray sizeof(iArray) 32
TYPE iArray sizeof(iArray[0]) 4
8. 注釋
內(nèi)聯(lián)匯編中可以使用匯編語(yǔ)言的注釋?zhuān)?;"。例如:
__asm MOV EAX, OFFSET pbBuff ; Load address of pbBuff
因?yàn)?C/C++ 宏將會(huì)展開(kāi)到一個(gè)邏輯行中,為了避免在宏中使用匯編語(yǔ)言注釋帶來(lái)的混亂,內(nèi)聯(lián)匯編也允許使用 C/C++ 風(fēng)格的注釋。
9. _EMIT 偽指令
_EMIT 偽指令相當(dāng)于 MASM 中的 DB,但是 _EMIT 一次只能在當(dāng)前代碼段(.text 段)中定義一個(gè)字節(jié)。例如:
__asm
{
JMP _CodeLabel
_EMIT 0x00 ; 定義混合在代碼段的數(shù)據(jù)
_EMIT 0x01
_CodeLabel: ; 這里是代碼
_EMIT 0x90 ; NOP指令
}
10. 寄存器使用
一般來(lái)說(shuō),不能假定某個(gè)寄存器在 __asm 塊開(kāi)始的時(shí)候有已知的值。寄存器的值將不能保證會(huì)從 __asm 塊保留到另外一個(gè) __asm 塊中。
如果一個(gè)函數(shù)聲明為 __fastcall 調(diào)用方式,則其參數(shù)將通過(guò)寄存器而不是堆棧來(lái)傳遞。這將會(huì)使 __asm 塊產(chǎn)生問(wèn)題,因?yàn)楹瘮?shù)無(wú)法被告知哪個(gè)參數(shù)在哪個(gè)寄存器中。如果函數(shù)接收了 EAX 中的參數(shù)并立即儲(chǔ)存一個(gè)值到 EAX 中的話(huà),原來(lái)的參數(shù)將丟失掉。另外,在所有聲明為 __fastcall 的函數(shù)中,ECX 寄存器是必須一直保留的。為了避免以上的沖突,包含 __asm 塊的函數(shù)不要聲明為 __fastcall 調(diào)用方式。
提示:如果使用 EAX、EBX、ECX、EDX、ESI 和 EDI 寄存器,你不需要保存它。但如果你用到了 DS、SS、SP、BP 和標(biāo)志寄存器,那就應(yīng)該用 PUSH 保存這些寄存器。
提示:如果程序中改變了用于 STD 和 CLD 的方向標(biāo)志,必須將其恢復(fù)到原來(lái)的值。
四、 使用 C/C++ 元素
1. 可用的 C/C++ 元素
C/C++ 與匯編語(yǔ)言可以混合使用,在內(nèi)聯(lián)匯編中可以使用 C/C++ 變量以及很多其它的 C/C++ 元素,包括:
符號(hào),包括標(biāo)號(hào)、變量和函數(shù)名;
常量,包括符號(hào)常量和枚舉型成員;
宏定義和預(yù)處理指示符;
注釋?zhuān)?/**/"和"http://";
類(lèi)型名,包括所有 MASM 中合法的類(lèi)型;
typedef 名稱(chēng),通常使用 PTR 和 TYPE 操作符,或者使用指定的的結(jié)構(gòu)或枚舉成員。
在內(nèi)聯(lián)匯編中,可以使用 C/C++ 或匯編語(yǔ)言的基數(shù)計(jì)數(shù)法。例如,0x100 和 100H 是相等的。
2. 操作符使用
內(nèi)聯(lián)匯編中不能使用諸如""一類(lèi)的 C/C++ 操作符。但是,C/C++ 和 MASM 共有的操作符(比如"*"和"[]"操作符),都被認(rèn)為是匯編語(yǔ)言的操作符,是可以使用的。舉個(gè)例子:
int iArray[10];
__asm MOV iArray[6], BX ; Store BX at iArray + 6 (Not scaled)
iArray[6] = 0; // Store 0 at iArray+12 (Scaled)
提示:在內(nèi)聯(lián)匯編中,可以使用 TYPE 操作符使其與 C/C++ 一致。比如,下面兩條語(yǔ)句是一樣的:
__asm MOV iArray[6 * TYPE int], 0 ; Store 0 at iArray + 12
iArray[6] = 0; // Store 0 at iArray + 12
3. C/C++ 符號(hào)使用
在 __asm 塊中可以引用所有在作用范圍內(nèi)的 C/C++ 符號(hào),包括變量名稱(chēng)、函數(shù)名稱(chēng)和標(biāo)號(hào)。但是不能訪(fǎng)問(wèn) C++ 類(lèi)的成員函數(shù)。
下面是在內(nèi)聯(lián)匯編中使用 C/C++ 符號(hào)的一些限制:
每條匯編語(yǔ)句只能包含一個(gè) C/C++ 符號(hào)。在一條匯編指令中,多個(gè)符號(hào)只能出現(xiàn)在 LENGTH、TYPE 或 SIZE 表達(dá)式中。
在 __asm 塊中引用函數(shù)必須先聲明。否則,編譯器將不能區(qū)別 __asm 塊中的函數(shù)名和標(biāo)號(hào)。
在 __asm 塊中不能使用對(duì)于 MASM 來(lái)說(shuō)是保留字的 C/C++ 符號(hào)(不區(qū)分大小寫(xiě))。MASM 保留字包含指令名稱(chēng)(如 PUSH)和寄存器名稱(chēng)(如 ESI)等。
在 __asm 塊中不能識(shí)別結(jié)構(gòu)和聯(lián)合標(biāo)簽。
4. 訪(fǎng)問(wèn) C/C++ 中的數(shù)據(jù)
內(nèi)聯(lián)匯編的一個(gè)非常大的方便之處是它可以使用名稱(chēng)來(lái)引用 C/C++ 變量。例如,如果 C/C++ 變量 iVar 在作用范圍內(nèi):
__asm MOV EAX, iVar ; Stores the value of iVar in EAX
如果 C/C++ 中的類(lèi)、結(jié)構(gòu)或者枚舉成員具有唯一的名稱(chēng),則在 __asm 塊中可以只通過(guò)成員名稱(chēng)來(lái)訪(fǎng)問(wèn)(省略"."操作符之前的變量名或 typedef 名稱(chēng))。然而,如果成員不是唯一的,你必須在"."操作符之前加上變量名或 typedef 名稱(chēng)。例如,下面的兩個(gè)結(jié)構(gòu)都具有 SameName 這個(gè)成員變量:
struct FIRST_TYPE
{
char *pszWeasel;
int SameName;
};
struct SECOND_TYPE
{
int iWonton;
long SameName;
};
如果按下面方式聲明變量:
struct FIRST_TYPE ftTest;
struct SECOND_TYPE stTemp;
那么,所有引用 SameName 成員的地方都必須使用變量名,因?yàn)?SameName 不是唯一的。另外,由于上面的 pszWeasel 變量具有唯一的名稱(chēng),你可以?xún)H僅使用它的成員名稱(chēng)來(lái)引用它:
__asm
{
MOV EBX, OFFSET ftTest
MOV ECX, [EBX]ftTest.SameName ; 必須使用"ftTest"
MOV ESI, [EBX]. pszWeasel ; 可以省略"ftTest"
}
提示:省略變量名僅僅是為了書(shū)寫(xiě)代碼方便,生成的匯編指令還是一樣的。
5. 用內(nèi)聯(lián)匯編寫(xiě)函數(shù)
如果用內(nèi)聯(lián)匯編寫(xiě)函數(shù)的話(huà),要傳遞參數(shù)和返回一個(gè)值都是非常容易的??聪旅娴睦樱容^一下用獨(dú)立匯編和內(nèi)聯(lián)匯編寫(xiě)的函數(shù):
; PowerAsm.asm
; Compute the power of an integer
PUBLIC GetPowerAsm
_TEXT SEGMENT WORD PUBLIC 'CODE'
GetPowerAsm PROC
PUSH EBP ; Save EBP
MOV EBP, ESP ; Move ESP into EBP so we can refer
; to arguments on the stack
MOV EAX, [EBP+4] ; Get first argument
MOV ECX, [EBP+6] ; Get second argument
SHL EAX, CL ; EAX = EAX * (2 ^ CL)
POP EBP ; Restore EBP
RET ; Return with sum in EAX
GetPowerAsm ENDP
_TEXT ENDS
END
C/C++ 函數(shù)一般用堆棧來(lái)傳遞參數(shù),所以上面的函數(shù)中需要通過(guò)堆棧位置來(lái)訪(fǎng)問(wèn)它的參數(shù)(在 MASM 或其它一些匯編工具中,也允許通過(guò)名稱(chēng)來(lái)訪(fǎng)問(wèn)堆棧參數(shù)和局部堆棧變量)。
下面的程序是使用內(nèi)聯(lián)匯編寫(xiě)的:
// PowerC.c
#include
int GetPowerC(int iNum, int iPower);
int main()
{
printf("3 times 2 to the power of 5 is %d\n", GetPowerC( 3, 5));
}
int GetPowerC(int iNum, int iPower)
{
__asm
{
MOV EAX, iNum ; Get first argument
MOV ECX, iPower ; Get second argument
SHL EAX, CL ; EAX = EAX * (2 to the power of CL)
}
// Return with result in EAX
}
使用內(nèi)聯(lián)匯編寫(xiě)的 GetPowerC 函數(shù)可以通過(guò)參數(shù)名稱(chēng)來(lái)引用它的參數(shù)。由于 GetPowerC 函數(shù)沒(méi)有執(zhí)行 C 的 return 語(yǔ)句,所以編譯器會(huì)給出一個(gè)警告信息,我們可以通過(guò) #pragma warning 禁止生成這個(gè)警告。
內(nèi)聯(lián)匯編的其中一個(gè)用途是編寫(xiě) naked 函數(shù)的初始化和結(jié)束代碼。對(duì)于一般的函數(shù),編譯器會(huì)自動(dòng)幫我們生成函數(shù)的初始化(構(gòu)建參數(shù)指針和分配局部變量等)和結(jié)束代碼(平衡堆棧和返回一個(gè)值等)。使用內(nèi)聯(lián)匯編,我們可以自己編寫(xiě)干干凈凈的函數(shù)。當(dāng)然,此時(shí)我們必須自己動(dòng)手做一些有關(guān)函數(shù)初始化和掃尾的工作。例如:
void __declspec(naked) MyNakedFunction()
{
// Naked functions must provide their own prolog.
__asm
{
PUSH EBP
MOV ESP, EBP
SUB ESP, __LOCAL_SIZE
}
.
.
.
// And we must provide epilog.
__asm
{
POP EBP
RET
}
}
6. 調(diào)用 C/C++ 函數(shù)
內(nèi)聯(lián)匯編中調(diào)用聲明為 __cdecl 方式(默認(rèn))的 C/C++ 函數(shù)必須由調(diào)用者清除參數(shù)堆棧,下面是一個(gè)調(diào)用 C/C++ 函數(shù)例子:
#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
// 壓入了 3 個(gè)參數(shù)在堆棧中,調(diào)用函數(shù)之后要調(diào)整堆棧
ADD ESP, 12
}
}
提示:參數(shù)是按從右往左的順序壓入堆棧的。
如果調(diào)用 __stdcall 方式的函數(shù),則不需要自己清除堆棧。因?yàn)檫@種函數(shù)的返回指令是 RET n,會(huì)自動(dòng)清除堆棧。大多數(shù) Windows API 函數(shù)均為 __stdcall 調(diào)用方式(僅除 wsprintf 等幾個(gè)之外),下面是一個(gè)調(diào)用 MessageBox 函數(shù)的例子:
#include
TCHAR g_tszAppName[] = TEXT("API Test");
void main()
{
TCHAR tszHello[] = TEXT("Hello, world!");
__asm
{
PUSH MB_OK OR MB_ICONINFORMATION
PUSH OFFSET g_tszAppName ; 全局變量用 OFFSET
LEA EAX, tszHello ; 局部變量用 LEA
PUSH EAX
PUSH 0
CALL DWORD PTR [MessageBox] ; 注意這里不是 CALL MessageBox,而是調(diào)用重定位過(guò)的函數(shù)地址
}
}
提示:可以不受限制地訪(fǎng)問(wèn) C++ 成員變量,但是不能訪(fǎng)問(wèn) C++ 的成員函數(shù)。
7. 定義 __asm 塊為 C/C++ 宏
使用 C/C++ 宏可以方便地把匯編代碼插入到源代碼中。但是這其中需要額外地注意,因?yàn)楹陮?huì)擴(kuò)展到一個(gè)邏輯行中。
為了不會(huì)出現(xiàn)問(wèn)題,請(qǐng)按以下規(guī)則編寫(xiě)宏:
使用花括號(hào)把 __asm 塊包圍?。?/p>
把 __asm 關(guān)鍵字放在每條匯編指令之前;
使用經(jīng)典 C 風(fēng)格的注釋?zhuān)?/* comment */"),不要使用匯編風(fēng)格的注釋?zhuān)?; comment")或單行的 C/C++ 注釋?zhuān)?http:// comment");
舉個(gè)例子,下面定義了一個(gè)簡(jiǎn)單的宏:
#define PORTIO __asm \
/* Port output */ \
{ \
__asm MOV AL, 2 \
__asm MOV DX, 0xD007 \
__asm OUT DX, AL \
}
乍一看來(lái),后面的三個(gè) __asm 關(guān)鍵字好像是多余的。其實(shí)它們是需要的,因?yàn)楹陮⒈粩U(kuò)展到一個(gè)單行中:
__asm /* Port output */ { __asm MOV AL, 2 __asm MOV DX, 0xD007 __asm OUT DX, AL }
從擴(kuò)展后的代碼中可以看出,第三個(gè)和第四個(gè) __asm 關(guān)鍵字是必須的(作為語(yǔ)句分隔符)。在 __asm 塊中,只有 __asm 關(guān)鍵字和換行符會(huì)被認(rèn)為是語(yǔ)句分隔符,又因?yàn)槎x為宏的一個(gè)語(yǔ)句塊會(huì)被認(rèn)為是一個(gè)邏輯行,所以必須在每條指令之前使用 __asm 關(guān)鍵字。
括號(hào)也是需要的,如果省略了它,編譯器將不知道匯編代碼在哪里結(jié)束,__asm 塊后面的 C/C++ 語(yǔ)句看起來(lái)會(huì)被認(rèn)為是匯編指令。
同樣是由于宏展開(kāi)的原因,匯編風(fēng)格的注釋?zhuān)?; comment")和單行的 C/C++ 注釋?zhuān)?http:// commen")也可能會(huì)出現(xiàn)錯(cuò)誤。為了避免這些錯(cuò)誤,在定義 __asm 塊為宏時(shí)請(qǐng)使用經(jīng)典 C 風(fēng)格的注釋?zhuān)?/* comment */")。
和 C/C++ 宏一樣 __asm 塊寫(xiě)的宏也可以擁有參數(shù)。和 C/C++ 宏不一樣的是,__asm 宏不能返回一個(gè)值,因此,不能使用這種宏作為 C/C++ 表達(dá)式。
不要不加選擇地調(diào)用這種類(lèi)型的宏。比如,在聲明為 __fastcall 的函數(shù)中調(diào)用匯編語(yǔ)言宏可能會(huì)導(dǎo)致不可預(yù)料的結(jié)果(請(qǐng)參看前文的說(shuō)明)。
8. 轉(zhuǎn)跳
可以在 C/C++ 里面使用 goto 轉(zhuǎn)跳到 __asm 塊中的標(biāo)號(hào)處,也可以在 __asm 塊中轉(zhuǎn)跳到 __asm 塊里面或外面的標(biāo)號(hào)處。__asm 塊內(nèi)的標(biāo)號(hào)是不區(qū)分大小寫(xiě)的(指令、指示符等也是不區(qū)分大小寫(xiě)的)。例如:
void MyFunction()
{
goto C_Dest; /* 正確 */
goto c_dest; /* 錯(cuò)誤 */
goto A_Dest; /* 正確 */
goto a_dest; /* 正確 */
__asm
{
JMP C_Dest ; 正確
JMP c_dest ; 錯(cuò)誤
JMP A_Dest ; 正確
JMP a_dest ; 正確
a_dest: ; __asm 標(biāo)號(hào)
}
C_Dest: /* C/C++ 標(biāo)號(hào) */
return;
}
不要使用函數(shù)名稱(chēng)當(dāng)作標(biāo)號(hào),否則將轉(zhuǎn)跳到函數(shù)中執(zhí)行,而不是標(biāo)號(hào)處。例如,由于 exit 是 C/C++ 的函數(shù),下面的轉(zhuǎn)跳將不會(huì)到 exit 標(biāo)號(hào)處:
; 錯(cuò)誤:使用函數(shù)名作為標(biāo)號(hào)
JNE exit
.
.
.
exit:
.
.
.
美元符號(hào)"$"用于指定當(dāng)前指令位置,常用于條件跳轉(zhuǎn)中,例如:
JNE $+5 ; 下面這條指令的長(zhǎng)度是 5 個(gè)字節(jié)
JMP _Label
NOP ; $+5,轉(zhuǎn)跳到了這里
.
.
.
_Label:
.
.
.
五、在 Visual C++ 工程中使用獨(dú)立匯編
內(nèi)聯(lián)匯編代碼不易于移植,如果你的程序打算在不同類(lèi)型的機(jī)器(比如 x86 和 Alpha)上運(yùn)行,你可能需要在不同的模塊中使用特定的機(jī)器代碼。這時(shí)候你可以使用 MASM(Microsoft Macro Assembler),因?yàn)?MASM 支持更多方便的宏指令和數(shù)據(jù)指示符。
這里簡(jiǎn)單介紹一下在 Visual Studio .NET 2003 中調(diào)用 MASM 編譯獨(dú)立匯編文件的步驟。
在 Visual C++ 工程中,添加按 MASM 的要求編寫(xiě)的 .asm 文件。在解決方案資源管理器中,右擊這個(gè)文件,選擇"屬性"菜單項(xiàng),在屬性對(duì)話(huà)框中,點(diǎn)擊"自定義生成步驟",設(shè)置如下項(xiàng)目:
命令行:ML.exe /nologo /c /coff "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)"
輸出:$(IntDir)\$(InputName).obj
如果要生成調(diào)試信息,可以在命令行中加入"/Zi"參數(shù),還可以根據(jù)需要生成 .lst 和 .sbr 文件。
如果要在匯編文件中調(diào)用 Windows API,可以從網(wǎng)上下載 MASM32 包(包含了 MASM 匯編工具、非常完整的 Windows API 頭文件/庫(kù)文件、實(shí)用宏以及大量的 Win32 匯編例子等)。相應(yīng)地,應(yīng)該在命令行中加入"/I X:\MASM32\INCLUDE"參數(shù)指定 Windows API 匯編頭文件(.inc)的路徑。MASM32 的主頁(yè)是:,里面可以下載最新版本的 MASM32 包。
網(wǎng)頁(yè)標(biāo)題:c語(yǔ)言嵌入?yún)R編除法函數(shù) c語(yǔ)言中嵌入?yún)R編指令
當(dāng)前網(wǎng)址:http://muchs.cn/article38/ddcsisp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、手機(jī)網(wǎng)站建設(shè)、做網(wǎng)站、搜索引擎優(yōu)化、網(wǎng)站內(nèi)鏈、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容