轉載:http://old.blog.edu.cn/user2/44558/archives/2006/1209858.shtml
VC內聯ASM彙編學習筆記
目的:學習在VC中進行ASM彙編語言程序設計的方法,以提高底層應用能力.
由於在VC中進行彙編不需要額外的編譯器和聯接器,且可以處理VC中不能處理的一些事情,而且可以使用在C中的變量,所以,非常方便.但是它並不支持所有的MASM宏和數據指示符.
下面的三種方法基本上都可以使用在VC中:
__asm
{
mov al, 2
mov dx, 0xD007
out al, dx
}
__asm mov al, 2
__asm mov dx, 0xD007
__asm out al, dx
__asm mov al, 2 __asm mov dx, 0xD007 __asm out al, dx
顯然,最好的是第一種.
_emit相當於MASM中的DB.
雖然內聯彙編可以使用C/C++中的變量,但是它不能夠自己定義變量.
可以使用EVEN和ALIGN.
不能夠使用MASM宏.
必須使用寄存器來說明段,跨越段必須顯式地說明,如ES:[BX].
在內聯彙編中的類型和變量大小:
我們可以使用LENGTH來取得C/C++中的數組中的元素個數,如果不是一個數組,則結果爲一.使用SIZE來取得C/C++中變量的大小,一個變量的大小是LENGTH和TYPE的乘積.TYPE用來取得一個變量的大小,如果是一個數組,它得到的一個數組中的單個元素的大小.
VC中允許使用MMX指令.
內聯的ASM代碼並不易於移植,所以,應當儘量避免.
在__asm塊中可以使用的元素:
1.符號包括函數名
2.常數和enum類型
3.宏和預處理成員
4.註釋
5.MASM中的類型名
6.typedef,PTR,TYPE
寄存器:
一般來說,在__asm塊開始的時候,寄存器是空的.不能在兩個__asm之間保存寄存器的值.
如果一個函數被聲明成了__fastcall,則其參數將放在寄存器中,這將給寄存器的管理帶來問題.所以,如果要將一個函數聲明成__fastcall,必須保存ECX寄存器.爲了避免以上的衝突,在聲明爲__fastcall的函數中不要有__asm塊.如果用了/Gr編譯選項(它全局的變成__fastcall),將每個函數聲明成__cdecl或者__stdcall,這個屬性告訴編譯器用傳統的C方法.
不用保存EAX, EBX, ECX, EDX, ESI, or EDI寄存器.但卻需要保存DS, SS, SP, BP, and標誌寄存器.
如果程序中改變了用於STD和CLD的方向標誌,你必須將其恢復到原來的值.
跳轉:
可以使用goto和ASM指定跳到label或__asm以外的程序段中去.例:
void func( void )
{
goto C_Dest; /* Legal: correct case */
goto c_dest; /* Error: incorrect case */
goto A_Dest; /* Legal: correct case */
goto a_dest; /* Legal: incorrect case */
__asm
{
jmp C_Dest ; Legal: correct case
jmp c_dest ; Legal: incorrect case
jmp A_Dest ; Legal: correct case
jmp a_dest ; Legal: incorrect case
a_dest: ; __asm label
}
C_Dest: /* C label */
return;
}
不要使用函數名稱當作label,否則將使其跳到函數執行而不是label處.如下所示:
; BAD TECHNIQUE: using library function name as label
jne exit
.
.
.
exit:
; More __asm code follows
美元符號$用於指定當前位置,如下所用,常用於條件跳轉:
jne $+5 ; next instruction is 5 bytes long
jmp farlabel
; $+5
.
.
.
farlabel:
調用C中的函數:
下面是一個例子:
#include
char format[] = "%s %s/n";
char hello[] = "Hello";
char world[] = "world";
void main( void )
{
__asm
{
mov eax, offset world
push eax
mov eax, offset hello
push eax
mov eax, offset format
push eax
call printf
//clean up the stack so that main can exit cleanly
//use the unused register ebx to do the cleanup
pop ebx
pop ebx
pop ebx
}
}
注意:函數參數是從右向左壓棧.
不能夠訪問C++中的類成員函數.可以訪問extern "C"函數.
VC不會優化__asm塊中的代碼.