目的:学习在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中的函数:
下面是一个例子:
#i nclude
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块中的代码.