Linux嵌入式汇编(转)

  在Linux的源代码中,有很多C语言的函数中嵌入一段汇编语言程序段,这就是gcc提供的“asm”功能,例如在include/asm-i386/system.h中定义的,读控制寄存器CR0的一个宏read_cr0():
   #define read_cr0() ({ \

         unsigned int __dummy; \

         __asm__( \

                 "movl %%cr0,%0\n\t" \

                 :"=r" (__dummy)); \

         __dummy; \

 })

  这种形式看起来比较陌生,这是因为这不是标准C所定义的形式,而是gcc 对C语言的扩充。其中__dummy为C函数所定义的变量;关键词__asm__表示汇编代码的开始。括弧中第一个引号中为汇编指令movl,紧接着有一个冒号,这种形式阅读起来比较复杂。

  一般而言,嵌入式汇编语言片段比单纯的汇编语言代码要复杂得多,因为这里存在怎样分配和使用寄存器,以及把C代码中的变量应该存放在哪个寄存器中。为了达到这个目的,就必须对一般的C语言进行扩充,增加对编译器的指导作用,因此,嵌入式汇编看起来晦涩而难以读懂。

1. 嵌入式汇编的一般形式:

__asm__ __volatile__ ("<asm routine>" : output : input : modify);

   其中,__asm__表示汇编代码的开始,其后可以跟__volatile__(这是可选项),其含义是避免“asm”指令被删除、移动或组合;然后就是小括弧,括弧中的内容是我们介绍的重点:

·      "<asm routine>"为汇编指令部分,例如,"movl %%cr0,%0\n\t"。数字前加前缀“%“,如%1,%2等表示使用寄存器的样板操作数。可以使用的操作数总数取决于具体CPU中通用寄存器的数量,如Intel可以有8个。指令中有几个操作数,就说明有几个变量需要与寄存器结合,由gcc在编译时根据后面输出部分和输入部分的约束条件进行相应的处理。由于这些样板操作数的前缀使用了”%“,因此,在用到具体的寄存器时就在前面加两个“%”,如%%cr0。

·      输出部分(output),用以规定对输出变量(目标操作数)如何与寄存器结合的约束(constraint),输出部分可以有多个约束,互相以逗号分开。每个约束以“=”开头,接着用一个字母来表示操作数的类型,然后是关于变量结合的约束。例如,上例中:

:"=r" (__dummy)

“=r”表示相应的目标操作数(指令部分的%0)可以使用任何一个通用寄存器,并且变量__dummy 存放在这个寄存器中,但如果是:

:“=m”(__dummy)

“=m”就表示相应的目标操作数是存放在内存单元__dummy中。

表示约束条件的字母很多,下表给出几个主要的约束字母及其含义:

      字母

含义

   m, v,o

表示内存单元

   R

表示任何通用寄存器

   Q

表示寄存器eax, ebx, ecx,edx之一

   I, h

表示直接操作数

   E, F

表示浮点数

   G

表示“任意”

   a, b.c d

表示要求使用寄存器eax/ax/al, ebx/bx/bl, ecx/cx/cl或edx/dx/dl

   S, D

表示要求使用寄存器esi或edi

   I

表示常数(0~31)

  输入部分(Input):输入部分与输出部分相似,但没有“=”。如果输入部分一个操作数所要求使用的寄存器,与前面输出部分某个约束所要求的是同一个寄存器,那就把对应操作数的编号(如“1”,“2”等)放在约束条件中,在后面的例子中,我们会看到这种情况。

  修改部分(modify):这部分常常以“memory”为约束条件,以表示操作完成后内存中的内容已有改变,如果原来某个寄存器的内容来自内存,那么现在内存中这个单元的内容已经改变。

  注意,指令部分为必选项,而输入部分、输出部分及修改部分为可选项,当输入部分存在,而输出部分不存在时,分号“:“要保留,当“memory”存在时,三个分号都要保留,例如system.h中的宏定义__cli():

   #define __cli()                 __asm__ __volatile__("cli": : :"memory")

  cmpxchg %ecx, %ebx;如果EAX与EBX相等,则ECX送EBX且ZF置1;否则EBX送EAX,且ZF清0
  也就是说,在old和ptr指向的内容不相等的时候,将ptr的内容写入eax中,这样,ptr的内容就会返回给cmpxchg函数的调用者。这样就和原意相符合了。

posted on 2013-07-29 21:28  Brill  阅读(1051)  评论(0)    收藏  举报

导航