linux内核:__user,__kernel,__safe,__force,__iomem
首先看一下linux内核4.20.1源码:
linux/linux/compile_types.h
# define __user __attribute__((noderef, address_space(1)))
# define __kernel __attribute__((address_space(0)))
# define __safe __attribute__((safe))
# define __force __attribute__((force))
# define __nocast __attribute__((nocast))
# define __iomem __attribute__((noderef, address_space(2)))
# define __must_hold(x) __attribute__((context(x,1,1)))
# 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)
# define __percpu __attribute__((noderef, address_space(3)))
# define __rcu __attribute__((noderef, address_space(4)))
# define __private __attribute__((noderef))
引出Sparse
Sparse 诞生于 2004 年, 是由linux之父开发的, 目的就是提供一个静态检查代码的工具, 从而减少linux内核的隐患. 其实在Sparse之前, 已经有了一个不错的代码静态检查工具("SWAT"), 只不过这个工具不是免费软件, 使用上有一些限制.所以 linus 还是自己开发了一个静态检查工具.(参考,原文)
Sparse通过 gcc 的扩展属性 __attribute__ 以及自己定义的 __context__ 来对代码进行静态检查.
宏名称 |
宏定义 |
检查点 |
__bitwise | __attribute__((bitwise)) | 确保变量是相同的位方式(比如 bit-endian, little-endiandeng) |
__user | __attribute__((noderef, address_space(1))) | 指针地址必须在用户地址空间 |
__kernel | __attribute__((noderef, address_space(0))) | 指针地址必须在内核地址空间 |
__iomem | __attribute__((noderef, address_space(2))) | 指针地址必须在设备地址空间 |
__safe | __attribute__((safe)) | 变量可以为空 |
__force | __attribute__((force)) | 变量可以进行强制转换 |
__nocast | __attribute__((nocast)) | 参数类型与实际参数类型必须一致 |
__acquires(x) | __attribute__((context(x, 0, 1))) | 参数x 在执行前引用计数必须是0,执行后,引用计数必须为1 |
__releases(x) | __attribute__((context(x, 1, 0))) | 与 __acquires(x) 相反 |
__acquire(x) | __context__(x, 1) | 参数x 的引用计数 + 1 |
__release(x) | __context__(x, -1) | 与 __acquire(x) 相反 |
__cond_lock(x,c) | ((c) ? ({ __acquire(x); 1; }) : 0) | 参数c 不为0时,引用计数 + 1, 并返回1 |
其中 __acquires(x) 和 __releases(x), __acquire(x) 和 __release(x) 必须配对使用, 否则 Sparse 会给出警告。以上内容来自:https://www.cnblogs.com/wang_yb/p/3575039.html
Sparse 使用方法
__bitwise 的使用
主要作用就是确保内核使用的整数是在同样的位方式下.
在内核代码根目录下 grep -r '__bitwise', 会发现内核代码中很多地方都使用了这个宏.
对于使用了这个宏的变量, Sparse 会检查这个变量是否一直在同一种位方式(big-endian, little-endian或其他)下被使用,
如果此变量在多个位方式下被使用了, Sparse 会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:include/sound/core.h 51行 */
typedef int __bitwise snd_device_type_t;
__user 的使用
如果使用了 __user 宏的指针不在用户地址空间初始化, 或者指向内核地址空间, 设备地址空间等等, Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:arch/score/kernel/signal.c 45行 */
static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
__kernel 的使用
如果使用了 __kernel 宏的指针不在内核地址空间初始化, 或者指向用户地址空间, 设备地址空间等等, Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:arch/s390/lib/uaccess_pt.c 180行 */
memcpy(to, (void __kernel __force *) from, n);
__iomem 的使用
如果使用了 __iomem 宏的指针不在设备地址空间初始化, 或者指向用户地址空间, 内核地址空间等等, Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:arch/microblaze/include/asm/io.h 22行 */
static inline unsigned char __raw_readb(const volatile void __iomem *addr)
__safe 的使用
使用了 __safe修饰的变量在使用前没有判断它是否为空(null), Sparse会给出警告.
我参考的内核版本(v2.6.32.61) 中的所有内核代码都没有使用 __safe, 估计可能是由于随着gcc版本的更新,
gcc已经会对这种情况给出警告, 所以没有必要用Sparse去检查了.
__force 的使用
使用了__force修饰的变量可以进行强制类型转换, 没有使用 __force修饰的变量进行强制类型转换时, Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:arch/s390/lib/uaccess_pt.c 180行 */
memcpy(to, (void __kernel __force *) from, n);
__nocast 的使用
使用了__nocast修饰的参数的类型必须和实际传入的参数类型一致才行,否则Sparse会给出警告.
内核代码中的例子:
/* 内核版本:v2.6.32.61 file:fs/xfs/support/ktrace.c 55行 */
ktrace_alloc(int nentries, unsigned int __nocast sleep)
__acquires __releases __acquire __release的使用
这4个宏都是和锁有关的, __acquires 和 __releases 必须成对使用, __acquire 和 __release 必须成对使用, 否则Sparse会给出警告.
Sparse 在编译内核中的使用
用 Sparse 对内核进行静态分析非常简单.
# 检查所有内核代码
make C=1 检查所有重新编译的代码
make C=2 检查所有代码, 不管是不是被重新编译
补充
Sparse除了能够用在内核代码的静态分析上, 其实也可以用在一般的C语言程序中.
比如下面的小例子:
/******************************************************************************* @file : sparse_test.c* @author : wangyubin* @date : Fri Feb 28 16:33:34 2014* * @brief : 测试 sparse 的各个检查点* history : init******************************************************************************/#include <stdio.h>#define __acquire(x) __context__(x,1)
#define __release(x) __context__(x,-1)int main(int argc, char *argv[])
{int lock = 1;__acquire(lock);/* TODO something */__release(lock); /* 注释掉这一句 sparse 就会报错 */return 0;
}
如果安装了 Sparse, 执行静态检查的命令如下:
$ sparse -a sparse_test.c
sparse_test.c:15:5: warning: context imbalance in 'main' - wrong count at exit
以上内容来自:https://www.cnblogs.com/wang_yb/p/3575039.html,在此鸣谢。
linux内核:__user,__kernel,__safe,__force,__iomem相关推荐
- linux内核__force,Linux内核学习:I2C_SLAVE_FORCE
在Linux内核源代码include/linux/i2c-dev.h文件内,有如下定义: #define I2C_SLAVE0x0703/* Use this slave address */ #de ...
- Linux 内核中的宏定义
Linux 内核中的宏定义 rtoax 日期 内核版本:linux-5.10.13 注释版代码:https://github.com/Rtoax/linux-5.10.13 __attribute__ ...
- Linux内核概念:per-CPU,cpumask,inicall机制,通知链
Linux内核概念 per-CPU,cpumask,inicall机制,通知链 rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 1. Per-cpu 变 ...
- Linux内核IO追踪:用GDB调试,一个磁盘IO的流程是什么样的
Table of Contents 构建内核 产生IO写入的程序 追踪到兔子洞 准备步骤 进入FS层:我正在使用的fs是XFS 潜入块层 进入块驱动程序层:我的块驱动程序是SCSI 回到fs层,研究内 ...
- Linux内核同步:RCU
linux内核 RCU机制详解 简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的 ...
- linux内核网络协议栈--监控和调优:发送数据(三十)
译者序 本文翻译自 2017 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Sending Data.如果能看懂英文,建议阅读原 ...
- Linux内核访问外设I O资源的方式
首先介绍一下I/O端口和I/O内存. 1. I/O端口:当一个寄存器或内存位于I/O空间时,称其为I/O端口. 2. I/O内存:当一个寄存器或内存位于内存空间时,称其为I/O内存. 再来看一下I/O ...
- linux内核中的copy_to_user和copy_from_user(一)
linux内核中的copy_to_user和copy_from_user(一) 2017年12月21日 20:07:32 prike 阅读数:4768 linux内核中的copy_to_user和co ...
- 一文讲解Linux内核中根文件系统挂载流程
根文件系统的概念 根文件系统是控制权从linux内核转移到用户空间的一个桥梁.linux内核就类似于一个黑匣子,只向用户提供各种功能的接口,但是功能的具体实现不可见,用户程序通过对这些功能接口的不同整 ...
最新文章
- 【Qt】Qt再学习(五):HTTP Example(HTTP下载文件的示例)
- NR 5G MAC媒体接入控制
- 为什么软件开发周期是预估的2~3倍?
- java metrics 简书_Spring Boot Metrics
- c语言编简单博弈小游戏,[2018年最新整理]实验二:利用α-β搜索过程的博弈树搜索算法编写一字棋游戏.doc...
- 网易宣布:招30人![免费加入]网易java人才培养计划!
- 数据结构基础(10) --单链表迭代器的设计与实现
- CSS 魔法系列:纯 CSS 绘制各种图形《系列五》
- 如何卸载自己手机上的APK文件程序
- preg使用。还是一样,只是个人记录,不放博客园首页
- VC中,如何将十六进制字符串转换为十进制数?
- mysql测评作业指导书_测评作业指导书
- 一个简单的透视游戏的编写
- 计算机词汇怎么背,如何背诵英语词汇更有效?
- 利用JavaScript实现BMI指数计算
- 数学中常见的maxmin,min max
- 服务器硬盘识别不到d盘,windows10系统本地磁盘找不到d盘如何解决
- 百度地图JS版本API常见问题
- SPI-flash模拟U盘
- 什么是以太坊大都会:终极指南
热门文章
- Docker的Hadoop-Hbase的 Docker Hub文档
- Java语言基础1-关键字、标识符、常量和变量
- (备忘)卸载微软自带输入法
- 使用Python编写简单网络爬虫抓取视频下载资源
- Windows进程同步之事件内核对象(Event)
- 转载 OAuth认证协议原理分析及使用方法
- Windows SharePoint Services To Be Open Source With 2007 Microsoft Office Release
- 6-Spring Boot缓存管理
- html合并标记,在合并期间在HTML标记之间拉取特定的(文本)间隔
- oracle创建联机重做日志,oracle联机重做日志文件管理!