星期五, 十二月 28, 2007

gcc核心扩展

===========================
Linux 内核使用的 GNU C 扩展
===========================

GNC CC 是一个功能非常强大的跨平台 C 编译器,它对 C 语言提供了很多扩展,
这些扩展对优化、目标代码布局、更安全的检查等方面提供了很强的支持。本文把
支持 GNU 扩展的 C 语言称为 GNU C。

Linux 内核代码使用了大量的 GNU C 扩展,以至于能够编译 Linux 内核的唯一编
译器是 GNU CC,以前甚至出现过编译 Linux 内核要使用特殊的 GNU CC 版本的情
况。本文是对 Linux 内核使用的 GNU C 扩展的一个汇总,希望当你读内核源码遇
到不理解的语法和语义时,能从本文找到一个初步的解答,更详细的信息可以查看
gcc.info。文中的例子取自 Linux 2.4.18。

语句表达式
==========

GNU C 把包含在括号中的复合语句看做是一个表达式,称为语句表达式,它可以出
现在任何允许表达式的地方,你可以在语句表达式中使用循环、局部变量等,原本
只能在复合语句中使用。例如:

++++ include/linux/kernel.h
159: #define min_t(type,x,y) \
160:         ({ type __x = (x); type __y = (y); __x window_clamp, tcp_full_space(sk));

复合语句的最后一个语句应该是一个表达式,它的值将成为这个语句表达式的值。
这里定义了一个安全的求最小值的宏,在标准 C 中,通常定义为:

#define min(x,y) ((x) " "%s:%d", filename, line)

使用 ## 的原因是处理 arg 不匹配任何参数的情况,这时 arg 的值为空,GNU
C 预处理器在这种特殊情况下,丢弃 ## 之前的逗号,这样

    pr_debug("success!\n")

扩展为

    printk("" "success!\n")

注意最后没有逗号。

标号元素
========

标准 C 要求数组或结构变量的初使化值必须以固定的顺序出现,在 GNU C 中,通
过指定索引或结构域名,允许初始化值以任意顺序出现。指定数组索引的方法是在
初始化值前写 '[INDEX] =',要指定一个范围使用 '[FIRST ... LAST] =' 的形式,
例如:

+++++ arch/i386/kernel/irq.c
1079: static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };

将数组的所有元素初使化为 ~0UL,这可以看做是一种简写形式。

要指定结构元素,在元素值前写 'FIELDNAME:',例如:

++++ fs/ext2/file.c
41: struct file_operations ext2_file_operations = {
42:         llseek:         generic_file_llseek,
43:         read:           generic_file_read,
44:         write:          generic_file_write,
45:         ioctl:          ext2_ioctl,
46:         mmap:           generic_file_mmap,
47:         open:           generic_file_open,
48:         release:        ext2_release_file,
49:         fsync:          ext2_sync_file,
50 };

将结构 ext2_file_operations 的元素 llseek 初始化为 generic_file_llseek,
元素 read 初始化为 genenric_file_read,依次类推。我觉得这是 GNU C 扩展中
最好的特性之一,当结构的定义变化以至元素的偏移改变时,这种初始化方法仍然
保证已知元素的正确性。对于未出现在初始化中的元素,其初值为 0。

Case 范围
=========

GNU C 允许在一个 case 标号中指定一个连续范围的值,例如:

++++ arch/i386/kernel/irq.c
1062:                         case '0' ... '9': c -= '0'; break;
1063:                         case 'a' ... 'f': c -= 'a'-10; break;
1064:                         case 'A' ... 'F': c -= 'A'-10; break;

    case '0' ... '9':

相当于

    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':

声明的特殊属性
==============

GNU C 允许声明函数、变量和类型的特殊属性,以便手工的代码优化和更仔细的代
码检查。要指定一个声明的属性,在声明后写

    __attribute__ (( ATTRIBUTE ))

其中 ATTRIBUTE 是属性说明,多个属性以逗号分隔。GNU C 支持十几个属性,这
里介绍最常用的:

* noreturn

属性 noreturn 用于函数,表示该函数从不返回。这可以让编译器生成稍微优化的
代码,最重要的是可以消除不必要的警告信息比如未初使化的变量。例如:

++++ include/linux/kernel.h
47: # define ATTRIB_NORET  __attribute__((noreturn)) ....
61: asmlinkage NORET_TYPE void do_exit(long error_code)
        ATTRIB_NORET;

* format (ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)

属性 format 用于函数,表示该函数使用 printf, scanf 或 strftime 风格的参
数,使用这类函数最容易犯的错误是格式串与参数不匹配,指定 format 属性可以
让编译器根据格式串检查参数类型。例如:

++++ include/linux/kernel.h?
89: asmlinkage int printk(const char * fmt, ...)
90:         __attribute__ ((format (printf, 1, 2)));

表示第一个参数是格式串,从第二个参数起根据格式串检查参数。

* unused

属性 unused 用于函数和变量,表示该函数或变量可能不使用,这个属性可以避免
编译器产生警告信息。

* section ("section-name")

