ARM64基础11:GCC内嵌汇编补充

目的:
(1)优化,对特定代码进行优化;
(2)C语言需要访问某些特殊指令来实现特殊功能,比如内存屏障指令;

内嵌汇编两种模式:

基础内嵌汇编:不带参数;
扩展的内嵌汇编:C语言变量参数;

(1)基础内嵌汇编

格式
asm关键字:表明是一个GNU扩展;
修饰词(qualifiers)
volatile:基础内嵌汇编中,通常不需要;
inline:内敛,asm代码会尽可能小;

汇编代码块
GCC编译器把内嵌汇编当成一个字符串;
GCC编译器不会去解析和分析内嵌汇编;
多条汇编指令,需要使用“\n\t”换行;
GCC的优化器,可能乱序汇编指令,如果需要保持汇编指令的顺序,最好使用多个内嵌汇编的方式;
内核arch/arm64/include/asm/barrier.h文件
在这里插入图片描述

(2)扩展内嵌汇编

asm asm-qualifiers(
				Assembler Template;
				:outputOperands
				:inputOperands
				[:Clobbers])

格式
asm关键字:表明是一个GNU扩展;
修饰词(qualifiers)
volatile:用来关闭GCC优化;
inline: 内敛,减小汇编代码尺寸;
goto:在内嵌汇编里会跳转到C语言的label;
输出部
用于描述在指令部中可以被修改的C语言变量以及约束条件;
每个约束通常以"="开头,接着的字母表示对操作类型的说明,然后是关于变量结合的约束;

=+”+约束修饰符+变量

“=”表示被修饰的操作数具有可写属性;
“+”表示被修饰的操作数具有可读可写属性;
输出部可以是空的;

输入部:
用来描述在指令部中,只读的C语言变量以及约束条件;
输入部描述的参数,是只读属性,不要修改参数内容,因为GCC编译器假定输入部参数,在内嵌汇编前后是一致的;
输入部中不能使用"=/+"约束条件,编译器会报错;
输入部可以是空的;

损坏部:
“memory”告诉GCC内嵌汇编指令 改变了内存的值,强迫编译器在执行该汇编代码前,存储所有缓存的值,在执行完汇编代码之后重新加载该值,目的是防止编译乱序;
“cc”:表示内嵌汇编代码影响状态寄存器相关的标志位;

内核里的实例,arch/arm64/include/asm/barrier.h
在这里插入图片描述
扩展内嵌汇编指令部中的参数表示:
在这里插入图片描述
案例1,用内嵌汇编实现memcpy:

  static void my_memcpy_asm_test(unsigned long src, unsigned long dst,unsigned long counter)
  {
      unsigned long tmp;
      unsigned long end = src+counter;
  
      asm volatile(
              "1: ldr %1, [%2], #8\n"
              "str %1, [%0], #8\n"
              "cmp %2, %3\n"
              "b.cc 1b"
              :"+r"(dst),"+r"(tmp),"+r"(src)   //output list, can write and read
              :"r"(end)                        //input list, readonly
              :"memory"
              );
  }

使用汇编符号名实现内嵌汇编:

  static void my_memcpy_asm_test(unsigned long src, unsigned long dst,unsigned long counter)
  {
      unsigned long tmp;
      unsigned long end = src+counter;
  
      asm volatile(
              "1: ldr %[tmp], [%[src]], #8\n"
              "str %[tmp], [%[dst]], #8\n"
              "cmp %[src], %[end]\n"
              "b.cc 1b"
              :[dst]"+r"(dst),[tmp]"+r"(tmp),[src]"+r"(src)   //output list, can write and read
              :[end]"r"(end)                        //input list, readonly
              :"memory"
              );  
  }

内嵌汇编与宏结合

 #define MY_OPS(ops,asm_ops) \
  static inline my_asm_##ops(unsigned long mask, void *p) \
  { \
      unsigned long tmp; \
      asm volatile( \
              "ldr %1, [%0]\n" \
              " "#asm_ops" %1, %1, %2\n" \
              "str %1,[%0]\n" \
              : "+r"(p), "+r"(tmp) \
              :"r"(mask) \
              : "memory" \
              ); \
  }
  
  MY_OPS(and, and)
  MY_OPS(or, orr)
  MY_OPS(andnot, bic)
  
  static void my_ops_test(void)
  {
      unsigned long p;
  
      p = 0xf;
      my_asm_and(0x2, &p);
      printk("test and:p=0x%x\n",p);
  
      p = 0x0;
      my_asm_or(0x3, &p);
      printk("test or:p=0x%x\n",p);
  
      p = 0x3;
      my_asm_andnot(0x2, &p);
      printk("test andnot:p=0x%x\n",p);
  }

技巧:

(1)使用了C语言宏中的“#”和“##”;
“#”:预处理器把这个参数转换为一个字符串;
“##”:是一种分隔链接方式,它的作用是先分隔,在进行强制链接;
(2)通过一个宏来实现多个类似的函数,这是linux内核常用的技巧;

实现读和写系统寄存器的宏

 //equals    asm volatile("mrs %0,""#reg" :"=r"(_val)); _val;}
  #define read_sysreg(reg) ({ \
      unsigned long _val; \
      asm volatile("mrs %0,"#reg \
                   :"=r"(_val)); \
                   _val; \
  })
  
  #define write_sysreg(val, reg) ({\
          unsigned long _val=(unsigned long)val; \
          asm volatile("msr "#reg ",%0" \
          ::"rZ"(_val)); \
  })
  static test_sysregs(void)
  {
      unsigned long el; 
  
      el = read_sysreg(CurrentEL);
      printk("el=%d\n",el>>2);
  
      write_sysreg(0x10000, vbar_el1);
      printk("read vbar:0x%x\n",read_sysreg(vbar_el1));
  }

实现从汇编到C代码的跳转

  
  static void test_asm_goto(int a)                                                                                                           
  {
      asm goto(
              "cmp %w0, 1\n"
              "b.eq %l[label]\n"
              :        //必须为空
              :"r"(a)
              :"memory"
              :label
              );  
  
      return 0;
  label:
      printk("%s: a=%d.\n",__func__,a);
  }

goto模板的输出部必须为空;

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值