解析 Linux 内核可装载模块的版本检查机制

2023-11-05

解析 Linux 内核可装载模块的版本检查机制

王 华东, 系统工程师, 自由职业者

简介: 为保持 Linux 内核的稳定与可持续发展,内核在发展过程中引进了可装载模块这一特性。内核可装载模块就是可在内核运行时加载到内核的一组代码。通常 , 我们会在两个版本不同的内核上装载同一模块失败,即使是在两个相邻的补丁级(Patch Level)版本上。这是因为内核在引入可装载模块的同时,对模块采取了版本信息校验。这是一个与模块代码无关,却与内核相连的机制。该校验机制保证了内核装载的模块是用户认可的,且安全的。本文将从内核模块发布者的角度思考模块版本检查机制,并从开发者与授权 root 用户的角度去使用及理解该机制。

发布日期: 2011 年 11 月 17 日 
级别: 初级 
访问情况 : 19413 次浏览 
评论:  (查看 | 添加评论 - 登录)

平均分 4 星 共 13 个评分 平均分 (13个评分)
为本文评分

内核可装载模块概述

Linux 在发展过程中(即自 Linux 1.2 之后)引进了模块这一重要特性,该特性提供内核可在运行时进行扩展。可装载模块(Loadable Kernel Module,即 LKM)也被称为模块,就是可在内核运行时加载到内核的一组目标代码(并非一个完整的可执行程序)。这就意味着在重构和使用可装载模块时并不需要重新编译内核。模块依据代码编写与编译时的位置可分:内部模块和外部模块,即 in-tree module 和 out-of-tree module,在内核树外部编写并构建的模块就是外部模块。如果只是认为可装载模块就是外部模块或者认为在模块与内核通讯时模块是位于内核的外部的,那么这在 Linux 下均是错误的。当模块被装载到内核后,可装载模块已是内核的一部分。另外,我们使用的 Linux 发行版在系统启动过程 initrd 中已使用了必要的模块,除非我们只讨论基础内核(base kernel)。本文主要是对 Linux 2.6 的外部模块进行讨论的。

可装载模块在 Linux 2.6 与 2.4 之间存在巨大差异,其最大区别就是模块装载过程变化(如 图 1所示,在 Linux 2.6 中可装载模块在内核中完成连接)。其他一些变化大致如下:

  • 模块的后缀及装载工具;

对于使用模块的授权用户而言,模块最直观的改变应是模块后缀由原先的 .o 文件(即 object)变成了 .ko 文件(即 kernel object)。同时,在 Linux 2.6 中,模块使用了新的装卸载工具集 module-init-tools(工具 insmod 和 rmmod 被重新设计)。模块的构建过程改变巨大,在 Linux 2.6 中代码先被编译成 .o 文件,再从 .o 文件生成 .ko 文件,构建过程会生成如 .mod.c、.mod.o 等文件。

  • 模块信息的附加过程;

在 Linux 2.6 中,模块的信息在构建时完成了附加;这与 Linux 2.4 不同,先前模块信息的附加是在模块装载到内核时进行的(在 Linux 2.4 时,这一过程由工具 insmod 完成)。

  • 模块的标记选项。

在 Linux 2.6 中,针对管理模块的选项做了一些调整,如取消了 can_unload 标记(用于标记模块的使用状态),添加了 CONFIG_MODULE_UNLOAD 标记(用于标记禁止模块卸载)等。还修改了一些接口函数,如模块的引用计数。


图 1. 模块在内核中完成连接
图 1. 模块在内核中完成连接 

发展到 Linux 2.6,内核中越来越多的功能被模块化。这是由于可装载模块相对内核有着易维护,易调试的特点。可装载模块还为内核节省了内存空间,因为模块一般是在真正需要时才被加载。根据模块作用,可装载模块还可分三大类型:设备驱动、文件系统和系统调用。另须指出的是,虽然可装载模块是从用户空间加载到内核空间的,但是并非用户空间的程序。

回页首

模块的版本检查

Linux 的迅速发展致使相邻版本的内核之间亦存在较大的差异,即在版本补丁号(Patch Level,即内核版本号的第四位数)相邻的内核之间。为此 Linux 的开发者为了保证内核的稳定,Linux 在加载模块到内核时对模块采用了版本校验机制。当被期望加载模块的系统环境与模块的构建环境相左时,通常会出现如清单 1 所示的装载模块失败。


