C中汇编函数的调用(Function call to Assembly)


  首先来学习一下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!!




posted @ 2009-08-31 11:22  china_blue  阅读(2956)  评论(0编辑  收藏  举报