解决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选项,问题即可解决。

留下此记录,方便后来人,可能的话,如果解决了你的问题,还请点个赞,谢谢!

posted @ 2025-04-06 11:58  Lthis  阅读(82)  评论(0)    收藏  举报