清单 1. 装载模块失败
				
 # insmod ./hello/hello.ko 
 insmod: error inserting './hello/hello.ko': -1 Invalid module format 

 # dmesg | grep hello 
 [ 9206.599843] hello: disagrees about version of symbol module_layout 


清单 1 中,模块 hello.ko 构建时的环境与当前系统不一致,导致工具 insmod 在尝试装载模块 hello.ko 到内核时失败。hello.ko 是一个仅使用了函数 printk 的普通模块(您可在示例源码中找到文件 hello/hello.c)。我们通过命令 dmesg(或者您也可以查看系统日志文件如 /var/log/messages 等,如果您启用了这些系统日志的话)获取模块装载失败的具体原因,模块 hello.ko 装载失败是由于模块中 module_layout 的导出符号的版本信息与当前内核中的不符。函数 module_layout 被定义在内核模块版本选项 MODVERSIONS(即内核可装载模块的版本校验选项)之后。清单 2所示为 module_layout 在内核文件 kernel/module.c 中的定义。


清单 2. 函数 module_layout
				
 /* kernel/module.c */ 
 #ifdef CONFIG_MODVERSIONS 
 void module_layout(struct module *mod, 
       struct modversion_info *ver, 
       struct kernel_param *kp, 
       struct kernel_symbol *ks, 
       struct tracepoint * const *tp) 
 { 
 } 
 EXPORT_SYMBOL(module_layout); 
 #endif 


清单 3. 结构体 modversion_info
				
 /* include/linux/module.h */ 
 struct modversion_info 
 { 
     unsigned long crc; 
     char name[MODULE_NAME_LEN]; 
 }; 

正如您所想,函数 module_layout 的第二个参数 ver 存储了模块的版本校验信息。结构体 modversion_info 中保存了用于模块校验的 CRC(Cyclic Redundancy Check,即循环冗余码校验)值(见 清单 3)。Linux 对可装载模块采取了两层验证:模块的 CRC 值校验和 vermagic 的检查。其中模块 CRC 值校验针对模块(内核)导出符号,是一种简单的 ABI(即 Application Binary Interface)一致性检查,清单 1中模块 hello.ko 加载失败的根本原因就是没有通过 CRC 值校验(即 module_layout 的 CRC 值与当前内核中的不符);而模块 vermagic(即 Version Magic String)则保存了模块编译时的内核版本以及 SMP 等配置信息(见 清单 4,模块 hello.ko 的 vermagic 信息),当模块 vermagic 与主机信息不相符时亦将终止模块的加载。


清单 4. 模块的 vermagic 信息
				
 # uname – r 
 2.6.38-10-generic 

 # modinfo ./hello/hello.ko 
 filename:       ./hello/hello.ko 
 license:        Dual BSD/GPL 
 srcversion:     31FE72DA6A560C890FF9B3F 
 depends:        
 vermagic:       2.6.38-9-generic SMP mod_unload modversions 

通常,内核与模块的导出符号的 CRC 值被保存在文件 Module.symvers 中,该文件需在开启内核配置选项 CONFIG_MODVERSIONS 之后并完全编译内核获得(或者您也可在编译外部模块后获得该文件,保存的是模块的导出符号的 CRC 信息),其信息的保存格式如清单 5 所示。


清单 5. 导出符号的 CRC 值
				
 0x1de386dd  module_layout  vmlinux  EXPORT_SYMBOL 
 <CRC>        <Symbol>  <module> 

Linux 内核在进行模块装载时先完成模块的 CRC 值校验,再核对 vermagic 中的字符信息,图 2展示了内核中与模块版本校验相关的函数的调用过程(分别在函数 setup_load_info 和 check_modinfo 中完成校验)。Linux 使用 GCC 中的声明函数属性 __attribute__ 完成对模块的版本信息附加。构建的模块存在几个 section,如 .modinfo、.gnu.linkonce.this_module 和 __versions 等,这些 ELF 小节(即 section)保存了模块校验所需的信息(关于这些 section 信息的附加过程,您可查看模块构建时生成的文件 <module>.mod.c 及工具 modpost,见 清单 8和 清单 15)。


