当前位置: 首页 > article >正文

正点原子2026开发板教程——从0开始配置Linux内核(4)内核模块详解:从 Hello World 到设备驱动

正点原子2026开发板教程——从0开始配置Linux内核4内核模块详解从 Hello World 到设备驱动为什么要写这一章这块跟移植关系不大是桥接到后续驱动编写的。后面准备更新Rootfs。前面我们花了三章的篇幅把 Linux 内核从哪里来、怎么编译、设备树是什么都讲清楚了。你可能觉得好了现在我对内核有认识了可以开始写驱动了吧但这里有一个坎儿你写的代码怎么放进内核里传统的做法是把代码直接编进内核镜像。这种方式有几个问题一是每次修改都要重新编译整个内核耗时漫长二是代码会一直占用内存即使用不到三是调试不方便出错可能导致整个系统起不来。有没有一种方式可以让代码在需要的时候加载不用的时候卸载修改后也不需要重编内核答案就是——内核模块。说实话我刚接触内核模块的时候也有点懵。明明就是 C 代码为什么不能直接编译成普通程序运行为什么必须用特殊的宏为什么 insmod 的时候提示 “unknown symbol”这些坑我都踩过而且不止一次。所以这一章我们手把手地从零开始写一个内核模块搞清楚它是什么、怎么编译、怎么加载卸载、怎么传参数、怎么处理依赖关系。当你把这些都弄明白了后面的设备驱动开发就是顺水推舟的事情。内核模块是什么为什么需要它模块 vs 静态编译Linux 内核有两种代码组织方式静态编译和模块化编译。静态编译就是把代码直接编进内核镜像vmlinux/zImage。系统启动时这些代码就驻留在内存里了。比如你查看一下/proc/kallsyms里面列出的就是内核里所有符号函数和变量的地址。cat/proc/kallsyms|head-20输出类似这样00000000 T startup_64 00000000 T _text ffffffff81000000 T _stext ...这些符号大部分是静态编入内核的代码。模块化编译则是把代码编译成独立的 .koKernel Object文件运行时通过insmod或modprobe加载到内核空间。模块加载后它的符号会被注册到内核的符号表里就像它本来就在内核里一样。模块的好处模块化设计有几个明显的好处动态加载。用不到的功能可以不加载节省内存。比如你开发板上可能没有 SCSI 设备那 SCSI 驱动模块就不需要加载。这在资源受限的嵌入式系统上很重要。快速迭代。开发驱动时每次修改代码只需要重新编译模块然后rmmod旧模块、insmod新模块。这比每次都重编内核快太多了。我记得我第一次碰驱动大概就几秒钟吧LED的驱动更简单我还没反应过来编完了。内核可就不好说了笑安全隔离。模块有 BUG 导致内核崩溃的概率比静态代码低因为模块可以选择性加载出问题时更容易定位。闭源兼容。有些厂商的驱动是闭源的必须以模块形式提供虽然这不是内核社区鼓励的做法嗯。模块的局限性当然模块也不是万能的启动前依赖。如果某个设备是系统启动必需的比如根文件系统所在的存储设备它的驱动就不能是模块必须静态编入内核。性能开销。模块加载/卸载有开销虽然不大但对性能敏感的场景可能需要注意。符号依赖。模块只能调用内核导出的符号不能直接访问内核内部的静态函数。手写一个 Hello World 模块好了理论讲够了。我们来写一个最简单的内核模块。创建工作目录首先在合适的地方创建一个目录来存放模块代码mkdir-p~/kernel-module-tutorialcd~/kernel-module-tutorial编写模块源码创建hello.c文件#includelinux/init.h// __init __exit 宏定义#includelinux/module.h// module_init module_exit 等核心宏#includelinux/printk.h// pr_info printk// 模块加载时执行的函数staticint__inithello_init(void){// 使用 pr_info 而不是 printk更简洁pr_info(Hello, kernel module!\n);return0;}// 模块卸载时执行的函数staticvoid__exithello_exit(void){pr_info(Goodbye, kernel module!\n);}// 注册初始化和清理函数module_init(hello_init);module_exit(hello_exit);// 模块元信息MODULE_LICENSE(GPL);MODULE_AUTHOR(Your Name your.emailexample.com);MODULE_DESCRIPTION(A simple hello world kernel module);MODULE_VERSION(1.0);踩坑提醒一定要包含MODULE_LICENSE(GPL)否则内核会认为你的模块是被污染的tainted某些功能会受限。而且使用 GPL 以外的许可证你不能访问某些只有 GPL 模块才能用的内核符号。编写 Makefile内核模块的编译和普通程序不同它需要使用内核的构建系统。创建一个Makefile# 模块名称 obj-m hello.o # 获取当前运行的内核构建目录 KDIR : /lib/modules/$(shell uname -r)/build # 当前目录 PWD : $(shell pwd) # 默认目标构建模块 all: $(MAKE) -C $(KDIR) M$(PWD) modules # 清理编译产物 clean: $(MAKE) -C $(KDIR) M$(PWD) clean注意Makefile 里的缩进必须是Tab不能是空格这是 Makefile 的语法要求用空格会报错 “missing separator”。编译模块现在可以编译了make你应该能看到类似这样的输出make -C /lib/modules/6.8.0-48-generic/build M/home/charliechen/kernel-module-tutorial modules make[1]: Entering directory /usr/src/linux-headers-6.8.0-48-generic CC [M] /home/charliechen/kernel-module-tutorial/hello.o MODPOST /home/charliechen/kernel-module-tutorial/Module.symvers CC [M] /home/charliechen/kernel-module-tutorial/hello.mod.o LD [M] /home/charliechen/kernel-module-tutorial/hello.ko BTF [M] /home/charliechen/kernel-module-tutorial/hello.ko make[1]: Leaving directory /usr/src/linux-headers-6.8.0-48-generic编译成功后当前目录下会出现几个文件hello.o目标文件hello.ko内核模块文件这就是我们需要的hello.mod.o、hello.mod.c模块版本信息相关Module.symvers符号导出文件.hello.ko.cmd等隐藏文件编译过程记录加载和卸载模块现在来加载模块sudoinsmod hello.ko如果一切正常命令没有任何输出。那怎么知道模块加载成功了查看内核日志sudodmesg|tail-5你应该能看到[ 1234.567890] Hello, kernel module!你也可以用lsmod命令查看已加载的模块lsmod|grephello输出hello 16384 0这表示hello模块已加载大小是 16384 字节16KB被引用次数是 0。现在来卸载模块sudormmod hello再查看日志sudodmesg|tail-5你应该能看到[ 1235.678901] Goodbye, kernel module!恭喜你已经成功完成了第一个内核模块的编写、编译、加载和卸载。交叉编译为目标板编译模块刚才的编译是针对你当前运行的开发机的。但我们的目标是 i.MX6ULL 开发板它用的是 ARM 架构需要交叉编译。准备交叉编译环境首先确保你有 ARM 交叉编译工具链arm-none-linux-gnueabihf-gcc--version应该能输出版本信息。准备内核源码交叉编译模块时需要访问目标架构的内核源码或头文件。你不需要完整编译一遍内核但至少要有内核源码树和配置好的.config。假设你内核源码在~/linux-imx输出目录在~/linux-imx-build# 确保内核已经配置过cd~/linux-imxmakeO~/linux-imx-buildARCHarmCROSS_COMPILEarm-none-linux-gnueabihf- imx_aes_defconfig修改 Makefile 用于交叉编译回到模块目录修改Makefileobj-m hello.o # 交叉编译相关变量 ARCH : arm CROSS_COMPILE : arm-none-linux-gnueabihf- # 内核源码目录根据你的实际路径修改 KDIR : ~/linux-imx # 输出目录 MODDIR : ~/linux-imx-build # 当前目录 PWD : $(shell pwd) all: $(MAKE) -C $(KDIR) ARCH$(ARCH) CROSS_COMPILE$(CROSS_COMPILE) O$(MODDIR) M$(PWD) modules clean: $(MAKE) -C $(KDIR) ARCH$(ARCH) CROSS_COMPILE$(CROSS_COMPILE) O$(MODDIR) M$(PWD) clean重新编译makecleanmake这次生成的hello.ko就是 ARM 架构的模块了。你可以验证一下filehello.ko输出应该显示hello.ko: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV) ...在开发板上测试把模块传到开发板通过 TFTP、NFS 或 SD 卡然后在开发板上加载insmod hello.ko查看日志dmesg|tail你应该能看到熟悉的 “Hello, kernel module!” 输出。模块参数传递硬编码的模块不太实用。更多时候我们希望能在加载模块时传递参数让模块行为更灵活。添加模块参数修改hello.c添加参数支持#includelinux/init.h#includelinux/module.h#includelinux/printk.h#includelinux/moduleparam.h// module_param 宏// 定义一个整型参数默认值 0staticintcount0;// 参数名、类型、权限S_IRUGO 表示所有用户可读module_param(count,int,S_IRUGO);MODULE_PARM_DESC(count,Number of times to print hello);// 定义一个字符串参数默认值 worldstaticchar*nameworld;module_param(name,charp,S_IRUGO);MODULE_PARM_DESC(name,Who to say hello to);// 定义一个布尔型参数默认值 falsestaticbool verbosefalse;module_param(verbose,bool,S_IRUGO);MODULE_PARM_DESC(verbose,Enable verbose output);staticint__inithello_init(void){inti;if(verbose){pr_info(Module parameters: count%d, name%s, verbose%d\n,count,name,verbose);}for(i0;icount;i){pr_info(Hello, %s! (#%d)\n,name,i1);}if(count0){pr_info(Hello, %s!\n,name);}return0;}staticvoid__exithello_exit(void){pr_info(Goodbye, %s!\n,name);}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE(GPL);MODULE_AUTHOR(Your Name your.emailexample.com);MODULE_DESCRIPTION(A hello world module with parameters);MODULE_VERSION(1.0);参数类型说明module_param宏支持这些类型类型C 类型说明intint整型shortshort短整型uintunsigned int无符号整型ushortunsigned short无符号短整型longlong长整型ulongunsigned long无符号长整型charpchar *字符串指针boolbool / int布尔型权限标志权限标志定义了谁可以通过/sys/module访问这个参数// S_IRUGO所有用户可读module_param(count,int,S_IRUGO);// S_IWUSR只有 root 可写module_param(count,int,S_IWUSR);// S_IRUGO | S_IWUSR所有用户可读root 可写module_param(count,int,S_IRUGO|S_IWUSR);常用权限常量常量值含义S_IRUSR0400所有者可读S_IWUSR0200所有者可写S_IRGRP0040组用户可读S_IWGRP0020组用户可写S_IROTH0004其他用户可读S_IWOTH0002其他用户可写S_IRUGO0444所有用户可读S_IWUGO0222所有用户可写加载时传递参数重新编译模块然后加载时传递参数# 使用默认参数sudoinsmod hello.ko# 指定 countsudoinsmod hello.kocount3# 指定 namesudoinsmod hello.konameKernel# 同时指定多个参数sudoinsmod hello.kocount5nameWorldverbose1查看日志sudodmesg|tail-10运行时查看和修改参数模块加载后可以通过/sys/module查看和修改参数# 查看模块参数目录ls-la/sys/module/hello/parameters/# 查看参数值cat/sys/module/hello/parameters/countcat/sys/module/hello/parameters/namecat/sys/module/hello/parameters/verbose# 修改参数如果权限允许sudosh-cecho 10 /sys/module/hello/parameters/count注意修改参数是否生效取决于模块代码如何使用参数。有些参数只在初始化时读取后续修改不会影响行为。模块依赖管理实际开发中模块之间往往有依赖关系。比如一个网络设备驱动模块可能依赖于通用 PHY 层模块。这时候加载顺序就很重要。查看模块依赖用modinfo命令查看模块信息modinfo hello.ko输出类似filename: /home/charliechen/kernel-module-tutorial/hello.ko version: 1.0 description: A hello world module with parameters author: Your Name your.emailexample.com license: GPL srcversion: XXXXXXXXXXXXXXXXXXXX depends: retpoline: Y name: hello vermagic: 6.8.0-48-generic SMP mod_unload modversions aarch64depends字段显示了这个模块依赖的其他模块。我们的 hello 模块没有依赖所以是空的。导出符号让模块提供 API如果一个模块想提供函数给其他模块使用需要导出符号。模块 A导出符号创建provider.c#includelinux/init.h#includelinux/module.h#includelinux/printk.h// 导出一个函数intprovider_add(inta,intb){pr_info(provider_add: %d %d %d\n,a,b,ab);returnab;}EXPORT_SYMBOL(provider_add);// 导出一个变量intprovider_counter0;EXPORT_SYMBOL(provider_counter);staticint__initprovider_init(void){pr_info(Provider module loaded\n);return0;}staticvoid__exitprovider_exit(void){pr_info(Provider module unloaded\n);}module_init(provider_init);module_exit(provider_exit);MODULE_LICENSE(GPL);模块 B使用导出的符号创建consumer.c#includelinux/init.h#includelinux/module.h#includelinux/printk.h// 声明外部符号externintprovider_add(inta,intb);externintprovider_counter;staticint__initconsumer_init(void){intresult;pr_info(Consumer module loaded\n);resultprovider_add(10,20);pr_info(Result from provider: %d\n,result);pr_info(Provider counter: %d\n,provider_counter);return0;}staticvoid__exitconsumer_exit(void){pr_info(Consumer module unloaded\n);}module_init(consumer_init);module_exit(consumer_exit);MODULE_LICENSE(GPL);更新 Makefileobj-m provider.o obj-m consumer.o KDIR : /lib/modules/$(shell uname -r)/build PWD : $(shell pwd) all: $(MAKE) -C $(KDIR) M$(PWD) modules clean: $(MAKE) -C $(KDIR) M$(PWD) clean编译和测试makesudoinsmod provider.kosudoinsmod consumer.kosudodmesg|tail-10加载顺序错误会怎样如果你先加载consumer会报错sudormmod provider consumer# 先卸载sudoinsmod consumer.ko输出insmod: ERROR: could not insert module consumer.ko: Unknown symbol查看详细错误sudodmesg|tail你会看到consumer: Unknown symbol provider_add (err 0) consumer: Unknown symbol provider_counter (err 0)这就是符号依赖consumer需要provider导出的符号但provider还没加载。modprobe自动处理依赖insmod不会自动处理依赖但modprobe会。sudormmod consumer providersudomodprobe consumermodprobe会自动分析依赖先加载provider再加载consumer。卸载时也类似sudomodprobe-rconsumermodprobe -r会自动卸载不再被依赖的模块比如provider。依赖信息存储模块的依赖信息存储在/lib/modules/$(uname -r)/modules.dep文件中cat/lib/modules/$(uname-r)/modules.dep|grepprovider这个文件是在安装内核模块时由depmod -a命令生成的。你自己编译的模块不在系统目录里所以modprobe可能找不到。解决方法是把模块.ko文件复制到/lib/modules/$(uname -r)/extra/然后运行sudo depmod -a。模块信息查看命令我们总结一下常用的模块管理命令lsmod列出已加载模块lsmod输出格式Module Size Used by hello 16384 0 provider 20480 1 consumer consumer 16384 0 ...Module模块名Size模块占用内存大小字节Used by被引用次数以及被哪些模块引用modinfo查看模块信息modinfo hello.ko# 查看未加载的模块modinfo hello# 查看已加载的模块depmod生成模块依赖sudodepmod-a# 重新生成所有模块的依赖信息sudodepmod-n# 只显示不实际写入文件modprobe智能加载/卸载模块sudomodprobe hello# 加载模块自动处理依赖sudomodprobe-rhello# 卸载模块自动卸载不再需要的依赖sudomodprobe hellocount5# 加载并传递参数insmod/rmmod手动加载/卸载sudoinsmod hello.ko# 加载模块不处理依赖sudoinsmod hello.kocount5# 加载并传递参数sudormmod hello# 卸载模块模块调试技巧查看内核日志sudodmesg# 查看所有日志sudodmesg|tail-20# 查看最近 20 行sudodmesg|grep-ihello# 过滤包含 hello 的日志sudodmesg-c# 清空日志实时监控日志sudodmesg-w# 持续监控新日志# 或sudojournalctl-kf# 使用 systemd journal查看模块符号cat/proc/kallsyms|grephello查看模块参数ls/sys/module/hello/parameters/cat/sys/module/hello/parameters/count动态调试dynamic debug如果你的模块使用pr_debug()或dev_dbg()打印调试信息可以通过 dynamic debug 动态控制# 启用某个模块的所有调试信息sudoechomodule hello p/sys/kernel/debug/dynamic_debug/control# 启用某个文件的所有调试信息sudoechofile hello.c p/sys/kernel/debug/dynamic_debug/control# 启用某个函数的所有调试信息sudoechofunc hello_init p/sys/kernel/debug/dynamic_debug/control# 查看当前调试设置sudocat/sys/kernel/debug/dynamic_debug/control|grephello常见错误排查“Invalid module format”这个错误通常表示模块和内核版本不匹配。可能是编译模块时用的内核源码和运行中的内核版本不一致交叉编译时架构不匹配解决方法uname-r# 查看当前内核版本modinfo hello.ko# 查看模块编译的内核版本vermagic 字段“Unknown symbol”表示模块依赖的符号不存在。可能是依赖的模块没有加载依赖的符号没有被导出内核配置问题该符号没有编入内核解决方法# 查看缺失的符号名称sudodmesg|tail# 搜索符号在哪个模块grep-rmissing_symbol_name/lib/modules/$(uname-r)/“Operation not permitted”表示权限不足。确保使用sudo加载/卸载模块。“Device or resource busy”表示模块正被使用Used by 0无法卸载。先查看谁在使用lsmod|grepmodule_name先卸载依赖它的模块再卸载它。写在最后到这里你应该对内核模块有了全面的认识。从简单的 Hello World 到参数传递从符号导出到依赖管理这些知识是后续驱动开发的基础。内核模块是 Linux 内核可扩展性设计的体现。它让内核既能保持稳定性又能灵活地支持新硬件和新功能。对于嵌入式开发者来说模块更是必不可少的工具——它让我们能够快速迭代代码而不需要每次都重新编译和烧录整个内核。下一章我们将深入探讨设备树在内核中的使用。你会看到内核如何解析设备树、如何根据设备树信息匹配设备和驱动、如何调试设备树相关的问题。那是从写代码到写驱动的关键一步。准备好了吗让我们继续。

