-
-
利用autoconf自动适配内核函数
-
发表于: 2023-3-31 18:44 13345
-
对于标准内核本身(eb7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6C8k6i4u0F1k6h3I4Q4x3X3g2G2M7X3N6Q4c8f1k6Q4b7V1y4Q4z5o6W2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5e0m8Q4z5p5y4Q4c8e0c8Q4b7U0S2Q4z5o6m8Q4c8e0c8Q4b7U0S2Q4b7f1q4Q4c8e0g2Q4z5o6N6Q4b7V1c8Q4c8e0k6Q4z5e0g2Q4b7U0m8Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0N6Q4b7U0q4Q4b7V1u0Q4c8e0g2Q4z5f1g2Q4z5p5u0Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0k6Q4z5o6S2Q4z5e0k6Q4c8e0S2Q4z5o6m8Q4z5o6g2Q4c8e0g2Q4z5e0m8Q4z5p5y4Q4c8e0c8Q4b7U0S2Q4z5o6m8Q4c8e0c8Q4b7U0S2Q4b7f1q4Q4c8e0N6Q4b7V1u0Q4z5e0y4Q4c8e0k6Q4z5f1g2Q4z5o6c8Q4c8e0c8Q4b7U0S2Q4b7f1c8Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0k6Q4z5o6S2Q4z5e0m8Q4c8e0g2Q4z5e0q4Q4z5e0S2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5f1y4Q4b7e0S2Q4c8e0c8Q4b7U0S2Q4z5p5c8Q4c8e0g2Q4z5e0m8Q4z5p5y4Q4c8e0N6Q4z5o6W2Q4z5o6S2Q4c8e0k6Q4z5f1y4Q4b7f1y4Q4c8e0c8Q4b7U0S2Q4b7f1c8Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5p5k6Q4b7f1k6Q4c8e0S2Q4z5o6y4Q4b7V1c8Q4c8e0k6Q4z5e0S2Q4b7f1k6Q4c8e0k6Q4z5f1y4Q4z5o6W2Q4c8e0g2Q4z5p5k6Q4z5e0S2Q4c8e0g2Q4z5p5y4Q4z5e0k6Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8f1k6Q4b7V1y4Q4z5f1t1`.
操作系统发行厂商(RedHat、Centos、Ubuntu等),会对内核进行backporting,比如CentOS-8.2中的内核版本为4.18.0-193.28.1,其中的DRM内核模块,是从5.3.0内核(版本>4.18.0),backporting过来的。
Autoconf不是根据版本号,而是通过试探性编译,判断函数类型。这样,一方面可以使驱动开发者,只需要关注函数有哪些类型,不需要关注每种类型对应哪些内核版本;另一方面也消除了backporting的问题(比如以上CentOS-8.2的例子,要同时结合内核和系统发行版本,才能确定DRM内核模块的版本,这会使版本判断逻辑十分臃肿)。
很多开源代码,通过执行“./configure; make; make install”,即可完成编译安装,其中,configure脚本执行时,一般会检查当前环境,是否安装了gcc、make等,有时候还会生成一个config.h头文件(内容通常受当前环境的glibc版本等因素影响),这个过程,其实就相当于将源码,动态适配到当前环境。
Configure实质上就是一个shell脚本,由autoconf命令生成,以下引用一张网络上搜索到的图片:
了解各个文件生成过程,只需要顺着依赖关系往回看即可,比如config.h:
可以看出,为了生成config.h,只要提供configure.ac、m4文件,并执行autoreconf命令(相当于aclocal+autoheader+autoconf的组合)即可,并且,如果自定义的宏不多,可以直接写在configure.ac文件,m4文件是可选的。
configure.ac和m4文件,本质上是还未展开的shell脚本,文件内部既可以定义宏,也可以调用宏(和c语言中的宏,概念相同,只不过定义和展开规则不同),这些宏最终都会由autoconf内部执行的m4命令展开,其中,m4程序本身内置了一些宏,autoconf程序也内置了一些专用于生成configure的宏。
m4宏的定义语法和展开规则,可以执行“info autoconf”,或在线查看gnu官方文档。
官方文档:844K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2Y4L8Y4g2Q4x3X3g2G2M7X3N6Q4x3V1k6K6L8$3k6@1N6$3q4J5k6g2)9J5c8X3q4#2N6r3!0U0L8$3&6X3i4K6u0r3L8h3q4F1N6h3q4D9i4K6u0r3j5i4g2@1L8$3y4G2L8X3k6Q4x3X3b7J5i4K6u0W2y4U0m8Q4x3V1k6Z5N6r3#2D9i4K6g2X3L8X3!0V1k6g2)9J5c8X3W2F1k6r3g2^5i4K6u0W2K9s2c8E0L8q4)9J5x3#2c8G2M7l9`.`.
组件关系:377K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3d9X3q4F1L8s2W2Q4x3V1k6H3i4K6u0r3x3e0b7@1x3K6b7&6x3e0c8Q4x3X3g2Z5N6r3#2D9
M4中文教程:84aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6k6h3N6E0k6h3&6@1k6X3q4#2L8s2c8Q4x3X3g2U0L8$3#2Q4x3V1k6S2i4K6u0r3x3e0p5&6x3o6l9H3x3o6l9H3y4o6p5H3y4o6j5&6y4R3`.`.
网上大量的文章,都只介绍了利用autoconf适配glibc函数的方法,但是直接套用于内核函数的适配,会遇到很多问题,面对大量的内置宏和晦涩的m4语法,尝试替换宏和各种写法之后,都没解决,所以最后决定套用rocm(AMD显卡驱动)代码中的用法。
附件中的打包文件,是对rocm驱动中dkms目录的简化:
首先是删除了m4目录中大量的.m4文件(access-ok.m4也可以删除,保留只是为了测试是否能正确检查access_ok()内核函数的类型),其次是抽离使用会报一些错误,所以还注释了pre-build.sh脚本中的一些片段,kernel.m4和sources文件也被注释了一些内容,具体修改可以通过diff等工具对比。
dkms.conf也可以删掉,它用于内核升级后,自动触发autoconf,以及后续的驱动编译、加载,和autoconf属性完全独立的功能,但在开源驱动中,经常结合autoconf一起使用。
Autoconf只是用于生成Makefile、config.h,至于何时触发,以及根据config.h对驱动进行重新编译、加载,就是通过dkms完成,不难理解。
使用:564K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2y4e0q4U0N6r3!0Q4x3X3g2U0L8$3#2Q4x3V1k6%4L8%4y4Z5K9i4W2#2x3o6l9I4i4K6u0r3x3U0V1#2x3U0f1&6y4R3`.`.
原理:1b9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8Y4N6W2K9i4S2A6L8W2)9#2k6U0x3@1y4U0t1$3x3K6l9$3i4K6u0r3j5i4u0@1K9h3y4D9k6g2)9J5c8X3c8W2N6r3q4A6L8s2y4Q4x3V1j5I4x3e0t1I4x3o6V1^5y4o6V1`.
github:affK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6V1k6h3I4D9i4K6u0r3k6r3E0E0M7H3`.`.
知乎大佬兰新宇的指导:
以及他的文章:527K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0f1%4x3o6t1I4z5o6t1%4x3R3`.`.
config.h
|
-
configure脚本
| |
-
configure.ac
| |
-
aclocal.m4
| | |
-
自定义的m4文件
# 所在目录通过AC_CONFIG_MACRO_DIR宏指定
| | |
-
aclocal命令
| |
-
autoconf命令
|
-
config.h.
in
|
-
AC_DEFINE宏
# 根据configure.ac,最终展开过AC_DEFINE宏
|
-
autoheader命令
赞赏
- shell+Makefile,坑我晚下班 2228
- 调试器:显示调用栈 2740
- helloworld减肥 + 单步执行原理 3034
- gcc -O2编译,gdb单步执行怪怪的 10486
- systemtap追踪自己开发的内核模块 11886