Linux C内联汇编用法

转载 2013年12月05日 11:31:27
  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

【Linux学习笔记】Linux C中内联汇编的语法格式及使用方法(Inline Assembly in Linux C)

在阅读Linux内核源码或对代码做性能优化时,经常会有在C语言中嵌入一段汇编代码的需求,这种嵌入汇编在CS术语上叫做inline assembly。本文的笔记试图说明Inline Assembly的基...
  • slvher
  • slvher
  • 2013年04月28日 20:53
  • 10465

内联汇编

内联汇编   内联汇编是指在 C/C++ 代码中嵌入的汇编代码,与全部是汇编的汇编源文件不同,它们被嵌入到 C/C++ 的大环境中。 一、gcc 内联汇编   gcc 内联汇编的格式如下: ...

C 内联汇编方法 __asm__ __volatile__

__asm__ __volatile__ C内嵌汇编, 内联汇编方法

Linux 中 x86 的内联汇编

Linux 中 x86 的内联汇编 如果您是 Linux 内核的开发人员,您会发现自己经常要对与体系结构高度相关的功能进行编码或优化代码路径。您很可能是通过将汇编语言指令插入到 C 语句的中间(...

Linux 内嵌汇编

简要说下GNU汇编编译器的语法 GCC,linux下的GNU c编译器,用的是AT&T的语法,下面列出一些,但并不是全部,,只是和内嵌汇编相关的部分 寄存器的命名 在寄存器的名字前加前缀%, 比...

linux下的C语言的asm内嵌式汇编

最近在上linux系统安全分析这门课,自己对这一方便比较感兴趣,就记载在这里。 关于asm内嵌式汇编 __asm__( " 汇编语句模板" : "输出部分 " : "输入部分 " ...

Linux GCC内嵌嵌入汇编程序基础知识

在Linux代码中很多地方都使用了这种形式的汇编语言,嵌入汇编程序的格式如下:   __asm__ __volatile__ (   asm statements   : outpu...

内联汇编语法和使用方法

转自:http://blog.csdn.net/slvher/article/details/8864996 //自学专用  在阅读Linux内核源码或对代码做性能优化时,经常会有在C语言中嵌入一...
  • ml_1995
  • ml_1995
  • 2016年04月02日 16:05
  • 1927

内联汇编基础学习

内联汇编简介在Linux内核代码中有一部分是使用汇编语言编写的,尤其是与特定体系结构相关的代码和一些对性能影响很大的代码都是使用汇编语言进行编写的,那么GCC为了可以在C语言中来编写汇编代码,提供了内...

ARM嵌入式开发中的GCC内联汇编__asm__

在针对ARM体系结构的编程中,一般很难直接使用C语言产生操作协处理器的相关代码,因此使用汇编语言来实现就成为了唯一的选择。但如果完全通过汇编代码实现,又会过于复杂、难以调试。因此,C语言内嵌汇编的方式...
  • comwise
  • comwise
  • 2013年08月25日 19:43
  • 1169
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux C内联汇编用法
举报原因:
原因补充:

(最多只允许输入30个字)