Linux内核源码分析(1)——compiler.h分析(1)

Linux的内核源码都会包含文件linux\compile.h,所以先分析该文件内的内容,作为开篇。

       

1 汇编编译时不定义的内容

       该文件的第一个内容是对宏__ASSEMBLY__的判断,这个宏的作用是避免在进行汇编编译的时候,不定义后续相关内容。这个宏通过在编译器中用-D选项中加入,参数AFLAGS也包含该宏定义。在汇编时编译器会定义__ASSEMBLY__为1。


#ifndef __ASSEMBLY__


1.1 Sparse工具检测使用的属性定义

       接下来是__CHECKER__宏的判断,__CHECKER__宏在通过Sparse(Semantic Parser for C)工具对内核代码进行检查时会定义的。在使用make C=1或C=2时便会调用该工具,这个工具可以检查在代码中声明了sparse所能检查到的相关属性的内核函数和变量。


#ifdef __CHECKER__


       下面分析一下sparse所能检查的相关属性。


# define __user                __attribute__((noderef, address_space(1)))

# define __kernel        /* default address space */

# define __safe                __attribute__((safe))

# define __force        __attribute__((force))

# define __nocast        __attribute__((nocast))

# define __iomem        __attribute__((noderef, address_space(2)))

# define __acquires(x)        __attribute__((context(x,0,1)))

# define __releases(x)        __attribute__((context(x,1,0)))

# define __acquire(x)        __context__(x,1)

# define __release(x)        __context__(x,-1)

# define __cond_lock(x,c)        ((c) ? ({ __acquire(x); 1; }) : 0)

extern void __chk_user_ptr(const volatile void __user *);

extern void __chk_io_ptr(const volatile void __iomem *);


__user特性用来修饰一个变量的地址,该变量必须是非解除参考(no dereference)即地址是有效的,并且变量所在的地址空间必须为1,这里为(address_space(1)),用户地址空间。sparse把地址空间分为3部分,0表示普通地址空间,对内核来说就是地址空间。1表示用户地址空间。2表示设备地址映射空间,即设备寄存器的地址空间。

__kernel特性修饰变量为内核地址,为内核代码里面默认的地址空间。

__safe特性声明该变量为安全变量,这是为了避免在内核函数未对传入的参数进行校验就使用的情况下,会导致编译器对其报错或输出告警信息。        通过该特性说明该变量不可能为空。

__force特性声明该变量是可以强制类型转换的。

__nocast声明该变量参数类型与实际参数类型要一致才可以。

__iomem声明地址空间是设备地址映射空间,其他的与__user一样。

__acquires为函数属性定义的修饰,表示函数内,该参数的引用计数值从1变为0。

__releases与__acquires相反,这一对修饰符用于Sparse在静态代码检测时,检查调用的次数和匹配请求,经常用于检测lock的获取和释放。

__acquire表示增加变量x的计数,增加量为1。

__release表示减少变量x的计数,减少量为1。这一对与上面的那一对是一样,只是这一对用在函数的执行过程中,都用于检查代码中出现不平衡的状况。

 __cond_lock用于表示条件锁,当c这个值不为0时,计数值加1,并返回1。

__chk_user_ptr和__chk_io_ptr在这里只声明函数,没有函数体,目的就是在编译过程中Sparse能够捕捉到编译错误,检查参数的类型。

你可能感兴趣的:(Linux内核,linux,Linux,LINUX)