在linux/include/unistd.h中定义的系统调用嵌入汇编宏函数_syscall0。
其实展开不难发现就是一个函数,只不过用宏定义了。其中关键的是怎么理解 __asm__ volatile这个语法。对于__asm__ volatile这个固定形式,我们暂且不理会它(可参考http://blog.csdn.net/robbie1314/archive/2011/04/17/6329880.aspx),关键看懂()里面的含义。
以下面这个为例子先简要介绍一下这个用法。
插入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;/
}