美文网首页
内联汇编

内联汇编

作者: 骑猪满天飞 | 来源:发表于2021-02-25 17:33 被阅读0次

    AT&T汇编语法

    GCC只支持AT&T汇编语法内嵌在C语言中。

    Intel和AT&T汇编风格对比:

    compare.png

    AT&T寻址

    寄存器间接寻址:

    • mov (%eax), %ebx ;表示将地址eax所指的内存复制4字节到ebx

    寄存器相对寻址:

    • movb -4(%eax), %al; 表示将地址(eax - 4)所指的内存复制一字节到al

    变址寻址:

    segreg(段基址):base_address(offset_address,index,size)
    对应表达式为:
    segreg(段基址):base_address + offset_address + index * size
    

    格式中不存在的部分要用‘,’占位,共有4种组合:

    • 无base_address,无offset_address

      movl %eax, (,%esi,2) -- 表示将eax的值写入esi*2所指的内存

    • 无base_address,有offset_address

      movl %eax,(%ebx,%esi,2) -- 表示将eax的值写入ebx + esi*2所指的内存

    • 有base_address,无offset_address

      movl %eax, base_value(,%esi,2) -- 表示将eax的值写入base_value + esi*2`所指的内存

    • 有base_address,有offset_address

      movl %eax, base_value(%ebx,%esi,2) -- 表示将eax的值写入base_value + %ebx + esi*2`所指的内存

    基本内联汇编

    内联汇编基本格式:

      asm [volatile] ("assembly code")  
      volatile关键字可选,使得gcc在-O指定优化时,不改变汇编代码
    

    assembly code规则:

    1. 指令必须在双引号内。
    2. 指令之间用分号、换行符\n或者换行符加制表符\n\t分隔

    示例:

    char* str = "hello,world\n";
    int count = 0;
    void main(){
        asm volatile ("\
            pusha; \
            movl $4, %eax; \
            movl $1, %ebx; \
            movl str, %ecx; \
            movl $12, %edx; \
            int $0x80; \
            movl %eax, count; \
            popa \
        ");
    }
    

    扩展内联汇编

    当汇编代码嵌入到C代码中,如何找到可用的寄存器是个问题,程序员不知道哪些寄存器已经被分配。GCC提供了扩展内联汇编格式。

    扩展内联汇编格式:

    asm [volatile] ("assembly code" : output : input : clobber/modify)

    1. output : <output> 用来指定汇编代码的数据如何传递给C代码使用,output中每个操作数的格式为:

    "操作数修饰符 + 约束名"(C变量名)

    引号和圆括号不可少,操作数修饰符通常为‘=’。多个操作数之间用‘,’分隔

    1. input : <input> 用来指定C中数据如何传递给汇编使用,input中每个操作数的格式为:

    ”[操作数修饰符] + 约束名“(C变量名)

    引号和圆括号不可少,操作数修饰符为可选项。多个操作数之间用‘,’分隔

    1. clobber/modify : 汇编代码执行后会破坏一些内存或寄存器资源,通过此项通知编译器,哪些寄存器或内存需要提前保护起来。

    2. 约束名

      寄存器约束

      寄存器约束就是要求gcc使用哪个寄存器

      a: eax/ax/al
      b: ebx/bx/bl
      c: ecx/cx/cl
      d: edx/dx/dl
      D: edi/di
      S: esi/si
      q: eax/ebx/ecx/edx中任意一个
      r: eax/ebx/ecx/edx/esi/edi中任意一个
      g: 表示存放到任意地点(寄存器和内存)
      A:把eax和edx组合成64位整数
      f: 表示浮点寄存器
      t: 表示第1个浮点寄存器
      u: 表示第2个浮点寄存器
      

      示例:

     #include <stdio.h>
     void main(){
         int in_a = 1, in_b = 2, out_sum;
         asm ("addl %%ebx, %%eax":"=a"(out_sum):"a"(in_a),"b"(in_b));
         printf("sum = %d\n",out_sum);
      }
    
    

    ps: 扩展内联汇编中寄存器前缀是两个%

    内存约束

    m: 表示操作数可以使用任意一种内存形式
    o: 操作数位内存变量
    

    示例 :

    #include <stdio.h>
    
    void main(){
        int in_a = 1, in_b = 2;
        asm ("movb %b0, %1"::"a"(in_a),"m"(in_b));
        printf("in_b = %d\n",in_b);
    }
    

    %1序号占位符,代表in_b的内存地址(指针)

    %b0表示对寄存器eax的引用,b表示一个字节,所以%b0表示al寄存器

    立即数约束

    只放在input中

    i: 整数立即数
    F: 浮点数立即数
    I: 0-31之间的立即数
    J: 0-63之间的立即数
    N: 0-255之间的立即数
    O: 0-32之间的立即数
    X: 任何类型的立即数
    

    通用约束

    0-9: 只用在input部分,表示与output和input中第n个操作数用相同的寄存器或内存
    
    1. 占位符

      为方便对操作数的引用,扩展内联汇编提供了占位符来表示指定操作数。

      序号占位符

      序号占位符是对在output和input中的操作数,按照他们从左到右出现的次序从0开始编号,一直到9,最多支持10个序号占位符。引用它的格式是%0-9

      若%0表示eax,则%h0 -- 表示ah,%b0表示al

      名称占位符

      可以对操作数进行显示命名,格式如下:

      [名称]”约束名“(c变量)
      采用%[名称]的形式引用操作数

      示例:

      #include <stdio.h>
      
      void main(){
          int in_a = 18, in_b = 3, out = 0;
          asm ("divb %[divisor]; movb %b1, %[result]":[result]"=m"(out):"a"(in_a),[divisor]"m"(in_b));
          printf("out = %d\n",out);
      }
      
    2. 操作数修饰符

      在output中:

      =: 表示操作数只写
      +: 表示操作数可读写
      &: 表示此output中的操作数要独占约束(分配的)寄存器,只供output使用,任何input中分配的寄存器不能与此相同
      

      input中:

      %: 该操作数可以和下一个输入操作数交换
      

      一般情况下input中的C变量是只读的,output中的C变量是只写的。

      示例:

      #include <stdio.h>
      
      void main(){
          int in_a = 1, in_b = 2;
          asm ("addl %%ebx, %%eax":"+a"(in_a):"b"(in_b));
          printf("sum = %d\n",in_a);
      }
      

      参考

    《操作系统真相还原》

    相关文章

      网友评论

          本文标题:内联汇编

          本文链接:https://www.haomeiwen.com/subject/dwuufltx.html