jason--liu/Blog

aarch64体系结构与编程4--GCC内嵌汇编

jason--liu opened this issue · 0 comments

GCC内嵌汇编

  • 内嵌汇编(Inline Assembly Language):在C语言中嵌入汇编代码
  • 目的:
    • 优化:对于特定重要代码(time-sensitive)进行优化
    • C语言需要访问某些特殊指令来实现特殊功能比如 内存屏障指令

内嵌汇编两种模式

  • 基础内嵌汇编(Base Asm):不带参数
  • 扩展的内嵌汇编(Extended Asm):C语言变量参数

基础内嵌汇编

asm asm-qualifiers ( AssemblerInstructions )
格式:

  • asm关键字:表明这是一个GNU扩展
  • 修饰词(qualifiers)
  • volatile:在基础内嵌汇编中通常不需要这个修饰词
  • inline:内联,asm汇编的代码会尽可能小
    汇编代码块:
  • GCC编译器把内嵌汇编当成一个字符串
  • GCC编译器不会去解析和分析内嵌汇编。
  • 多条汇编指令,需要使用“\n\t”来换行
  • GCC的优化器,可以移动汇编指令的前后位置。如果你需要保存汇编指令的顺序,最好使用多个内嵌汇编的方式。

扩展内联汇编

image
格式:

  • asm关键字:表明这是一个GNU扩展
  • 修饰词(qualifiers)
    • volatile:用来关闭GCC优化
    • inline:内联,asm汇编的代码会尽可能小
    • goto:在内嵌汇编里会跳转到C语言的标签里
  • 输出部:用于描述在指令部中可以被修改的C语言变量以及约束条件
    image
  • 输出部:用于描述在指令部中可以被修改的C语言变量以及约束条件
    • 每个输出约束(constraint)通常以“=”号开头,接着的字母表示对操作数类型的说明,然后是关于变量结合的约束。
      “=/+” + 约束修饰符 + 变量
    • 输出部通常使用“=”或者“+”作为输出约束,其中“=”表示被修饰的操作数只具有可写属性,“+” 表示被修饰的操作数只具有可读可写属性。
    • 输出部可以是空的
  • 输入部:用来描述在指令部只能被读取访问的C语言变量以及约束条件
    • 输入部描述的参数是只有只读属性,不要试图去修改输入部的参数的内容,因为GCC编译器假定,输入部的参数的内容在内嵌汇编之前和之后都是一致的
    • 在输入部中不能使用“=”或者“+”约束条件,否则编译器会报错
    • 输入部可以是空的。
  • 破坏部(Clobbers)
  • “memory”告诉GCC编译器内联汇编指令改变了内存中的值,强迫编译器在执行该汇编代码前存储所有缓存的值,在执行完汇编代码之后重新加载该值,目的是防止编译乱序。
  • “cc”表示内嵌汇编代码修改了状态寄存器相关的标志位。
  • 指令部中的 参数表示:
    在内嵌汇编代码中,使用%0 对应输出部和输入部的第一个参数,使用%1表示第二个参数。

输出部和输入部的约束修饰符

image

输出部和输入部的约束修饰符 – 通用

  • m:内存变量
  • o:操作数为内存变量,但是其寻址方式是偏移量类型
  • V:操作数为内存变量,但寻址方式不是偏移量类型
  • r:通用寄存器
  • i:立即数
  • n:立即数
  • p:操作数是一个合法的内存地址(指针)

输出部和输入部的约束修饰符 – ARM64

image

汇编符号名字来替代以前缀%

image
为了提高代码可读性,可以使用汇编符号名字来替代以前缀%来表示的操作数

内嵌汇编的高级用法 :和宏结合

技巧1: 使用了C语言的“#”运算符。在带参数的宏中,“#”运算符作为一个预处理运算符,可以把记号转换成字符串
image

内嵌汇编:goto

  • 内嵌汇编的goto模板,可以跳转到C语言的label标签里
    image
  • Goto模板的输出部必须为空。
  • 新增一个gotolabels的部,里面列出了C语言的label,是允许跳转的label
    image