Linux C内联汇编用法

  Linux内核中有很多c中使用汇编的情况,比如原子操作。内联汇编通常用下面的格式:

asm volatile("Instruction List" : Output : Input : Clobber/Modify);

        当然,或者写作如下格式(Output、Input、Clobber/Modify都是可选的),也就是三个冒号,4个部分:

asm volatile("Instruction List"

                                    : Output

                                    : Input

                                    : Clobber/Modify);

        为了理解方便,以屏蔽本地irq相关函数的代码为例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
static inline unsigned long native_save_fl( void )
{
     unsigned long flags;
  
     /*
      * "=rm" is safe here, because "pop" adjusts the stack before
      * it evaluates its effective address -- this is part of the
      * documented behavior of the "pop" instruction.
      */
     asm volatile ( "# __raw_save_flags\n\t"
              "pushf ; pop %0"
              : "=rm" (flags)
              : /* no input */
              : "memory" );
  
     return flags;
}
  
static inline void native_restore_fl(unsigned long flags)
{
     asm volatile ( "push %0 ; popf"
              : /* no output */
              : "g" (flags)
              : "memory" , "cc" );
}
  
static inline void native_irq_disable( void )
{
     asm volatile ( "cli" : : : "memory" );
}
  
static inline void native_irq_enable( void )
{
     asm volatile ( "sti" : : : "memory" );
}

        本篇blog耗时2小时。

 

1、asm和volatile

        volatile是c的关键字,是个修饰符,用于修饰变量或者函数,意思是告诉编译器,该变量或者函数是“易变”的,编译器会在优化时做相关的考虑。驱动中常用于修饰急促器变量。Linux下c中的使用内联汇编,就是这样,需要asm()的格式,可以没有volitile,但不能没有asm。

        关于asm到底是什么?首先,它不是ANSI C关键字,c89/c99标准中没有asm关键字;asm属于“GNU C Language Extensions”,像typeof,inline等都是这种情况。

2、Instruction List

        指令序列,就是指要执行的指令汇编指令,多条指令之间使用 分隔符“;”、“\n\t”等进行联合。

        对应例子中,就是

  • "pushf;pop %0"
  • “push %0;popf”
  • "cli"
  • "sti"

        含义分别为:

  • 将EFLAGS寄存器的值压栈,再出栈给的1个变量(先这么叫吧)
  • 将第1个变量压栈,再出栈给EFLAGS寄存器
  • 禁止本地中断
  • 开启本地中断

3、Output

        指令序列执行的结果的输出,指指令执行的结果要输出到哪。Output和Input部分,通常使用下列格式:

“constraint”(variable)

        constraint为限制的意思,翻译好听点就是“修饰”,用于限制variable的。

        在例子中,只有navtive_save_fl函数有“=rm”(flags),这句还不好臆测,还得查资料(参考资料5):

  • =,表示只写,也是output必须具备的(看见=,就是output)
  • r表示寄存器
  • m表示内存
  • flags为变量名

        联合起来表示将flags变量以内存或者寄存器的方式进行操作,flags是输出。

        关于constraint:

  • a,b,c,d,S,D 分别代表 eax,ebx,ecx,edx,esi,edi 寄存器
  • r 上面的寄存器的任意一个(谁闲着就用谁)
  • m 内存
  • i 立即数(常量,只用于输入操作数)
  • g 寄存器、内存、立即数 都行(gcc你看着办)

4、Input

       Input和Output很像,就是没有“=”。Input为指令序列提供输入,在例子中,只有native_restore_fl函数有“g”(flags),g表示“Any register, memory or immediate integer operand is allowed, except for registers that are not general registers.”,表示flags可以使用寄存器、内存、立即数等方式。

        还有个问题,就是Input和Output如何与Instruction List相关联的?Instruction List中的%0,前面叫他“第一个变量”,实际上是不准确的,实际上应该叫做input/output operand,输入/输出操作数,从Output开始,0表示第一个,1就表示第二个,以此类推。从gcc3.1开始,支持直接将%0写作%[input]、%[output]。

       input和Output可以有多个变量:中间用“,”隔开。

5、Clobber/Modify

       该部分表示哪些寄存器、内存被修改,但是又没有出现在Input/Output中。通常看到的就是memory,表示汇编语句可能修改了内存,如果有变量缓存在寄存器中,需要重新读取该变量。

 

参考资料:

1、Linux 中 x86 的内联汇编

2、__asm__ __volatile__内嵌汇编用法简述

3、第 19 章 汇编与C之间的关系

4、AT&T inline Assembly Constraint

5、Assembler Instructions with C Expression Operands

6、内联汇编

7、GCC-Inline-Assembly-HOWTO

Published in C语言技巧 and tagged asm, 汇编 on 2013年11月24日 by rock3
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值