鱼C论坛

 找回密码
 立即注册
查看: 1979|回复: 1

[技术交流] __asm__ volatile 之 C语言嵌入式汇编

[复制链接]
发表于 2013-5-30 11:57:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x

插入C语言的一个汇编语言代码片段可以分成4部分,以“:”号加以分隔,其一般形式为:

指令部:输出部:输入部:损坏部

static __inline__ void atomic_add(int i, atomic_t *v)

{

    __asm_volatile__(

               LOCK "addl %1, %0"

               : "=m" (v->counter)

               : "ir" (i), "m" (v->counter));

}

当汇编语言代码嵌入到C代码时,解决操作数和C代码中的变量结合是一个问题。我们无法确切知道gcc在嵌入点的前后会把哪个寄存器分配给哪个变量等,所以gcc采用一种方法:程序员只提供具体的指令,而对寄存器的使用则一般只提供一个“样板”和一些约束条件,而到底如何把变量和操作数结合的问题留给gcc和gas去处理。

指令部

数字加上前缀%,如%1、%0等,表示需要使用寄存器的样板操作数。可以使用的此类操作数的总数取决于具体CPU中通用寄存器的数量。

输出部

规定对输出变量,即目标操作数如何结合的约束条件。每个这样的条件称为一个“约束条件”。必要时输出部可以有多个约束条件,互相以逗号分隔。每个输出约束以“=”号开头,然后是一个字母表示对操作数类型的说明,然后是关于变量结合的约束。例子中:

: “=m”  (v->counter)

这里只有一个约束条件,“=m”表示相应的目标操作数(指令中的%0)是一个内存单元v->counter。

输入部

输入部约束的格式和输出约束相似,但不带“=”号。例子中:

第1个为"ir" (i),表示指令中的%1可以是一个在寄存器中的“直接操作数”(i表示immediate),并且该操作数来自于C代码中的变量名(这里是调用参数)i。

第2个约束条件“m” (v->counter)意义与输入约束相同。

损坏部

有些操作中,除了用于输入操作数和输出操作数的寄存器外,还要将若干个寄存器用于计算或者操作的中间结果。这样,这些寄存器原有的内容就损坏了,所以要在损坏部对操作的副作用加以说明,让gcc采取相应的措施。不过,有的时候就直接把这些说明放在输出部了,那也并无不可。

操作数的编号从输出部的第一个约束(序号为0)开始,顺序数下来,每个约束计数加1次。在指令部中引用这些操作数或分配用于这些操作数的寄存器时,就在序号前面加上%号。

表示约束条件的字母有很多,主要有:

"m"、"v"和"o"    ---- 表示内存单元

"r"                     ---- 表示任何寄存器

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

"i"和"h"             ---- 表示直接操作数

"E"和"F"            ---- 表示浮点数

"g"                    ---- 表示任意

"a","b", "c" "d" ---- 分别表示要使用寄存器eax ebx ecx和edx

"S"和"D"            ---- 分别表示要使用寄存器esi和edi

"I"                     ---- 表示常数(0至31)

回到上面的例子,这段代码的作用是将参数i的值加到v->counter上。代码的关键字LOCK表示在执行addl指令时要把系统总线锁住,不让别的CPU打扰,以保证原子性操作。

下面就可以照着上面的说明把下面代码看懂吧。

代码:

/* 以下定义系统调用嵌入式汇编宏函数 */

/* 不带参数的系统调用宏函数。type name(void)。
* %0 -eax(__res), %1 - eax(__NR_##name)。其中name是系统调用的名称
* 与 __NR_ 组合形成上面的系统调用符号常用,从而用来对系统调用表中函数指针寻址
* 调用系统中断0x80,返回值->eax(_res), 输入为系统中断调用号__NR_name
* 返回: 如果返回值大于等于0,则返回该值,否则置出错号errno,并返回-1
*/
#define _syscall0(type, name)/
type name(void)/
{/
    long __res;/
    __asm__ volatile ("int $0x80" /
                      : "=a" (__res) /
                      : "" (__NR_##name));/
    if (__res >= 0)/
    {/
        return (type)__res;/
    }/
    errno = -__res;/
    return -1;/
}

/* 有1个参数的系统调用宏函数。type name(atype a)
* %0 - eax(__res), %1 - eax(__NR_name), %2 - ebx(a)
*/
#define _syscall1(type, name, atype, a) /
type name(atype a)/
{/
    long __res;/
    __asm__ volatile ("int $0x80"/
                      : "=a" (_res)/
                      : "" (__NR_#name), "b" ((long)(a)));/
    if (__res >= 0)/
    {/
        return (type)__res;/
    }/
    errno = -__res;/
    return -1;/
}

/* 有2个参数的系统调用宏函数。type name(atype a, btype b)
* %0 - eax(__res), %1 - eax(__NR_name), %2 - ebx(a), %3 - ecx(b)
*/
#define _syscall2(type, name, atype, a, btype, b)/
type name(atype a, btype b)/
{/
    long __res;/
    __asm__ volatile ("int $0x80"/
                      : "=a" (__res)/
                      : "" (__NR_##name), "b" ((long)(a)), "c" ((long)(b)));/
    if (__res >= 0)/
    {/
        return (type)__res;/
    }/
    errno = -__res;/
    return -1/
}

/* 有3个参数的系统调用宏函数。type name(atype a, btype b, ctype c)
* %0 - eax(__res), %1 - eax(__NR_name), %2 - ebx(a), %3 - ecx(b), %4 - edx(c)
*/
#define _syscall3(type, name, atype, a, btype, b, ctype, c) /
type name(atype a, btype b, ctype c)/
{/
    long __res;/
    __asm__ volatile ("int $0x80"/
                      : "=a" (__res) /
                      : "" (__NR_##name), "b" ((long)(a)), /
                        "c" ((long)(b)), "d" ((long)(c)));/
    if (__res >= 0)/
    {/
        return (type)__res;/
    }/
    errno = -__res;/
    return -1;/
}


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-5-30 13:06:26 | 显示全部楼层
我不得不顶了……
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-17 12:33

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表