图 2. 模块的两层版本校验过程
图 2. 模块的两层版本校验过程 

为了更好的理解可装载模块,我们查看内核头文件 include/linux/module.h,它不仅定义了上述中的 struct modversion_info(见 清单 3)还定义了 struct module 等结构体。模块 CRC 值校验查看的是就是模块 __versions 小节的内容,即是附加的 struct modversion_info 信息。模块的 CRC 校验过程在函数 setup_load_info 中完成。Linux 使用 .gnu.linkonce.this_module 小节来解决模块对 struct module 信息的附加。文件 kernel/module.c 中的函数 check_modinfo 完成了主机与模块的 vermagic 值的对比(见 清单 6)。清单 6 中函数 get_modinfo 用于获取内核中的 vermagic 信息,模块 vermagic 信息则被保存在了 ELF 的 .modinfo 小节中。


清单 6. 函数 check_modinfo
				
 /* kernel/module.c */ 
 static int check_modinfo(struct module *mod, struct load_info *info) 
 { 
  const char *modmagic = get_modinfo(info, "vermagic"); 

  ... 
  } else if (!same_magic(modmagic, vermagic, info->index.vers)) { 
    ... 
  } 
  ... 

  return 0; 
 } 

内核空间与用户空间

操作系统须负责程序的独立操作并保护资源不受非法访问,而这一功能在现代 CPU 中以设计不同的操作模式(级别)来实现。内核运行在 CPU 的最高级别,即内核态,也被称为超级用户态;而应用程序则运行在最低级别,即用户态。由此系统内存在 Linux 中可分为两个不同的区域:内核空间与用户空间。模块运行在内核空间里,而应用程序则运行在对应的用户空间中。

须指出的是模块的 vermagic 信息来自内核头文件 include/linux/vermagic.h 中的宏 VERMAGIC_STRING,其中宏 UTS_RELEASE 保存了内核版本信息(见 清单 7)。与其关联的头文件 include/generated/utsrelease.h 需经内核预编译生成,即通过命令 make 或 make modules_prepare 等。


清单 7. 宏 VERMAGIC_STRING
				
 /* kernel/module.c */ 
 static const char vermagic[] = VERMAGIC_STRING; 

 /* include/linux/vermagic.h */ 
 #define VERMAGIC_STRING                         \ 
     UTS_RELEASE " "                         \ 
     MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT             \ 
     MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS   \ 
     MODULE_ARCH_VERMAGICLINE 

回页首

模块的装载与卸载

上述中,我们在装载模块时使用了工具 insmod。在 Linux 2.6 中,工具 insmod 被重新设计并作为工具集 module-init-tools 中的一个程序,其通过系统调用 sys_init_module(您可查看头文件 include/asm-generic/unistd.h)衔接了模块的版本检查,模块的装载等功能(如 图 3所示)。module-init-tools 是为 2.6 内核设计的运行在 Linux 用户空间的模块装卸载工具集,其包含的程序 rmmod 用于卸载当前内核中的模块。


图 3. 模块的装卸载
图 3. 模块的装卸载 

表 1. 工具集 module-init-tools 中的部分程序
名称 说明
insmod 装载模块到当前运行的内核中
rmmod 从当前运行的内核中卸载模块
lsmod 显示当前内核已加装的模块信息
modinfo 检查与内核模块相关联的目标文件,并打印出所有得到的信息
modprobe 利用 depmod 创建的依赖关系文件自动加载相关的模块
depmod 创建一个内核可装载模块的依赖关系文件,modprobe 用它来自动加载模块

值得一提的是在 module-init-tools 中可用于模块装卸载的程序 modprobe。程序 modprobe 的内部函数调用过程正如您所想与 insmod 类似,只是其装载过程会查找一些模块装载的配置文件,且 modprobe 在装载模块时可解决模块间的依赖性,即若有必要,程序 modprobe 会在装载一个模块时自动加载该模块依赖的其他模块。

回页首

其他一些细节