相关文章:

正点原子2026开发板教程——从0开始配置Linux内核(4)内核模块详解:从 Hello World 到设备驱动

正点原子2026开发板教程——从0开始配置Linux内核(4)内核模块详解:从 Hello World 到设备驱动 为什么要写这一章 这块跟移植关系不大,是桥接到后续驱动编写的。后面准备更新Rootfs。 前面我们花了三章的篇幅,把 Linux …...

DocMost 容器化部署进阶:从单机到高可用集群

1. 从单机到集群:为什么需要高可用部署 第一次用Docker Compose部署DocMost时,那种"一条命令启动全套服务"的爽快感至今难忘。但当我负责的在线教育平台用户量突破10万时,凌晨三点被报警短信吵醒成了家常便饭——数据库连接池爆满、…...

手把手教你为STM32F103C8T6(蓝色小药丸)编译Cleanflight固件,解决Flash溢出问题

深度优化STM32F103C8T6固件编译:从Flash溢出到精准裁剪实战 如果你手头正好有一块STM32F103C8T6开发板(也就是圈内俗称的"蓝色小药丸"),想要为它编译Cleanflight固件却频频遭遇Flash空间不足的问题,那么这篇…...

2026四川AI企业培训避坑指南:选对路径,少走弯路

随着DeepSeek等国产大模型在2025年的爆发式普及,四川企业迎来AI赋能的关键窗口期。成都、绵阳、德阳等地的国央企和民营企业纷纷启动AI培训计划,但在落地过程中,超过60%的企业反馈培训效果与预期存在差距。笔者近期调研了四川省内47家已开展A…...

