在编写一个自己写的gadget驱动的时候遇到一个这样的问题,编译的时候报了个警告:WARNING: "usb_composite_register" […/my_zero.ko] undefined!
告诉我这个函数没有定义,但是生成了ko文件,将这个文件拷贝到开发板目录下insmod,同样也是报这是一个未知的符号:
通常这种问题是因为没有包含函数头文件,这个函数是在linux/usb/composite.c中定义的,在composite.h中声明,因此包含linux/usb/composite.h就可以了…吗?事实上我已经包含了这个头文件。
这个时候我想到了光包含头文件不行啊,还要编译源文件啊。不过我似乎发现一个很奇怪的问题,那就是要编译源文件似乎是理所当然的,但问题是之前写驱动调用的那些函数也没有把它们的源文件放进来编译啊。比如说最开始写驱动的时候一定调用过printk,这个函数在printk.c中定义,但也没见哪条语句指定要把printk.c拿进来编译啊。
查找资料过后发现原来是EXPORT_SYMBOL搞的鬼,就是说使用EXPORT_SYMBOL导出的函数可以被其他内核模块使用,那这是不是说,把usb_composite_register这个函数用EXPORT_SYMBOL导出就可以了呢。我们在内核代码中usb_composite_register这个函数后面用EXPORT_SYMBOL将其导出,然后编译自己的模块,发现还是报相同的警告。难道要重新编译一下内核吗,于是我重新编译了内核,编译内核时它警告我usb_composite_register这个函数在g_serial.o中已经被导出了,但这是一个警告,我想问题应该不大。接下来再编译自己的模块,它就不报警告了。
既然和重新编译内核有关,那自然也要下载新编译的内核了,将新的内核下载进开发板后再insmod我编译的ko文件,结果还是报Unknown symbol usb_composite_register。
再查过资料后发现还有一个关键点我没做到,那就是必须先insmod包含要导出的函数的模块,然鹅查找了composite.c这个文件后发现这个文件里没有module_init,就意味着这不是一个独立的模块,也就没法“先insmod包含要导出的函数的模块”。
连源文件都给了,难道还调不了函数了吗,这怎么可能。我们可以看看内核文件里其他模块都是怎么做的,找到其他的gadget驱动文件,发现他们都比较流弊,是直接#include “composite.c”,直接把c文件包含进来了。这里可能有些朋友比较蒙圈(“只见过包含.h,没见过包含.c啊”),其实只要清楚#include的机制就能理解了。#include的作用是将包含的文件在使用#include处展开,不管是包含.c还是包含.h,都是将被包含的文件里的内容在包含处展开,相当于把被包含的文件里的内容全部复制下来,在#include处粘贴一样。
既然这样,那我也包含composite.c这个文件试试,先将composite.c复制到我自己的驱动目录下,结果一编译又报出几个警告:
那自然的要把包含这些函数的.c文件拿过来编译。发现这几个函数分别是在epautoconf.c、config.c和usbstring.c中定义的,把这些文件拷贝到自己的工作目录下,同时在c文件中包含它们,再编译又报一个找不到gadget_chips.h的错,把这个文件再拷贝到工作目录中,再编译。
最后将生成的ko文件拷贝到开发板工作目录中,再insmod就可以了。
如果嫌把这些文件都拷贝过来太麻烦的话,可以直接在内核代码目录下加入自己的模块,参见:https://www.cnblogs.com/Suzkfly/p/11765883.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?