从用户空间装载模块到内核时,Linux 还对用户权限进行了检查。模块的装载须是获得 CAP_SYS_MODULE 权限的超级用户,这正是模块装载时最先检查的内容(见 图 2)。在 Linux 2.6 中,模块在构建时生成了一些临时文件,如 .o 文件、.mod.o 文件等。了解这些文件的生成有助于我们更好的理解 Linux 2.6 的内核模块构建过程以及版本信息的检查等内容。文件 .o 是模块代码(即 .c 文件)经编译后获得的目标文件,文件 .mod.o 则对应文件 .mod.c。文件 <module>.mod.c 是对 <modulue>.c 的扩展,清单 8展示了文件 kobject-example.mod.c 的内容 ( 即模块 kobject-example.ko 的 .mod.c 文件 ),您可见到与模块版本检查相关三个小节。


清单 8. 文件 kobject-example.mod.c
				
 # cat ./kobject/kobject-example.mod.c 
 ... 

 MODULE_INFO(vermagic, VERMAGIC_STRING); 

 struct module __this_module 
 __attribute__((section(".gnu.linkonce.this_module"))) = { 
 ... 
 }; 

 static const struct modversion_info ____versions[] 
 __used 
 __attribute__((section("__versions"))) = { 
 ... 
 }; 

 static const char __module_depends[] 
 __used 
 __attribute__((section(".modinfo"))) = 
"depends="; 

 MODULE_INFO(srcversion, "B06F9B8B7AB52AEED247B9F"); 

清单 8 中显示了模块 kobject-example.ko 中的三个 section 以及宏 MODULE_INFO,最后一行 srcversion 则需开启内核配置选项 MODULE_SRCVERSION_ALL。经上述,我们知道这三个 section 正是模块版本检查的附加信息。我们通过工具 objdump 查看 .modinfo 小节(见 清单 9, 即模块的 vermagic 信息)。<module>.ko 的附加信息合并自文件 <module>.o 与文件 <module>.mod.o。内核工具 modpost 完成了一这步骤,且该工具是 Linux 2.6 内核模块构建时所必须的。


清单 9. 使用工具 objdump 查看 .modinfo 小节
				
 # objdump --section=.modinfo -s hello/hello.o 

 hello/hello.o:     file format elf64-x86-64 

 Contents of section .modinfo: 
 0000 6c696365 6e73653d 4475616c 20425344  license=Dual BSD 
 0010 2f47504c 00                          /GPL. 

 # modinfo hello/hello.o 
 filename:       hello/hello.o 
 license:        Dual BSD/GPL 

 # objdump --section=.modinfo -s hello/hello.mod.o 
 ... 
 # objdump --section=.modinfo -s hello/hello.ko 
 ... 

经上述,我们可知内核树的顶层 Makefile 文件包含了内核版本的信息,且该信息经编译后被添加到模块的(头文件 include/generated/utsrelease.h 保存的内核版本信息来自顶层 Makefile)。表 1中,工具 lsmod 打开文件 /proc/modules 查询当前内核中已装载的模块(见清单 10),文件 /proc/modules 还被 rmmod 在卸载模块时使用。另外,若您在装载模块 hello.ko 后没能在终端下看到相应的字符串输出,则需检查文件 /proc/sys/kernel/printk,并重设下消息级别。


清单 10. 工具 lsmod 的使用
				
 # insmod ./kobject/kobject-example.ko 

 # ls /sys/kernel/kobject_example/ 
 bar  baz  foo 

 # lsmod | grep kobject 
 kobject_example        12857  0 

 # cat /proc/modules | grep kobject 
 kobject_example 12857 0 - Live 0xffffffffa0523000 

Linux 2.6 构建模块时工具 modpost 被 scripts/Makefile.modpost 调用,生成 <module>.mod.c 及文件 Module.symvers(见 清单 15)。在开启内核选项 CONFIG_MODVERSIONS 之后,文件 Makefile.Build 会调用工具 genksyms(现位于内核树 scripts/genksyms 目录下,在 Linux 2.4 时是模块工具集 Modutils 的一部分)生成 CRC 信息(见 清单 11)。其中代码 call cmd_gensymtypes 就是对工具 genksyms 的调用。另外一个较为明晰的方式是,使用工具 objdump 或 readelf 查看相关的 ELF 小节,并使用 make – n 查看模块构建过程。