高效获取网络小说与个性化阅读的全流程指南

高效获取网络小说与个性化阅读的全流程指南 你是否也曾遇到过这样的困扰:想在不同设备上阅读喜欢的网络小说,却被格式不兼容、广告弹窗和多平台切换搞得心烦意乱?FictionDown作为一款跨平台小说处理工具,通过智能格式适配技术&…...

【愚公系列】《剪映+DeepSeek+即梦:短视频制作》020-声音:让短视频更加动听(音频素材处理)

💎【行业认证权威头衔】 ✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家 ✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主 ✔ 技术生态共建先锋&am…...

【认知雷达(Cognitive Radar)与深度学习融合架构】第2章 雷达信号预处理与深度特征工程

项目地址 https://wwbrq.lanzouv.com/ijsMS3lb8sah 第2章 雷达信号预处理与深度特征工程 2.1 雷达回波信号数字化与去噪 2.1.1 高速ADC采样与数字下变频(DDC)实现 2.1.1.1 基于Xilinx RFSoC的14-bit直接采样与数字正交解调算法 2.1.1.2 CIC抽取滤波器与FIR匹配滤波器的级…...

SecGPT-14B部署案例:CSDN平台双24G 4090 GPU算力高效适配实践

SecGPT-14B部署案例:CSDN平台双24G 4090 GPU算力高效适配实践 1. 项目背景与模型介绍 SecGPT-14B是一款专注于网络安全领域的14B参数大语言模型,基于Qwen2ForCausalLM架构开发。该模型在CSDN星图平台上实现了开箱即用的部署方案,特别针对双…...

