C指针原理教程之C内嵌汇编分享!

内联汇编的重要性体现在它能够灵活操作,而且可以使其输出通过 C 变量显示出来。因为它具有这种能力,所以 “asm” 可以用作汇编指令和包含它的 C 程序之间的接口。简单得说,内联汇编,就是可以让程序员在C语言中直接嵌入汇编代码,并与汇编代码交互C程序中的C表达式,享受汇编的高运行效率。

内联汇编的格式是直接在C代码中插入以下格式:

  asm(  ....  ....  )  

其中的”…”为汇编代码,比如下面例子中,在 result=a*b和printf(“%dn”,result)之间插入一段汇编,

     下面的这段汇编什么都不做,每个nop指令占用一个指令的执行时间

   result=a*b;   asm("nopnt"   "nopnt"   "nopnt"   "nop");//4个nop指令,nt表示换行,然后加上TAB行首空,因为每个汇编指令必须在单独一行,需要换行,加上制表符是为了适应某些编译器的要求。    printf("%dn",result);  

可以很明显地看到:

    汇编代码之间用“nt”间隔,并且每条汇编代码单独占用一行,共有4个nop指令,每个指令后的“nt”表示换行,然后加上TAB行首空,因为每个汇编指令必须在单独一行,需要换行,加上制表符是为了适应某些编译器的要求。

 下面是一个完整的例子,内嵌的汇编完成对2个C程序定义的全局变量c和d的相加,并将相加结果存入全局变量addresult中:

  #include <stdio.h>  int c=10;  int d=20;  int addresult;  int main(void){   int a=6;   int b=2;   int result;   result=a*b;   asm("nopnt"   "nopnt"   "nopnt"   "nop");//4个nop指令,nt表示换行,然后加上TAB行首空,因为每个汇编指令必须在单独一行,需要换行,加上制表符是为了适应某些编译器的要求。    printf("%dn",result);   asm("pushant"   "movl c,%eaxnt"   "movl d,%ebxnt"   "add %ebx,%eaxnt"   "movl %eax, addresultnt"   "popa");//使用全局C变量c和d    printf("%dn",addresult);    return 0;  }  

编译上述代码

  $ gcc -o test test.c  $ ./test  12  30  

在汇编代码中可以直接使用变量名称操作C程序定义的全局变量,比如c、d和addresult就是全局变量:

   "movl c,%eaxnt"   "movl d,%ebxnt"   "movl %eax, addresultnt"    

   内联汇编部分如果不需要编译器优化( 优化可能破坏汇编代码的内部结构,因为汇编代码直接操作寄存器,而寄存器使用优化是编译器提供的功能), 可以在 “asm” 后使用关键字 “volatile”。

  asm volatile(  ....  ....  )  

如果程序必须与 ANSI C 兼容,则应该使用 asm 和 volatile。

   __asm__ __volatile__(   .........   .........   )  

    下面的代码和刚才代码功能一样,唯一的区别是不需要优化

   #include <stdio.h>  int c=10;  int d=20;  int addresult;  int main(void){   int a=6;   int b=2;   int result;   result=a*b;   //ansi c标准的asm有其它用,所以用__asm__,__volatile__表示内联汇编部分不用优化(可以用volatile,但是ansi c不行),以防优化破坏内联代码组织结构   __asm__ __volatile__("nopnt"   "nopnt"   "nopnt"   "nop");//4个nop指令,nt表示换行,然后加上TAB行首空,因为每个汇编指令必须在单独一行,需要换行,加上制表符是为了适应某些编译器的要求。    printf("%dn",result);   __asm__ __volatile__("pushant"   "movl c,%eaxnt"   "movl d,%ebxnt"   "add %ebx,%eaxnt"   "movl %eax, addresultnt"   "popa");//使用全局C变量c和d    printf("%dn",addresult);    return 0;  }  

如何在内联汇编中访问C程序的局部变量呢,请看下面这段代码。

  #include <stdio.h>  int main(void){    //不使用全局变量,必须使用扩展GNU的asm    //格式为:asm("汇编代码":输出位置:输入位置:改动的寄存器列表)    //a为eax,ax,al;b为ebx等;c为ecx等;d为edx等;S为esi或si;D为edi或di    //+读和写;=写;%如果必要,操作数可以和下一个操作数切换;&在内联函数完成之前,可以删除或重新使用操作数    int xa=6;    int xb=2;    int result;    //ansi c标准的asm有其它用,所以用__asm__,__volatile__表示内联汇编部分不用优化(可以用volatile,但是ansi c不行),以防优化破坏内联代码组织结构    asm volatile(    "add %%ebx,%%eaxnt"    "movl $2,%%ecxnt"    "mul %%ecxnt"      "movl %%eax,%%edx"     :"=d"(result):"a"(xa),"b"(xb):"%ecx");//注意扩展方式使用2个%表示      printf("%dn",result);    return 0;  }  

这个例子完成这个计算:(xa+xb)2=(6+2)2=16

     不使用全局变量与汇编代码交互,我们必须使用扩展GNU的asm ,格式为:

      asm(“汇编代码”:输出位置:输入位置:改动的寄存器列表)  

       汇编代码中涉及寄存器部分的使用2个“%”,如:使用%%eax表示eax寄存器

       输出位置、输入位置的特殊命名规则为:

      a为eax,ax,al;b为ebx等;c为ecx等;d为edx等;S为esi或si;D为edi或di  

      +读和写

      =写

      %如果必要,操作数可以和下一个操作数切换

      &在内联函数完成之前,可以删除或重新使用操作数

    上述代码中,汇编代码部分为

    输出位置、输入位置、改动的寄存器列表部分为:
     :”=d”(result):”a”(xa),”b”(xb):”%ecx”

     先来看汇编代码部分,使用双%号表示寄存器,比如:

     “add %%ebx,%%eaxnt”

      关于输出位置、输入位置部分,可以这么理解:将变量与寄存器绑定,绑定后,对寄存器的操作就是对变量的操作。

       :”=d”(result):”a”(xa),”b”(xb)

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/482731.html

(0)
上一篇 2020年11月9日
下一篇 2020年11月9日

精彩推荐