VC内联ASM汇编学习笔记

转载: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块中的代码.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章