数据结构从入门到劝退?我用王者荣耀段位比喻线性表操作

数据结构王者之路:用游戏段位解锁线性表操作精髓 青铜段位:初识数据结构与线性表 刚接触数据结构的新手,就像刚注册游戏账号的青铜玩家。在这个阶段,我们需要理解最基础的概念——什么是数据结构?简单来说,…...

Breaking the Prior Dependency: A Novel Approach to Camouflaged Object Detection with Adaptive Featur

1. 伪装目标检测的挑战与突破 想象一下在丛林中寻找一只变色龙,或是军事侦察时识别伪装目标——这些场景下,目标物体往往与背景高度融合,肉眼都难以分辨。这正是伪装目标检测(Camouflaged Object Detection, COD)要解决…...

系统辨识入门:从最小二乘法到ARX模型,5步搞定黑箱建模

系统辨识入门:从最小二乘法到ARX模型,5步搞定黑箱建模 在自动化控制和机械工程领域,系统辨识是一项基础而关键的技能。面对一个未知的系统,如何通过输入输出数据建立数学模型?本文将带你从零开始,用最小二乘…...

Apache Flink Checkpoint 与 Chandy-Lamport 算法深度解析

本文从基础定义到底层算法原理,系统梳理 Flink Checkpoint 机制的完整知识体系,包含架构图、执行流程图、分类对比与生产调优指南。一、什么是 Checkpoint Checkpoint(检查点) 是 Apache Flink 容错机制的核心,它在不停…...