清单 11. 文件 Makefile.Build 的部分内容
				
 ifndef CONFIG_MODVERSIONS 
 cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< 
 else 
 cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< 
 cmd_modversions =              \ 
  if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then  \ 
    $(call cmd_gensymtypes, $(KBUILD_SYMTYPES))    \ 
        > $(@D)/.tmp_$(@F:.o=.ver);      \ 
                  \ 
    $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F)     \ 
      -T $(@D)/.tmp_$(@F:.o=.ver);      \ 
    rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);  \ 
  else                \ 
    mv -f $(@D)/.tmp_$(@F) $@;        \ 
  fi; 
 endif 

回页首

模块的构建与测试

为内核构建外部模块前,我们须准备一颗内核源码树(kernel source tree)。内核源码树就是一套包含系统配置及内核头文件的内核目录树。须指出的是 Linux 2.6 的内核源码树与 2.4 的不同,先前的内核只需一套内核头文件就可以了,但在 2.6 的内核源码树中还需存在一些目标文件及工具,如 scripts/mod/modpost 等。清单 12 所示是从内核源码进行内核模块预编译以此生成内核树,当然您也可使用 Linux 发行版的内核源码树(系统内核树一般存放在 /lib/modules/<kernel version>/build,如果存在的话)。


清单 12. 预编译内核模块
				
 # make menuconfig 
 # make modules_prepare 
 # 

当然,我们最先须根据主机的硬件信息产生内核配置文件 .config。您可使用命令 make menuconfig 或 make config 等来配置与模块相关的选项(清单 13与 清单 14相互对应,显示了模块相关的内核配置选项)。设置选项 CONFIG_MODULES=y 以及 CONFIG_MODVERSIONS=y 使内核支持模块的版本检查。另须注意的是,模块预编译并不生成 Module.symvers 文件,即使您开启了 CONFIG_MODVERSIONS 选项。因此最好的方式是完全编译 Linux 内核。


清单 13. 使用 make menuconfig 配置内核模块选项
				
 # make menuconfig 
 --- Enable loadable module support 
    [ ]   Forced module loading 
    [*]   Module unloading 
    [ ]     Forced module unloading 
    [*]   Module versioning support 
    [*]   Source checksum for all modules 


清单 14. 模块相关的内核配置选项
				
 CONFIG_MODULES 
 CONFIG_MODULE_FORCE_LOAD 
 CONFIG_MODULE_UNLOAD 
 CONFIG_MODULE_FORCE_UNLOAD 
 CONFIG_MODVERSIONS 
 CONFIG_MODULE_SRCVERSION_ALL 

内核 2.6 时,我们常为模块的构建编写一个 Makefile 文件,但仍可使用类似内核 2.4 下的模块构建命令。清单 15 展示了外部模块构建的 make 命令,其中 $KDIR 是内核树的绝对路径,$MDIR 是期望构建的模块的绝对路径(若是内部模块则可使用 make CONFIG_EXT2_FS=m …)。


清单 15. 构建外部模块
				
 # make -C $KDIR M=$MDIR [target] 

 # make -C /lib/modules/2.6.38-10-generic/build M=$PWD/hello  modules 
 make: Entering directory `/usr/src/linux-headers-2.6.38-10-generic'
 CC [M] /home/harris/work/samples/hello/hello.o 
 Building modules, stage 2. 
 MODPOST 1 modules 
 CC /home/harris/work/samples/hello/hello.mod.o 
 LD [M] /home/harris/work/samples/hello/hello.ko 
 make: Leaving directory `/usr/src/linux-headers-2.6.38-10-generic'

回页首

结束语

虽然本文已尽量集中描述可装载模块的版本检查机制,但是仍然涉及了非常多的内容。您需花一些时间来了解这些看似与模块不相关的内容,如 /proc、/sys 文件系统、ELF(即 Executable and Linkable Format)格式等,以此更好的全面理解内核可装载模块以及模块版本版本检查机制。另外,由于文章讨论的是 Linux 2.6 的外部模块,没有清晰的讲述内核的 Kbuild 系统及 Makefile 文件,但这对于模块亦是重要的内容。


回页首

下载

描述 名字 大小 下载方法
样例代码 samples.tar.gz 38KB HTTP

关于下载方法的信息


参考资料

学习

讨论

  • 加入 developerWorks 中文社区,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。