属性 section 用于函数和变量,通常编译器将函数放在 .text 节,变量放在
.data 或 .bss 节,使用 section 属性,可以让编译器将函数或变量放在指定的
节中。例如:

++++ include/linux/init.h
78: #define __init          __attribute__ ((__section__ (".text.init")))
79: #define __exit          __attribute__ ((unused, __section__(".text.exit")))
80: #define __initdata      __attribute__ ((__section__ (".data.init")))
81: #define __exitdata      __attribute__ ((unused, __section__ (".data.exit")))
82: #define __initsetup     __attribute__ ((unused,__section__ (".setup.init")))
83: #define __init_call     __attribute__ ((unused,__section__ (".initcall.init")))
84: #define __exit_call     __attribute__ ((unused,__section__ (".exitcall.exit")))

连接器可以把相同节的代码或数据安排在一起,Linux 内核很喜欢使用这种技术,
例如系统的初始化代码被安排在单独的一个节,在初始化结束后就可以释放这部分
内存。

* aligned (ALIGNMENT)

属性 aligned 用于变量、结构或联合类型,指定变量、结构域、结构或联合的对
齐量,以字节为单位,例如:

++++ include/asm-i386/processor.h
294: struct i387_fxsave_struct {
295:         unsigned short  cwd;
296:         unsigned short  swd;
297:         unsigned short  twd;
298:         unsigned short  fop;
299:         long    fip;
300:         long    fcs;
301:         long    foo;
......
308: } __attribute__ ((aligned (16)));

表示该结构类型的变量以 16 字节对齐。通常编译器会选择合适的对齐量,显示指
定对齐通常是由于体系限制、优化等原因。

* packed

属性 packed 用于变量和类型,用于变量或结构域时表示使用最小可能的对齐,用
于枚举、结构或联合类型时表示该类型使用最小的内存。例如:

++++ include/asm-i386/desc.h
51: struct Xgt_desc_struct {
52:         unsigned short size;
53:         unsigned long address __attribute__((packed));
54: };

域 address 将紧接着 size 分配。属性 packed 的用途大多是定义硬件相关的结
构,使元素之间没有因对齐而造成的空洞。

当前函数名
==========

GNU CC 预定义了两个标志符保存当前函数的名字,__FUNCTION__ 保存函数在源码
中的名字,__PRETTY_FUNCTION__ 保存带语言特色的名字。在 C 函数中,这两个
名字是相同的,在 C++ 函数中,__PRETTY_FUNCTION__ 包括函数返回类型等额外
信息,Linux 内核只使用了 __FUNCTION__。

