美文网首页
内联汇编

内联汇编

作者: 骑猪满天飞 | 来源:发表于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);
    }
    

    参考

《操作系统真相还原》

相关文章

  • 汇编语言如何与高级语言混编

    汇编混编的两种方式(内联汇编 和 外链汇编) 内联汇编 asm();这是内联汇编,编译器可以直接运行asm ( 汇...

  • 内联汇编

    lodsb: ds:[esi] -> al stosb: al -> es:[edi] SCASB: 比较 [ed...

  • 内联汇编

    AT&T汇编语法 GCC只支持AT&T汇编语法内嵌在C语言中。 Intel和AT&T汇编风格对比: AT&T寻址 ...

  • 内联汇编

    内联汇编是指在 C/C++ 代码中嵌入的汇编代码,与全部是汇编的汇编源文件不同,它们被嵌入到 C/C++ 的大环境...

  • C编程使用内联汇编控制PC蜂鸣器发声

    有了《初识Linux汇编》和《内联汇编控制PC蜂鸣器》两篇文章的基础了解后,我们使用内联汇编来改造《C编程控制PC...

  • CAS与内存屏障: 内联汇编的实际应用场景_(S2实现CAS)

    c++的CAS与内存屏障: 从c/c++的内联汇编说起(S3) 现在讨论下内联汇编与CAS lock-free是什...

  • DPDK gcc内联汇编

    在DPDK中,使用gcc的内联汇编实现高效率的函数,比如自旋锁,cas操作等。今天简单介绍一下gcc内联汇编语法和...

  • gcc内联汇编

    文章来自这里:gcc内联汇编...... 在阅读Linux内核源码或对代码做性能优化时,经常会有在C语言中嵌入一段...

  • 11 内联汇编

    11.1 汇编概述 尽管智能合约的大部分业务需求我们都能通过solidity提供的功能和模块完成,但一些特殊的功能...

  • Visual Studio 不支持x64 vc中内联汇编的原因

    Visual Studio目前只支持32位(x86)的内联汇编,而不支持64位(x64)下的内联汇编,在x64下编...

网友评论

      本文标题:内联汇编

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