解决LKM编译报错:include/linux/compiler_types.h:258:20: warning: ‘asm’ operand 2 probably does not match constraints
转载注明出处,谢谢!
背景交代
在进行linux LKM(Loadable Kernel Module)开发过程中,make时发生了莫名奇妙的报错。
该报错问题拦了我3个小时,主要原因在于,报错代码不是我的代码,而是报系统源码的问题,报错内容如下:
CC [M] /root/mysrc/testproject/testproject_main.o
In file included from ./include/linux/filter.h:25,
from ./include/net/sock.h:59,
from ./include/linux/tcp.h:19,
from /root/mysrc/testproject/testproject_main.c:8:
./include/net/sch_generic.h: In function ‘qdisc_cb_private_validate’:
./include/net/sch_generic.h:508:30: warning: unused variable ‘qcb’ [-Wunused-variable]
508 | struct qdisc_skb_cb *qcb;
| ^~~
In file included from <command-line>:
./include/linux/thread_info.h: In function ‘copy_overflow’:
././include/linux/compiler_types.h:258:20: warning: ‘asm’ operand 2 probably does not match constraints
258 | #define asm_inline asm __inline
| ^~~
./arch/x86/include/asm/bug.h:27:9: note: in expansion of macro ‘asm_inline’
27 | asm_inline volatile("1:\t" ins "\n" \
| ^~~~~~~~~~
./arch/x86/include/asm/bug.h:82:9: note: in expansion of macro ‘_BUG_FLAGS’
82 | _BUG_FLAGS(ASM_UD2, __flags, ASM_REACHABLE); \
| ^~~~~~~~~~
./include/asm-generic/bug.h:100:17: note: in expansion of macro ‘__WARN_FLAGS’
100 | __WARN_FLAGS(BUGFLAG_NO_CUT_HERE | BUGFLAG_TAINT(taint));\
| ^~~~~~~~~~~~
./include/asm-generic/bug.h:132:17: note: in expansion of macro ‘__WARN_printf’
132 | __WARN_printf(TAINT_WARN, format); \
| ^~~~~~~~~~~~~
./include/linux/thread_info.h:200:9: note: in expansion of macro ‘WARN’
200 | WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
| ^~~~
././include/linux/compiler_types.h:258:20: error: impossible constraint in ‘asm’
258 | #define asm_inline asm __inline
| ^~~
./arch/x86/include/asm/bug.h:27:9: note: in expansion of macro ‘asm_inline’
27 | asm_inline volatile("1:\t" ins "\n" \
| ^~~~~~~~~~
./arch/x86/include/asm/bug.h:82:9: note: in expansion of macro ‘_BUG_FLAGS’
82 | _BUG_FLAGS(ASM_UD2, __flags, ASM_REACHABLE); \
| ^~~~~~~~~~
./include/asm-generic/bug.h:100:17: note: in expansion of macro ‘__WARN_FLAGS’
100 | __WARN_FLAGS(BUGFLAG_NO_CUT_HERE | BUGFLAG_TAINT(taint));\
| ^~~~~~~~~~~~
./include/asm-generic/bug.h:132:17: note: in expansion of macro ‘__WARN_printf’
132 | __WARN_printf(TAINT_WARN, format); \
| ^~~~~~~~~~~~~
./include/linux/thread_info.h:200:9: note: in expansion of macro ‘WARN’
200 | WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
| ^~~~
./include/linux/thread_info.h: In function ‘hook_getdents64’:
././include/linux/compiler_types.h:258:20: warning: ‘asm’ operand 2 probably does not match constraints
258 | #define asm_inline asm __inline
| ^~~
./arch/x86/include/asm/bug.h:27:9: note: in expansion of macro ‘asm_inline’
27 | asm_inline volatile("1:\t" ins "\n" \
| ^~~~~~~~~~
./arch/x86/include/asm/bug.h:82:9: note: in expansion of macro ‘_BUG_FLAGS’
82 | _BUG_FLAGS(ASM_UD2, __flags, ASM_REACHABLE); \
| ^~~~~~~~~~
./include/asm-generic/bug.h:106:17: note: in expansion of macro ‘__WARN_FLAGS’
106 | __WARN_FLAGS(BUGFLAG_ONCE | \
| ^~~~~~~~~~~~
./include/linux/thread_info.h:216:13: note: in expansion of macro ‘WARN_ON_ONCE’
216 | if (WARN_ON_ONCE(bytes > INT_MAX))
| ^~~~~~~~~~~~
make[1]: *** [scripts/Makefile.build:285: /root/mysrc/testproject/testproject_main.o] Error 1
make: *** [Makefile:1875: /root/mysrc/testproject] Error 2
make: Leaving directory '/usr/src/linux-headers-5.15.0-40-generic'
由于是将我的低版本内核代码移植到高版本内核(5.15)后导致的。在花了很多时间解决掉我的代码的移植问题后,我的代码终于不报错了,但诡异的是,系统的源码开始报编译错误。
一开始将报错内容甩给各个AI,无法分析出问题,最后通过二分法确定,是我在调用copy_from_user/copy_to_user的时候才会出现该编译问题。于是查看了该两个函数在5.15中的的定义:
static __always_inline unsigned long __must_check
copy_from_user(void *to, const void __user *from, unsigned long n)
{
if (likely(check_copy_size(to, n, false)))
n = _copy_from_user(to, from, n);
return n;
}
static __always_inline unsigned long __must_check
copy_to_user(void __user *to, const void *from, unsigned long n)
{
if (likely(check_copy_size(from, n, true)))
n = _copy_to_user(to, from, n);
return n;
}
这两个函数都是强制内联+必须检查返回值。根据这些信息再次跟AI多轮沟通,最终给到我两个原因。
可能的原因
内存访问越界:copy_from_user 和 copy_to_user 函数在复制数据时,若源地址或者目标地址无效,或者复制的长度超出了可用内存范围,就会引发错误。
编译器优化问题:编译器对内联汇编代码进行优化时,可能会产生不匹配的约束。
对于第一个原因,我这边对函数的参数和返回值都通过if判断进行了合理性检查,所以排除。
那就剩下编译器优化问题,我的项目是LKM,所以编译规则都放在Makefile里,我的Makefile如下:
obj-m := testproject.o
CC = gcc -ggdb -O0
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
而问题就出在编译上面,由于我要进行LKM调试,所以打开了调试选项,并且禁止优化(-O0)。
这种情况下,在调用被"__always_inline"修饰的函数的时候会因为强制内联时汇编代码不匹配从而报错。所以,关闭掉-O0选项,问题即可解决。
留下此记录,方便后来人,可能的话,如果解决了你的问题,还请点个赞,谢谢!