++++ fs/ext2/super.c
98: void ext2_update_dynamic_rev(struct super_block *sb)
99: {
100:         struct ext2_super_block *es = EXT2_SB(sb)->s_es;
101:
102:         if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
103:                 return;
104:
105:         ext2_warning(sb, __FUNCTION__,
106:                      "updating to rev %d because of new feature flag, "
107:                      "running e2fsck is recommended",
108:                      EXT2_DYNAMIC_REV);

这里 __FUNCTION__ 将被替换为字符串 "ext2_update_dynamic_rev"。虽然
__FUNCTION__ 看起来类似于标准 C 中的 __FILE__,但实际上 __FUNCTION__
是被编译器替换的,不象 __FILE__ 被预处理器替换。

内建函数
========

GNU C 提供了大量的内建函数,其中很多是标准 C 库函数的内建版本,例如
memcpy,它们与对应的 C 库函数功能相同,本文不讨论这类函数,其他内建函数
的名字通常以 __builtin 开始。

* __builtin_return_address (LEVEL)

内建函数 __builtin_return_address 返回当前函数或其调用者的返回地址,参数
LEVEL 指定在栈上搜索框架的个数,0 表示当前函数的返回地址,1 表示当前函数
的调用者的返回地址,依此类推。例如:

++++ kernel/sched.c
437:                 printk(KERN_ERR "schedule_timeout: wrong timeout "
438:                        "value %lx from %p\n", timeout,
439:                        __builtin_return_address(0));

* __builtin_constant_p(EXP)

内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数,如果参数
EXP 的值是常数,函数返回 1,否则返回 0。例如:

++++ include/asm-i386/bitops.h
249: #define test_bit(nr,addr) \
250: (__builtin_constant_p(nr) ? \
251:  constant_test_bit((nr),(addr)) : \
252:  variable_test_bit((nr),(addr)))

很多计算或操作在参数为常数时有更优化的实现,在 GNU C 中用上面的方法可以
根据参数是否为常数,只编译常数版本或非常数版本,这样既不失通用性,又能在
参数是常数时编译出最优化的代码。

* __builtin_expect(EXP, C)

内建函数 __builtin_expect 用于为编译器提供分支预测信息,其返回值是整数表
达式 EXP 的值,C 的值必须是编译时常数。例如:

++++ include/linux/compiler.h
13: #define likely(x)       __builtin_expect((x),1)
14: #define unlikely(x)     __builtin_expect((x),0)
++++ kernel/sched.c
564:         if (unlikely(in_interrupt())) {
565:                 printk("Scheduling in interrupt\n");
566:                 BUG();
567:         }

这个内建函数的语义是 EXP 的预期值是 C,编译器可以根据这个信息适当地重排
语句块的顺序,使程序在预期的情况下有更高的执行效率。上面的例子表示处于中
断上下文是很少发生的,第 565-566 行的目标码可能会放在较远的位置,以保证
经常执行的目标码更紧凑。

3 意見:

匿名 说...

A nice double sprain on swimwear [url=http://plus-size-swimwear.webnode.com/]women s swimwear[/url] Rare editorial supplies the important points for swimwear which only a couple of persons know. [url=http://modest-swimwear.webnode.com/]modest swimwear[/url] Impartial guide lets out Unique brand new stuff about swimwear that not a soul is bringing up. [url=http://spanx-swimwear.webnode.com/]spanx swimwear[/url] Specifically why all of them are dead wrong on the subject off bikini and also why you have to look at this expose. [url=http://vitamin-a-swimwear.webnode.com/]betsey johnson swimwear[/url] The reasons why anything and everything that you've read about swimwear is actually false and what you must know.
All new swimwear Publication Presents The Right Way To Rule The swimwear Arena [url=http://girls-swimwear.webnode.com/]girls swimwear[/url] Recent questions on swimwear replied in addition to the reason why you must absolutely scan through every concept in this insider report. [url=http://freya-swimwear.webnode.com/]freya swimwear[/url] Something everyone else has been doing with regards to swimwear and consequently something that you would want to try and do totally different. [url=http://victoria-secret-swimwear.webnode.com/]bra sized swimwear[/url] Innovative swimwear E-book Reveals A Way To Rule The swimwear Market [url=http://cheap-swimwear.webnode.com/]swimwear sale[/url] Fresh guideline clearly shows the information on swimwear as well as , reasons why you will need to take action now.[url=http://women-swimwear.webnode.com/]tan through swimwear[/url] Rare blog provides the leading points over swimwear which experts state only a few visitors know.

匿名 说...

The activities all others has been doing with regards to swimwear and the thing youought to do totally different. [url=http://bikini-wholesale.webnode.com/]China bikini[/url] The reason none of us is chatting about bikini and as a result things one ought to do this afternoon. [url=http://wholesale-swimwear1.webnode.com/]wholesale swimwears[/url] Efficient report demonstrates to you the workings for swimwear coupled with something that one want to do right away. [url=http://china-swimwears.webnode.com/]plus size swimwear[/url] What professionals aren't explaining about swimwear as well as how it has an effect on you. [url=http://fashion-bikinis.webnode.com/]ladies swimwears[/url] Extraordinary summary supplies the run data on bikini which experts state just some persons know of.
The best fix for the swimwear you can read about now.[url=http://micro-bikini.webnode.com/]micro bikini[/url] Brief statement clearly shows the undeniable details about bikini and in what way it could influence on anyone. [url=http://bikini-models.webnode.com/]bikini contest[/url] Progressive publishing clearly shows the low down upon swimwear and reasons why must take action as we speak. [url=http://sheer-bikini.webnode.com/]sheer bikini[/url] The actual fundamentals of bikini it is possible to profit by beginning today. [url=http://thong-bikini.webnode.com/]bikini beach[/url] Honest article discloses Six great new things regarding swimwear that none is covering. [url=http://extreme-bikini.webnode.com/]slingshot bikini[/url] Fresh new queries about bikini clarified and therefore the reasons why you have got to read through each and every statement in this article.

匿名 说...

The reason noone is preaching about swimwear and as a result something that one ought to execute right away. [url=http://high-waisted-swimwear.webnode.com/]freya swimwear[/url] What pros won't be implying over swimwear and ways this is relevant to you actually. [url=http://discount-swimwear.webnode.com/]women swimwear[/url] Methods to comprehend every little thing there is to find out surrounding swimwear in eight uncomplicated steps. [url=http://modest-swimwear8.webnode.com/]modest swimwear[/url] Recent commentary reveal the intel on swimwear and as a result reasons why must take action right now. [url=http://blanca-swimwear.webnode.com/]blanca swimwear[/url] The best ways to understand everything that there is to learn relating to swimwear in A couple of easy ways. [url=http://girls-swimwear0.webnode.com/]mens swimwear[/url]
Whatever the pros are never thinking regarding swimwear and the way this is affecting you. [url=http://string-bikini.webnode.com/]mini bikini[/url] Whatever the pros are generally not saying in relation to swimwear in a manner that it can affect you actually. [url=http://mini-bikini.webnode.com/]mini bikini[/url] Whoa, awesome item. Your corporation got to find out more about swimwear immediately while it's still in store . . . [url=http://swimwear-bikinis.webnode.com/]swimwear[/url] The swimwear-competitors Does not Want You To Check Out Thes advices [url=http://women-bikinis.webnode.com/]women swimwear[/url] What Every person Should Know Regarding swimwear Web business [url=http://plus-size-swimwear3.webnode.com/]women swimwear[/url]