批量次品频发?MES+QMS的参数比对机制提前拦截风险

批量次品是制造业质量管控的“重灾区”,一旦发生不仅会造成物料、产能浪费,还会延误订单交付、损害品牌信誉。传统质量管控多依赖事后检验,待发现次品时已形成批量产出,损失难以挽回。核心症结在于缺乏生产过程中实时质量校验机制…...

从Talkie到MiniMax-01:揭秘这款低调国产AI如何征服海外市场

从Talkie到MiniMax-01:揭秘这款低调国产AI如何征服海外市场 在AI技术日新月异的今天,一个来自中国的团队正以惊人的速度在全球市场崭露头角。MiniMax,这个在国内鲜为人知的名字,却在海外AI应用市场占据了重要席位。它的成功并非偶…...

云曦26开学考复现

hello_rce查看当前目录: print_r(scandir(.)); print_r(scandir(dirname(__FILE__)));查看flag文件: call_user_func(passthru,base64${IFS}flag); call_user_func(passthru,tac${IFS}flag);新东西输入: {{lipsum.globals.os.popen(‘ls’).read()}}输入…...

90%的AI创业BP被VC秒删,因为创始人犯了同一个致命错误

大多数AI创始人花大量时间在BP里堆砌技术参数、模型架构和宏大愿景,以为这样就能显得专业。 结果发出去后,99%石沉大海。 其实VC每天处理几十份BP,用的是最残酷的「排除法」。你的BP很可能前30秒就被扔进垃圾桶。 真正决定AI项目生死的是6个评…...

