Archive for the ‘gcc’ tag
locale惹的祸
换了一台新机器去做TPM硬件驱动的开发,于是从远程仓库把代码clone下来。试着把代码编译一次,出问题了,满版的错误,费点时间看了一下,其实是stddef.h没有找到造成的。
新机器和原来的机器都是一样系统,工具链也是一样的,代码也已经在我原来的机器上编译通过了。用find找了一下stddef.h,在机器上也是有的。仔细对比了一下通过和不通过的CFLAGS,发现不通过的情况下,头文件路径中没有gcc的包含路径,问题就出在这里了。
再看Makefile,gcc路径是通过如下的方法取得的。
GCC_INSTALL = $(shell gcc --print-serarch-dirs | sed -n -e 's/install: \(.*\)/\1/p')
使用sed匹配了以install开头的行。
但是,我现在这个系统的locale是中文的,所以“install”没有出现,取而代之的是“安装”,匹配不成功,GCC_INSTALL就成了空值,那么也没有把路径加入。
追踪了半天,没想到是locale出了问题。因为我原来一直用的是英文系统,所以没有遇到过这种情况。所以以后装系统,最好还是用英文的locale,不是说崇洋媚外不喜欢中文,要是遇到我今天的情况,估计还是挺恶心的,看着满版的错误,挺郁闷的。
The Story of “likely()” and “unlikely()”
“likely()” and “unlikely()” are macros defined in Linux kernel. But the true story is about optimization.
#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0)
These macros can be used in user space, though. Because they are in fact some built-in features of gcc(1). gcc(1) should optimize assembly generation according to program’s need.
Try this simple sample.
int main()
{
int a;
if (likely(a == 100))
printf("Branch 1\n");
else
printf("Branch 2\n");
return 0;
}
I use an uninitialized variable, that’s a bug, but this does not affect my demostration. Feel free to ignore that uninitialized “a”, we just need something to compare to a constant, don’t we? If I use two constants for comparison, gcc(1) will optimize in compile time and we can not see the outcoming of “likely()” and “unlikely()”.
Use gcc(1) to generate assembly.
$ gcc -S -O2 likely.c
Here is what we get. Ignore less important part, focus on most valuable snippet.
cmpl $100, %eax
jne .L2
movl $.LC0, (%esp)
call puts
.L4:
addl $4, %esp
xorl %eax, %eax
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.L2:
movl $LC1, (%esp)
call puts
jmp .L4
Pay attention to that “jne” directive. We compare variable (which stores in eax) with 100 to see if they are equal. The outcoming result is “likely” to be true, so that “jne” is not executed, the code just falls through. The benifit we get is that no jumping means no pipe line flush, we can make full use of directive cache.
If I change “likely” to “unlikely” in my C code, assembly code generation will be different. However, it should follow the same rule as above - make full use of pipe line.
The Story of “likely()” and “unlikely()”
“likely()” and “unlikely()” are macros defined in Linux kernel. But the true story is about optimization.
#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0)
These macros can be used in user space, though. Because they are in fact some built-in features of gcc(1). gcc(1) should optimize assembly generation according to program’s need.
Try this simple sample.
int main()
{
int a;
if (likely(a == 100))
printf("Branch 1n");
else
printf("Branch 2n");
return 0;
}
I use an uninitialized variable, that’s a bug, but this does not affect my demostration. Feel free to ignore that uninitialized “a”, we just need something to compare to a constant, don’t we? If I use two constants for comparison, gcc(1) will optimize in compile time and we can not see the outcoming of “likely()” and “unlikely()”.
Use gcc(1) to generate assembly.
$ gcc -S -O2 likely.c
Here is what we get. Ignore less important part, focus on most valuable snippet.
cmpl $100, %eax
jne .L2
movl $.LC0, (%esp)
call puts
.L4:
addl $4, %esp
xorl %eax, %eax
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.L2:
movl $LC1, (%esp)
call puts
jmp .L4
Pay attention to that “jne” directive. We compare variable (which stores in eax) with 100 to see if they are equal. The outcoming result is “likely” to be true, so that “jne” is not executed, the code just falls through. The benifit we get is that no jumping means no pipe line flush, we can make full use of directive cache.
If I change “likely” to “unlikely” in my C code, assembly code generation will be different. However, it should follow the same rule as above - make full use of pipe line.
Type-checking in gcc
In linux/kernel.h, there is such a macro
/*
* min()/max() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
In order to do strict type-checking, that “unnecessary” pointer comparison is, however, necessary. If we compare two distinct pointers without a cast, gcc will complain about it, so that we are able to figure out where things go wild.
To go further, we need some knowledge about Type System, which means “a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute”. That requires an understanding of computer language theories, which is beyond my knowledge now. I shall figure it out in the future.
http://en.wikipedia.org/wiki/Type_system