关于作者

王华东,自由职业者,对 Linux、开放源码感兴趣。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解析 Linux 内核可装载模块的版本检查机制 的相关文章

  • 操作系统多线程实现_操作系统中的线程实现

    操作系统多线程实现 Each process has an address space There is one thread of control in every traditional OS Sometimes it is viabl
  • setns对当前进程无效问题的排查(getpid获取值不变)

    1 复现流程及lxc的处理 demo1程序与执行结果如下 此时在容器内部看不到执行的程序 int main int ret fd pid printf father pid old d n getpid fd open dev ns O R
  • 01信号学习之信号的概念于机制

    1 信号的相关认知 1 信号的概念 传播信息的方法 所以它是信息发送的标志 2 信号的机制 A给B发送信号 B收到信号之前执行自己的代码 收到信号后 不管执行到程序的什么位置 都要暂停运行 去处理信号 处理完毕再继续执行 与硬件中断类似 异
  • 多核处理器下的快速包处理软件架构FastGate

    FastGate主要的目标是帮助用户缩短研发周期 保护已有的代码 快速开发和灵活部署自己的业务 用户无需关注多核处理器的硬件细节 无需关注性能和扩展性 只需专注于自身功能模块的开发 然后通过和FastGate框架的无缝集成便可以快速形成自己
  • 【RDMA】降低CPU除了RDMA (vbers)还是VMA ?

    前言 看介绍 像是mellonx针对其kernel bypass网卡 RDMA网卡 提供的一个lib库 该lib库对外提供socket api 使得用户的程序不需要修改就可以直接使用kernel bypass网卡 如RDMA网卡 我们都知道
  • 为WinDbg设置符号文件路径

    WinDbg可以通过加载Symbol文件 pdb 即时的调试程序 WinDbg如何找到相应的符号文件呢 WinDbg首先在 exe或者 dll所在目录下寻找同名的 pdb文件 如果找不到 WinDbg在Symbol File Path中查找
  • 教你动手移植RT-Thread到国产MCU

    摘要 现在芯片价格不断上涨 国内很多厂商也在不断的找替换方案 以ST为例 一个芯片涨了十几倍 蛋疼 最近刚好有机会拿到国产芯片MCU 兆易创新的评估板 GD32350R 板载资源如下 硬件 描述 芯片型号 GD32F350R8T6 CPU
  • 内核中的位图介绍(DECLARE_BITMAP宏)

    1 DECLARE BITMAP宏定义 define DIV ROUND UP x y x y 1 y 向上取整 define BITS TO LONGS nr DIV ROUND UP nr BITS PER BYTE sizeof lo
  • 树莓派3B+内核编译

    获取内核源码 https github com raspberrypi 选着linux工程代码 https github com raspberrypi linux 版本分支选择rpi 4 14 y 获取内核配置文件 如果已经有内核配置文件
  • 虚拟机的启动内核日志

    等有时间了 回来分析下 0 000000 Initializing cgroup subsys cpuset 0 000000 Initializing cgroup subsys cpu 0 000000 Initializing cgr
  • Linux用户空间和内核空间的内存互访

    Linux用户空间和内核空间的内存互访 标签 虚拟内存 安全性 Linux 用户 2012 11 13 15 55 Linux 内存 在 Linux 中 用户内存和内核内存是独立的 在各自的地址空间实现 地址空间是虚拟的 就是说地址是从物理
  • Linux中的中断机制 2

    Linux中的中断机制 2009 06 11 23 03 44 分类 LINUX Linux中的中断机制 X86里面中断发生时CPU控制单元工作流程 也就是硬件需要做的事情 在CPU执行下一条instruction之前 首先判断有没有发生异
  • qemu: 设备后端模拟

    目录 1 网卡模拟 2 网卡参数解析 3 qemu前端虚拟网卡设备创建 4 报文发送流程 5 报文发送流程 1 网卡模拟 参数 netdev type tap id eth0 ifname tap30 script no downscrip
  • 国产开源IoTOS:腾讯物联网操作系统TencentOS Tiny的探索与实践

    导语 腾讯物联网终端操作系统 TencentOS tiny 是腾讯面向物联网领域自主研发的嵌入式实时操作系统 可助力物联网终端设备及业务快速接入腾讯云物联网平台 本文是对腾讯高级工程师汪礼超 赵健在云 社区 online 分享的整理 为大家
  • jffs2:You cannot use older JFFS2 filesystems with newer kernels错误

    jffs2 You cannot use older JFFS2 filesystems with newer kernels错误 原因 可能在于交叉编译linux内核时 没有打开jffs2系统的使能开关 解决方法 在内核文件中执行make
  • Linux用户空间与内核空间

    Linux用户空间与内核空间 2012 08 30 15 39 1969人阅读 评论 1 收藏 举报 linux linux内核 struct user system allocation Linux 操作系统和驱动程序运行在内核空间 应用
  • linux内核之无锁缓冲队列kfifo原理(结合项目实践)

    无锁缓冲队列kfifo 1 kfifo概述 2 kfifo功能描述 3 kfifo put与 kfifo get详解 4 kfifo get和kfifo put无锁并发操作 5 总结 6 项目使用介绍 7 其它 userspace 移植实现
  • late_initcall和module_init

    late initcall和module init 分类 linux驱动程序设计 2012 11 04 15 14 3680人阅读 评论 0 收藏 举报 所有的 init函数在区段 initcall init中还保存了一份函数指针 在初始化
  • Linux 内核开发学习

    Linux 内核 Linux 内核官网 传送门 Linux 内核源码下载 传送门 1 内核空间 现在来说一下内核空间以及用户空间 这是学习linux内核最基本的两个概念了 如果连这都不懂 那就好好学吧 我们先从这张图入手 32位操作系统的最
  • 基于树莓派博通BCM2835芯片手册导读写编简单引脚驱动代码编译和测试(树莓派)

    编写引脚驱动代码 这边写的是17引脚的驱动代码代码 IO口控制的代码在下面 这边只是简单的代码 驱动代码 include