检索大赛 实验3 豆包实验结果

根据对提供文献的核实,以下是真实存在的文献判断结果:1. **《RealVul: Can We Detect Vulnerabilities in Web Applications with LLM?》** - **真实性**:**存疑** - 理由:EMNLP 2024尚未召开(通常会议论文接收列表会…...

从仿真到综合:组合逻辑环的那些坑(附避坑指南)

从仿真到综合:组合逻辑环的那些坑(附避坑指南) 在数字电路设计中,组合逻辑环(Combinational Loop)是一个既常见又容易被忽视的问题。许多工程师第一次遇到这类警告时,往往会选择最简单的解决方案…...

【WebAssembly 】WebAssembly 组成部分详解(0~12 段 ID 详解)

WebAssembly 二进制文件由多个段(Section) 组成,每个段有唯一的 ID。本文详细介绍 ID 0-12 共 13 个标准段的完整结构。 一、文件整体结构 一个 .wasm 文件的结构如下: ------------------ 0x00 | 魔数 (4 字节) | \0asm ---…...

Win11 WSL2下CentOS9-Stream保姆级安装指南:从零配置到Docker实战

Win11 WSL2下CentOS9-Stream保姆级安装指南:从零配置到Docker实战 对于需要在Windows环境下进行Linux开发的用户来说,WSL2(Windows Subsystem for Linux 2)无疑是一个革命性的工具。它允许开发者在Windows系统上运行原生的Linux二…...

单细胞数据分析避坑指南:如何用Seurat V5搞定细胞周期矫正与双胞体过滤

单细胞数据分析避坑指南:如何用Seurat V5搞定细胞周期矫正与双胞体过滤 单细胞RNA测序技术正在彻底改变我们对复杂生物系统的理解能力。当您第一次拿到单细胞测序数据时,可能会被细胞周期效应和双胞体污染这两个"隐形杀手"所困扰——它们悄无声…...

OSM道路数据里的‘fclass’字段到底怎么用?一份给GIS新手的标签解读与筛选指南

OSM道路数据里的‘fclass’字段到底怎么用?一份给GIS新手的标签解读与筛选指南 当你第一次打开从OpenStreetMap下载的道路数据,面对属性表中密密麻麻的"fclass"字段分类,是不是感到一头雾水?作为GIS领域最常用的开源数据…...

光电经纬仪与AI:能捕获隐身战机的“最后一瞥”吗?

引言 在现代防空体系中,光电经纬仪作为一种高精度光学测量设备,一直扮演着“记录者”与“验证者”的角色。它能够以极高的精度测量空中目标的轨迹,并记录下清晰的光学图像。然而,当面对像F-35这样的第五代隐身战机时,…...

腾讯:揭示评估幻觉并构建知识驱动新范式

📖标题:Beyond the Illusion of Consensus: From Surface Heuristics to Knowledge-Grounded Evaluation in LLM-as-a-Judge 🌐来源:arXiv, 2603.11027v1 🌟摘要 LLM-as-a-judge的范式依赖于一个关键假设,即…...

【图形图像处理】之栅格化:从原理到实时渲染的引擎核心

1. 为什么游戏和VR离不开栅格化? 第一次接触栅格化这个概念时,我正试图在Unity里实现一个简单的3D场景。当时发现无论模型多复杂,最终显示在屏幕上的永远是由无数小像素组成的画面。这个将矢量图形转换为像素矩阵的过程,就是栅格化…...

科技伦理兜着岐金兰

科技伦理兜着岐金兰引言当前,人工智能技术的迅猛发展正深刻重塑着人类社会的权力结构和话语体系。在这一背景下,科技伦理作为调节技术发展与社会价值的重要机制,其话语建构过程本身就蕴含着复杂的权力博弈。岐金兰在其系列文章中敏锐地捕捉到…...

避坑指南:ESP32-S3 Flash加密后,如何用Flash下载工具重新烧录固件?

ESP32-S3 Flash加密后固件更新实战:Release模式下的救砖指南 当ESP32-S3芯片开启Flash加密(特别是Release模式)后,常规的固件烧录方法将完全失效。这给产品迭代和bug修复带来了巨大挑战。本文将深入剖析加密机制背后的原理&#x…...

美团:融合先验与稀疏采样的自适应基线

📖标题:V0.5:Generalist Value Model as a Prior for Sparse RL Rollouts 🌐来源:arXiv, 2603.10848v1 🌟摘要 在具有可验证奖励的强化学习(RLVR)中,构建稳健的优势基线对…...

ROS2 编译依赖缺失的排查与修复指南

1. ROS2编译依赖缺失的典型表现 第一次用ROS2编译功能包时,看到满屏红色报错确实容易懵。最常见的就是CMake哭着告诉你"找不到某某包",就像你去超市买酱油却发现货架空空如也。这种报错通常长这样: CMake Error at CMakeLists.txt:…...

记忆走私犯:倒卖富豪脑数据的暗网暴富术——软件测试从业者的技术警示与防御蓝图

脑数据走私的崛起与技术危机2026年初,暗网曝出富豪思维记录以每秒计价拍卖,单条记忆数据标价高达250万美元,这标志着脑数据走私已成为新型犯罪风口。脑机接口(BCI)技术的普及让神经数据成为“数字黄金”,但…...