__user宏出现的地方有三处,__kernel宏有两处,但都挨着
静态检查
/ include / linux / compiler_types.h
#ifdef __CHECKER__
/* address spaces */
# define __kernel __attribute__((address_space(0)))
# define __user __attribute__((noderef, address_space(__user)))
这个__CHECKER__宏专门给sparse用的,sparse是一个静态检验代码的工具,这就是个标记用的。
demo
# define __user __attribute__((noderef, address_space(__user)))
# define __kernel __attribute__((noderef, address_space(0)))
int add(char __user *d){
return 0;
}
int main(){
char __user * d;
add(d);
return 0;
}
如果这样写,运行结果如下
pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/_user$ sparse main.c
main.c:7:10: warning: non-ANSI function declaration of function 'main'
main.c:4:5: warning: symbol 'add' was not declared. Should it be static?
pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/_user$ make
gcc main.c
main.c:4:1: warning: ‘noderef’ attribute directive ignored [-Wattributes]
4 | int add(char __user *d){
| ^~~
main.c:4:1: warning: ‘address_space’ attribute directive ignored [-Wattributes]
main.c: In function ‘main’:
main.c:8:9: warning: ‘noderef’ attribute directive ignored [-Wattributes]
8 | char __user * d;
| ^~~~
main.c:8:9: warning: ‘address_space’ attribute directive ignored [-Wattributes]
./a.out
没啥事儿,也能编译过去。
demo
# define __user __attribute__((noderef, address_space(__user)))
# define __kernel __attribute__((noderef, address_space(0)))
int add(char *d){
return 0;
}
int main(){
char __user * d;
add(d);
return 0;
}
运行结果
pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/_user$ sparse main.c
main.c:7:10: warning: non-ANSI function declaration of function 'main'
main.c:4:5: warning: symbol 'add' was not declared. Should it be static?
main.c:9:9: warning: incorrect type in argument 1 (different address spaces)
main.c:9:9: expected char *d
main.c:9:9: got char [noderef] __user *d
pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/_user$ make
gcc main.c
main.c: In function ‘main’:
main.c:8:9: warning: ‘noderef’ attribute directive ignored [-Wattributes]
8 | char __user * d;
| ^~~~
main.c:8:9: warning: ‘address_space’ attribute directive ignored [-Wattributes]
./a.out
看到了吧
main.c:9:9: warning: incorrect type in argument 1 (different address spaces)
main.c:9:9: expected char *d
main.c:9:9: got char [noderef] __user *d
他说这不是正确的类型,因为你实参加了形参没加,但也能编译过去。
demo2
# define __user __attribute__((noderef, address_space(__user)))
# define __kernel __attribute__((noderef, address_space(0)))
int add(char __kernel *d){
return 0;
}
int main(){
char __user * d;
add(d);
return 0;
}
运行结果
pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/_user$ sparse main.c
main.c:7:10: warning: non-ANSI function declaration of function 'main'
main.c:4:5: warning: symbol 'add' was not declared. Should it be static?
main.c:9:9: warning: incorrect type in argument 1 (different address spaces)
main.c:9:9: expected char [noderef] *d
main.c:9:9: got char [noderef] __user *d
pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/_user$ make
gcc main.c
main.c:4:1: warning: ‘noderef’ attribute directive ignored [-Wattributes]
4 | int add(char __kernel *d){
| ^~~
main.c:4:1: warning: ‘address_space’ attribute directive ignored [-Wattributes]
main.c: In function ‘main’:
main.c:8:9: warning: ‘noderef’ attribute directive ignored [-Wattributes]
8 | char __user * d;
| ^~~~
main.c:8:9: warning: ‘address_space’ attribute directive ignored [-Wattributes]
./a.out
pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/_user$
一样的。
说白了就是给开发者提示用的,你这指针指的用户空间,结果你传到内核空间,那肯定有问题。
编译
/ include / linux / compiler_types.h
# define __kernel
# ifdef STRUCTLEAK_PLUGIN
# define __user __attribute__((user))
# else
# define __user BTF_TYPE_TAG(user)
# endif
这一个kernel好解释了,就是啥也不起作用
STRUCTLEAK_PLUGIN 刚查了下,这个好像是gcc的一个插件,如果定义了的话,user宏就变成
# define __user __attribute__((user))
功能基本跟上面1提到的一样。那为啥kernel就给省略了,我猜呀,可能编译时也会去查吧,因为这些变量,除了标记为__user的,其余肯定在内核空间内,因为我们编的就是内核,所以把kernel省略了。
#if defined(CONFIG_DEBUG_INFO_BTF) && defined(CONFIG_PAHOLE_HAS_BTF_TAG) && \
__has_attribute(btf_type_tag) && !defined(__BINDGEN__)
# define BTF_TYPE_TAG(value) __attribute__((btf_type_tag(#value)))
#else
# define BTF_TYPE_TAG(value) /* nothing */
#endif
# define __user BTF_TYPE_TAG(user)
这个跟什么BTF有关,我看了下,基本默认配置时,就把他配置为N,所以基本就是没啥用。
总结
看代码时基本可忽略