- likely与unlikely
这个宏定义主要是告诉编译器x变量更可能是1或者是0,方便编译器进行分支优化,__builtin_expect是gcc的一个宏,并没有改变变量x的值#define likely(x) (__builtin_expect((x) != 0, 1)) #define unlikely(x) (__builtin_expect((x) != 0, 0))
例如,程序:
编译查看其汇编代码:gcc -fprofile-arcs -O2 -c like.c#define LIKELY(x) __builtin_expect((x) != 0, 1) #define UNLIKELY(x) __builtin_expect((x) != 0, 0) int test_likely(int x) { if(LIKELY(x)) { x=2; } else { x=3; } return x; } int test_unlikely(int x) { if(UNLIKELY(x)) { x=2; } else { x=3; } return x; }
objdump -d like.o0000000000000000 <test_unlikely>: 0: 48 83 05 00 00 00 00 addq $0x1,0(%rip) # 8 <test_unlikely+0x8> 7: 01 8: 85 ff test %edi,%edi a: 75 0e jne 1a <test_unlikely+0x1a> 此处认为条件判断不成立可能性更大 c: 48 83 05 00 00 00 00 addq $0x1,0(%rip) # 14 <test_unlikely+0x14> 13: 01 14: b8 03 00 00 00 mov $0x3,%eax 19: c3 retq 1a: 48 83 05 00 00 00 00 addq $0x1,0(%rip) # 22 <test_unlikely+0x22> 21: 01 22: b8 02 00 00 00 mov $0x2,%eax 27: c3 retq 28: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 2f: 00 0000000000000030 <test_likely>: 30: 48 83 05 00 00 00 00 addq $0x1,0(%rip) # 38 <test_likely+0x8> 37: 01 38: 85 ff test %edi,%edi 3a: 74 0e je 4a <test_likely+0x1a> 此处认为很可能比较成立 3c: 48 83 05 00 00 00 00 addq $0x1,0(%rip) # 44 <test_likely+0x14> 43: 01 44: b8 02 00 00 00 mov $0x2,%eax 49: c3 retq 4a: 48 83 05 00 00 00 00 addq $0x1,0(%rip) # 52 <test_likely+0x22> 51: 01 52: b8 03 00 00 00 mov $0x3,%eax 57: c3 retq 58: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
- REGPRM1-3
haproxy中出现很多这种函数标示,宏定义是:
#ifndef REGPRM1
#if CONFIG_REGPARM >= 1 && __GNUC__ >= 3
#define REGPRM1 __attribute__((regparm(1)))
#else
#define REGPRM1
#endif
#endif
#ifndef REGPRM2
#if CONFIG_REGPARM >= 2 && __GNUC__ >= 3
#define REGPRM2 __attribute__((regparm(2)))
#else
#define REGPRM2 REGPRM1
#endif
#endif
#ifndef REGPRM3
#if CONFIG_REGPARM >= 3 && __GNUC__ >= 3
#define REGPRM3 __attribute__((regparm(3)))
#else
#define REGPRM3 REGPRM2
#endif
#endif
主要用到__attribute__,该关键字可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。比如我们指定 __attribute__((regparm(0))) ,则表示不用寄存器来传递参数,所有参数都通过堆栈来传递;如果我们指定 __attribute__((regparm(3))),那么就是说会用 3 个寄存器来传递参数(EAX, EDX, ECX),其余的参数通过堆栈来传递。
- syscall1-3
大多数系统调用都在各种C语言函数库中有所实现,所以在一般情况下,我们都可以像调用普通的库函数那样调用系统调用,只在极个别的情况下,我们才有机会用到_syscall*()这几个宏,在unistd.h中定义了7个宏:
syscall0(type,name)
_syscall1(type,name,type1,arg1)
_syscall2(type,name,type1,arg1,type2,arg2)
_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)
_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)
_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)
_syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,static _syscall1 (int, epoll_create, int, size);
它们的作用是形成相应的系统调用函数原型,供我们在程序中调用,这是系统调用的标准用法。我们很容易就能发现规律,_syscall后面的数字和typeN,argN的数目一样 多。事实上,_syscall后面跟的数字指明了展开后形成函数的参数的个数,比如:
static _syscall1 (int, epoll_create, int, size);
展开之后是:
int epoll_create(int size)
{
long __res;
__asm__ volatile("int $0x80" : "=a" (__res) : "0" (13),"b" ((long)(tloc)));
do {
if ((unsigned long)(__res) >= (unsigned long)(-125)) {
errno = -(__res);
__res = -1;
}
return (int) (__res);
} while (0) ;
}
可以看出,static _syscall1 (int, epoll_create, int, size);展开成一个名为epoll_create的函数,原参数int就是函数的返回类型,原参数int和size分别构成新函数的参数。函数中相当于把epoll_create引用进来设为static