美文网首页C
一段C内嵌汇编代码的理解

一段C内嵌汇编代码的理解

作者: SnC_ | 来源:发表于2019-10-23 16:47 被阅读0次

在DPDK中遇到了一个内嵌C代码的函数,于是了解了一下其语法。
主要参考文档

 static inline void
 rte_spinlock_lock(rte_spinlock_t *sl)
 {
    int lock_val = 1;
    asm volatile (
            "1:\n"
            "xchg %[locked], %[lv]\n"
            "test %[lv], %[lv]\n"
            "jz 3f\n"
            "2:\n"
            "pause\n"
            "cmpl $0, %[locked]\n"
            "jnz 2b\n"
            "jmp 1b\n"
            "3:\n"
            : [locked] "=m" (sl->locked), [lv] "=q" (lock_val)
            : "[lv]" (lock_val)
            : "memory");
 }
  • 这是一段 extended asm(它与Basic asm的区别在于它有operand,即上述16~18行)。
    • extended asm代码必须写在函数内,Basic asm不用。

extend asm主要有2种格式:

asm asm-qualifiers ( AssemblerTemplate 
                 : OutputOperands 
                 [ : InputOperands
                 [ : Clobbers ] ])

asm asm-qualifiers ( AssemblerTemplate 
                      : 
                      : InputOperands
                      : Clobbers
                      : GotoLabels)

上述代码使用的是后一种。

格式分析

  • volatile为asm-qualifier。

    • volatile的作用为:防止assembler对asm代码进行优化,改变其原来的布局。
  • 6~15行,为Assembler Template

    • 它读取Operand中的输入,形成最终的汇编代码,并由gcc传给assembler解析。 gcc自己不会分析这段内容。
  • 第16行,为Output Operands

    • [locked] 和 [lv] 对应 Template 中的 %[locked] 和 %[lv]。
    • (sl->locked) 和 (lock_val) 对应C代码中的变量。
    • 汇编代码运行后的输出由这句代码指定。
  • Output Operands中的"=m"为 Constraints。

    • "="为Modifier,其表示用左边的值覆写右边的值。
    • msimple constraint中的一个,表示将结果存放到内存中。
    • q表示哪个寄存器本人尚未清楚。
  • 第17行,为Input Operands,用于指定Template中的输入

  • 第18行,为Clobber,用于指定汇编代码需要改变哪些寄存器/其他位置的数据,防止代码意外地改写更多数据。

    • momory表示汇编代码会读或写内存到上述的Input/Output Operands

汇编内容分析

  • 第6、10、15行为汇编中的Label,用于跳转用。第9、13、14会根据Condition Register的内容进行跳转。3f表示Label 3在下面,1b2b表示Label 1和Label 2在上面。
  • %[xxx] 对应Input/Output Operands中的变量。
  • $0 表示数字0
  • test 对2个操作数进行AND操作。
  • cmpl(Compare Logical),以unsigned integer的形式比较2个操作数的内容,并改写Condition Register Field中的一个bit。
  • pause ,一般只用在Spinlock的代码中,用来告诉CPU接下来运行的代码是spin-wait循环。 具体细节貌似较为复杂,感兴趣的可以仔细浏览这两个链接。

此函数的目的就是加锁,即将sl->locked变量置为1.

  1. 输入值lv(即lock_val)为1,在第7行将 lv 与 locked 交换,并检查交换后 lv 的值。若为0,说明锁之前是free的,此时成功加锁,跳到 Label 3退出函数。
  2. 若交换后 lv 的值为1,说明锁已经被加上,这就需要等待其free后再加锁,10~13行即等待锁free的循环。
  3. 等到锁为free时,从14行跳到第6行,继续执行第1步。

相关文章

网友评论

    本文标题:一段C内嵌汇编代码的理解

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