随机推荐

  • 个人网站推广服务器,个人网站如何利用百度来推广自己的网站

    提前先申明一下 1 我下面所讲 利用百度推广网站 的经历是真实有过的 并非虚假吹牛 2 我所讲的的内容中的方法必须天天坚持 如果不能坚持的不一定有效果 大家听听就 行了 我要让大家知道的是做网站推广的人要有一种精神 以此来鼓励大家 开始叙说
  • Python正则表达式re.sub功能详解

    Python正则表达式re sub功能详解 正则表达式 regular expression 缩写为re sub即substitute 替换 re sub 语法结构 re sub pattern repl string count flag
  • 区块链中的去中心化

    想知道更多区块链技术知识 请百度 链客区块链技术问答社区 链客 有问必答 去中心化 是加密经济学领域中使用频率最高的词汇之一 同时也是区块链中最为关键的特性 但是其定义一直模糊不清 为了实现去中心化 迄今为止 人们已经花费数千小时的研究 投
  • android studio 华为手机真机测试

    手机的开发人员选项打开 USB 调试打开 在拨号界面输入 2846579 进入测试菜单界面 然后 Project Menu 后台设置 LOG设置 LOG 开关 LOG 打开 LOG 级别设置 VERBOSE Dump Log 全部选中 重启
  • GDI+ 中图片的绘制

    背景 GDI 中使用 Graphics 类的成员函数 DrawImage 来绘制图片 原样绘制 使用 Graphics 类的 成员函数 DrawImage 来绘制图片 当仅指定绘制起始位置时按照图片大小原样绘制 void DemoGDI D
  • Spark学习(六) 数据结构(迭代器、数组、元组)

    Spark学习 六 数据结构 迭代器 数组 元组 1 迭代器 Iterator 1 在Scala中迭代器不是一种集合 但是它提供了访问集合的一种方法 2 迭代器包含两个基本操作 next和hasNext next可以返回迭代器的下一个元素
  • 哈希表(Hash Table)原理及其实现

    原理 介绍 哈希函数构造 冲突处理 举例 拉链法 hash索引跟B树索引的区别 实现 原理 介绍 哈希表 Hash table 也叫散列表 是根据关键码值 Key value 而直接进行访问的数据结构 也就是说 它通过把关键码值映射到表中一
  • 逻辑回归(梯度上升、交叉验证)Python实现

    目录 1 介绍 2 算法实现 3 代码 4 实验结果 1 介绍 logistic回归又称logistic回归分析 是一种广义的线性回归分析模型 常用于数据挖掘 疾病自动诊断 经济预测等领域 例如 探讨引发疾病的危险因素 并根据危险因素预测疾
  • [shell/脚本]检索某个文件夹下的所有文件夹并且复制文件夹下文件到指定目录

    写一个脚本实现不同分支下的代码sync 递归去检索某个文件下的所有文件 bin bash usage source sync code sh 源码路径 目标路径 SOURCEDIR 1 TARGETDIR 2 if d SOURCEDIR
  • node、npm、cnpm踩坑

    文章目录 前言 一 cnpm i 报错无法使用 二 解决步骤 1 查看cnpm 是否安装 2 查看 node 和 npm 版本 3 处理 总结 前言 提示 npm install g cnpm registry https registry
  • vue项目请求控制请求头必须为https

    前言 因为很多项目必须要求是严格模式 不能有http请求 需要限制我们的请求头必须为https 如果是http的话 手动转成https来实现请求效果 实现方法 在 public index html 的 head 标签里面加入以下代码 效果
  • Step4:Angular调试方法

    1 方法一 采用VSCode编译器 下载插件debugger for chrome 选择调试 然后再选择chrome浏览器 在运行中输入npm start执行 就可以在代码中打断点了 2 方法二 在浏览器中按F12打开开发者工具 Sourc
  • Python第二课

    枭 Python第二课 今天讲解了Python的 内置函数 模块导入 序列 列表 切片操作 内置函数 divmod x y 用法 x y divmod a b 其中x返回值a b y返回值a b map func iterablies 用法
  • 4g网络设置dns地址_4G网速越来越慢,通过这三个简单的操作,网速成倍提升

    随着互联网的进步 从零几年开始移动手机在全国开始普及起来 网速也像火箭一样快速飙升 从2G发展到了现在的5G 不过 有很多网友表示 刚从2G或者3G升级到4G时 网速体验非常好 但近两年来的4G网速越来越慢 还卡顿 甚至感觉还不如以前的3g
  • 忘记网站服务器密码怎么办,忘记远程服务器的密码怎么办

    忘记远程服务器的密码怎么办 内容精选 换一换 如果在创建弹性云服务器时未设置密码 或密码丢失 过期 可以参见本节操作重置密码 密码丢失或过期前 已安装密码重置插件 公共镜像创建的弹性云服务器默认已安装一键重置密码插件 私有镜像创建的云服务器
  • Matlab—M_Map的实战学习笔记(一)M_Map库的安装

    最近在做美赛集训 做到了2020年的美赛A题 有关苏格兰附近鲭鱼和鲱鱼分布预测问题 在写论文的过程中 为了画几张精美的地图 可谓是历经千难万险 花费了不少时间 走了不少弯路 现在对使用matlab的m map映射库进行地图绘制做一个总结 力
  • Python:UnicodedecodeError编码问题解决方法汇总-彻底解决

    今天真的被编码问题一直困扰着 午休都没进行 也真的见识到了各种编码 例如 gbk unicode utf 8 ansi gb2312等 如果脚本程序中编码与文件编码不一致 就会报出UnicodedecodeError的错误 1 情景一 读文
  • python语法-面向对象(构造方法、魔术方法)

    python语法 面向对象 构造方法 魔术方法 1 构造方法 构造方法 python类可以使用 init 方法 称之为构造方法 可以实现 在创建类对象时 会自动执行 在创建类对象时 将传入参数自动传递给 init 方法使用 演示使用构造方法
  • Android中的定时器Timer、AlarmManager、CountDownTimer的使用

    1 Timer和TimerTask的使用 java util Timer定时器 实际上是个线程 定时调度所拥有的TimerTasks 1 创建一个Timer code class hljs cs has numbering style di
  • 解析 Linux 内核可装载模块的版本检查机制

    解析 Linux 内核可装载模块的版本检查机制 王 华东 系统工程师 自由职业者 简介 为保持 Linux 内核的稳定与可持续发展 内核在发展过程中引进了可装载模块这一特性 内核可装载模块就是可在内核运行时加载到内核的一组代码 通常 我们会