首先来学习一下C函数和汇编函数之间的调用关系吧。

      在什么情况下才用到这种调用呢:


  就是C语言的库函数中不存在的功能,例如

读写I/O; 
 
   获取CPU寄存器的相关信息.如CR0,DR0,MTRR,... 
 
      一些特殊的指令:CPUID(获取CPU的基本信息),invbin(disable缓存)... 
 
  一般大家都知道,在C语言中可以嵌套汇编,一般如下格式: 
 
      void example() 
 
      {    ... 
 
          _ASM{ 
 
          push ax 
 
          push bx 
 
            ...... 
 
          pop   bx 
 
          pop   ax 
 
          } 
 
            ... 
 
      } 
 
 或者是形如: 
 
   void example(){ 
 
        asm push ax 
 
        asm push bx 
 
        ... 
 
        asm pop  bx 
 
        asm pop  ax 
 
      } 
 
      这些都是很常用的,下面我要介绍的是C中直接和汇编函数的调用。 
 
      这里因为32位(IA32)和64位(X64)是有差别的,所以将他们对比来分析。 
 
  可能很多人对64位的比较陌生,这里我把32位和64位CPU的寄存器列举一下,大家自己可以做一下对比: 
 
      
 
32位: 
 
  
 
EAX

EBX

ECX

EDX

ESP

EBP

ESI

EDI

EFLAG

CS

ES

DS

GS

ES


 
64位: 
 
  
 
RAX

RBX

RCX

RDX

RSP

RBP

RSI

RDI

R8

R9

R10

R11

R12

R13

R14

R15

RFLAG

CS

DS

ES

FS

GS


 

     首先来看C和汇编之间的接口: 
 
   
 32位(IA32): 
 
      @ 所有C函数的参数都按照从后到前的顺序被压到堆栈(Stack)中 
 
      例如: void example(int a,int b,intc){...} 
 
      压栈的顺序是:先将c压入堆栈,然后是b,最后是a. 
 
      @ 汇编函数从堆栈中获取这些参数。 
 
      @   汇编函数将结果通过EAX,EDX寄存器返回给C 
 
      
  64位(X64): 
 
      @ C函数中的前4个参数是通过RCX,RDX,R8,R9寄存器来传递的,如果参数的个数超过4个,则后面的参数按照IA32一样的顺序来压入堆栈,实现参数的传递。 
 
  @ 汇编函数通过RCX,RDX,R8,R9和堆栈来获取参数。 
 
      @ 汇编函数将结果通过RAX,RDX寄存器返回给C 
 
好了,下面举个I/O读写的例子吧: 
 
   
 32位(IA32):
C文件: 
 
      extern void IOWrite(int Port,int Data); 
 
      extern void IORead(int Port); 
 
      void main() 
 
      {    int pData; 
 
            IOWrite(0x80,0xAA);     //  向80h port写 AAh   
 
            pData=IORead(0x64);            //读64h port的数据  
 
            printf("%d\n",pData);       //显示从64h端口读取的数据 
 
      }  
 
 ASM文件: 
 
  .Model small,c 
 
      .586p 
 
      .data 
 
      .stack 
 
      .code  
 
IOWrite proc near public 
 
       mov dx,[ESP+04]; 获取port   
 
       mov al,[ESP+8]    ;获取data 
 
       out dx,al             ;数据(data)输出到端口(port) 
 
       ret                     ;返回 
 
IOWrite endp      
 
IORead proc near public 
 
       mov dx,[ESP+04]; 获取port   
 
       in al,dx               ;获取port的data 
 
       ret                     ;返回 
 
IOWrite endp      
 
       end 
 
 下面的表格就是参数的压栈情况:   
 

 

 
Data
ESP+8

Port
ESP+4

EIP

ESP


 

 
  
 64位(x64): 
 
C文件: 
 
      extern void IOWrite(int Port,int Data); 
 
      extern void IORead(int Port); 
 
      void main() 
 
      {    int pData; 
 
            IOWrite(0x80,0xAA);     //  向80h port写 AAh   
 
            pData=IORead(0x64);            //读64h port的数据  
 
            printf("%d\n",pData);       //显示从64h端口读取的数据 
 
      }  
 
 ASM文件: 
 
  .Model small,c 
 
      .586p 
 
      .data 
 
      .stack 
 
      .code  
 
IOWrite proc near public 
 
       mov al,dl; 获取data  
 
       mov dx,cx    ;获取port 
 
       out dx,al             ;数据(data)输出到端口(port) 
 
       ret                     ;返回 
 
IOWrite endp      
 
IORead proc near public 
 
       mov dx,cx; 获取port   
 
       in al,dx               ;获取port的data 
 
       ret                     ;返回 
 
IOWrite endp      
 
       end


我们可以自己比较一下差别,就能更深刻得了解如何实现对汇编函数的调用,以及32位和64位的差别。这是最基本的一些应用而已。感觉要把自己知道的东西写出来,需要照顾到很多东西,不是一件简单的事,写博客很费时间啊,不过对自己系统的掌握知识很是很有帮助的,哈哈,继续努力!Fighting!!