[driver]linux内核动态加载模块

内核模块及工作原理 什么是内核模块?  现在,你是不是想编写内核模块。你应该懂得C语言,写过一些用户程序, 那么现在你将要见识一些真实的东西。在这里,你会看到一个野蛮的指针是如何 毁掉你的文件系统的,一次内核崩溃意味着重启动。  什么是内核模块?内核模块是一些可以让操作系统内核在需要时载入和执行的代码,这同样意味着它可以在不需要时有操作系统卸载。它们扩展了操作系 统内核的功能却不需要重新启动系 阅读详情
问题:
1.  把编译好的模块放到板子/lib/modules对应文件夹下,并且执行了depmod -a, 比如pl2303.ko, 那么下一次插入pl2303的串口线,是否可以识别,也就是自动加载pl2303驱动?
--------------------------------------------------------------------------------------------------------------
转自:http://blog.youkuaiyun.com/hunanchenxingyu/article/details/47292327

一、安装内核模块

一般步骤:

  1. 在/usr/src/Linux/下运行make menuconfig把需要编译成模块的项打上(M),保存并退出。
  2. 运行make modules,这一步将在/usr/src/linux/下生成*.o或*.ko文件。
  3. 运行make modeules_install来安装,这步会把生成的.o或ko文件拷贝到/lib/modules/`uname -r`/下。

如果你只要编译某一个或几个模块,就可以用下面这个快速的方法:

  1. 找到编译内核所需要的.config文件。 在/usr/src/linux/arch目录下有若干编译内核所用的配置。选择我们想要的配置,将它复制到/usr/src/linux目录下,改名为.config。 cp /usr/src/linux/arch/x86/xxconfig /usr/src/linux/.config
  2. 修改.config文件,去掉不用的模块,加上自己想要的模块。 打开.config,有许多XXXX=m的项,这些都是要被编译为模块 的项,因为我们不希望编译这些模块,所以要把XXXX=m的项统统去掉。然后再加上我们想要的模块,例如将# CONFIG_NTFS_FS is not set 改为CONFIG_NTFS_FS=m 当然,可以用你熟悉各种工具来做这件事。
  3. 编译NTFS模块。在/usr/src/linux目录下运行命令make modules来编译我们想要的模块。
  4. 安装模块。 编译后得到的.o文件在/usr/src/linux/目录下,手动将它复制到正确的目录下。 例如cp /usr/src/linux/fs/ntfs/ntfs.o /lib/modules/2.2.16-22/fs/

 注意:千万不能运行命令make modules_install,否则将带来严重的后果,它会删除你系统中的所有模块,只安装刚刚编译的模块(ntfs.o)。

二:安装完成以后,我们就可以加载模块了

和linux中加载模块有关的几个命令分别如下:

depmod, modprobe, lsmod

2.1.先来看看depmod命令:

depmod是一个 用来产生modules.dep和map文件的程序。在modules.dep文件中空白行和以'#'开头的行将被忽略.depmod通过读取/lib /modules/version目录下的每一个模块来创建一个记录模块相依性的列表。这个列表就是/lib/modules/version目录下的 modules.dep。depmod也会在/lib/modules/version目录下创建许多map文件,例如 modules.dep,modules.isapnpmap,modules.pcimap,modules.alias这些文件将会被hotplug 用到。

OPTIONS:
-a --all Probe all modules. This option is enabled by default if no
            file names are given in the command-line.
检查所有的模块,这个命令是默认的如果你没有指定模块名字的话。

-A --quick This option scans to see if any modules are newer than the
                 modules.dep file before any work is done%3

2.2.再来看看modprobe命令:

modprobe 命令是根据depmod -a的输出/lib/modules/version/modules.dep来加载全部的所需要模块。可以通过modprobe -l来显示可以当前可以加载的模块。modprobe 在挂载模块是不用指定模块文件的路径,也不用带文件的后缀.o 或.ko, 而insmod 需要的是模块的所在目录的绝对路径,并且一定要带有模块文件名后缀的(modulefile.o 或modulesfile.ko )。 insmod比较重要的用途是用来测试模块的正确性,加载一般都是依靠modprobe。

用法:modprobe xxx.ko        #加载某个模块
modprobe -r xxx.ko     #卸载某个模块

2.3.lsmod:

lsmod 显示当前加载的所有 模块,相当于cat /proc/modules,假设你没有设定开机加载某个模块,比如ntfs,那么开机后执行lsmod,列表里不会有ntfs这个模块的,这时你再执行 mount -t ntfs xxx后,执行lsmod后列表里就会有ntfs这个模块了。
还要注意的是lsmod显示的是模块名,而不是别名(alias)。

2.4.modinfo

显示kernel模块的对象文件,以显示该模块的相关信息

三、系统如何完成动态加载

在内核中有一个“Automatic kernel module loading"功能被编译到了内核中。当用户尝试打开某类型的文件时,内核会根据需要尝试加载相应的模块。我们来看看驱动程序自动加载是怎么实现的:

  每一个设备都有Verdon ID, Device ID, SubVendor ID等信息。而每一个设备驱动程序,必须说明自己能够为哪些Verdon ID, Deviece

  ID, SubVendor ID的设备提供服务。以PCI设备为例,它是通过一个pci_device_id的数据结构来实现这个功能的。例如:RTL8139的pci_device_id定义为:

static struct pci_device_id rtl8139_pci_tbl[] = {
      {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
      {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
      ......
}

在模块安装的时候,depmod会根据模块中的rtl8139_pci_tbl的信息,生成下面的信息,保存到/lib/modules/uname-r /modules.alias文件中,其内容如下:

alias pci:v000010ECd00008138sv*sd*bc*sc*i* 8139too
alias pci:v000010ECd00008139sv*sd*bc*sc*i* 8139too
......

另外在/lib/modules/uname-r /modules.dep文件中还保存这模块之间的依赖关系,其内容如下:

(这里省去了路径信息。)

8139too.ko:mii.ko

在内核启动过程中,

  • 总线驱动程序会按总线协议进行总线枚举,并且为每一个设备建立一个设备对象(总线驱动程序总是集成在内核之中,不能够按模块方式加载,你可以通过make menuconfig进入Bus options,这里面的各种总线,你只能够选择Y或N,而不能选择M.)。
  • 每一个总线对象有一个kset对象,每一个设备对象嵌入了一个kobject对象,kobject连接在kset对象上,这样总线和总线之间,总线和设备之间就组织成一颗树状结构。
  • 当总线驱动程序为扫描到的设备建立设备对象时,会初始化kobject对象,并把它连接到设备树中,同时会调用kobject_uevent()把这个(添加新设 备的)事件,以及相关信息(包括设备的VendorID,DeviceID等信息)。
  • 通过netlink发送到用户态中。在用户态的udevd检测到这个 事件,就可以根据这些信息,打开/lib/modules/uname-r /modules.alias文件,根据 alias pci:v000010ECd00008138sv*sd*bc*sc*i* 8139too 得知这个新扫描到的设备驱动模块为8139too。
  • 于是modprobe就知道要加载8139too这个模块了,同时modprobe根据 modules.dep文件发现,8139too依赖于mii.ko,如果mii.ko没有加载,modprobe就先加载mii.ko,接着再加载 8139too.ko。

实验

在你的shell中,运行:

# ps aux | grep udevd

# kill -9 25063 然后跟踪udevd,在shell中运行:

 # strace -f /sbin/udevd --daemon  这时,我们看到udevd的输出如下:

 ......
 close(8)                                = 0
 munmap(0xb7f8c000, 4096)                = 0
 select(7, [3 4 5 6], NULL, NULL, NULL

我们发现udevd在这里被阻塞在select()函数中。 select函数原型如下:  int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);  

  • 第一个参数:nfds表示最大的文件描述符号,这里为7(明明是6 ?)。
  • 第二个参数:readfds为读文件描述符集合,这里为3,4,5,6.
  • 第三个参数:writefds为写文件描述符集合,这里为NULL。
  • 第四个参数:exceptfds为异常文件描述符集合,这里为NULL。 第五个参数:timeout指定超时时间,这里为NULL。

select函数的作用是:

如果readfds中的任何一个文件有数据可读,或者witefds中的任何一个文件可以写入,或者exceptfds中的任 何一个文件出现异常时,就返回。否则阻塞当前进程,直到上诉条件满足,或者因阻塞时间超过了timeout指定的时间,当前进程被唤醒,select返 回。 所以,在这里udevd等待3,4,5,6这几个文件有数据可读,才会被唤醒。现在,到shell中运行:  # ps aux | grep udevd root 27615 ...... strace -o /tmp/udevd.debug -f /sbin/udevd --daemon root 27617 ...... /sbin/udevd --daemon  udevd的进程id为27617,现在我们来看看select等待的几个文件: # cd /proc/27615/fd # ls -l udevd的标准输入,标准输出,标准错误全部为 /dev/null. 0 -> /dev/null 1 -> /dev/null 2 -> /dev/null  udevd在下面这几个文件上等待。  3 -> /inotify 4 -> socket:[331468] 5 -> socket:[331469] 6 -> pipe:[331470] 7 -> pipe:[331470] 

由于不方便在运行中插入一块8139的网卡,因此现在我们以一个U盘来做试验,当你插入一个U盘后,你将会看到strace的输出,从它的输出可以看到 udevd在select返回后,调用了modprobe加载驱动模块,并调用了sys_mknod,在dev目录下建立了相应的节点。 

execve("/sbin/modprobe", ["/sbin/modprobe", "-Q", "usb:v05ACp1301d0100dc00dsc00dp00"...] ...... mknod("/dev/sdb", S_IFBLK|0660, makedev(8, 16)) = 0 ......

这里modprobe的参数"usb:v05AC..."对应modules.alias中的某个模块。 可以通过udevmonitor来查看内核通过netlink发送给udevd的消息,在shell中运行: # udevmonitor --env 然后再插入U盘,就会看到相关的发送给udevd的消息。

四、内核模块加载的配置:

有时候需要一次性加载许多模块,需要在一个地方统一配置modprobe的选项等,有一个比较重要的文件: /etc/modprobe.conf , 在opensuse中,和它有关的还有modprobe.d/文件夹下的许多文件和 modprobe.conf.local 文件,在 /etc/modprobe.conf 里会include其它所有的文件,一般建议在 modprobe.conf.local 中修改自己的配置。  /etc/modprobe.conf 其实就是用于 写入模块的加载命令或模块的别名的定义等。 man modprobe.conf :

alias my-mod really_long_modulename为模块定义一个便于使用的别名

options modulename option...在加载模块时添加选项

install modulename command...使用自己定义的命令去加载指定的模块,如install fred /sbin/modprobe barney; /sbin/modprobe
              --ignore-install fred" 每次加载fred模块的时候用的是 “/sbin/modprobe barney; /sbin/modprobe
              --ignore-install fred”命令

remove modulename command...用自己定义的命令删除指定的模块。

include filename 引入其它文件

blacklist modulename 不再加载某个模块

五、内核模块开机自动挂载:

对于开机自动挂载模块,在redhat系统里,网上说在内核启动的过程中,init执行/etc/rc.d/rc.sysinit后,启动内核外挂模块 时会读取 /etc/modprobe.conf 这个文件。在2.4的内核中, 只 要直接修改/etc/modprobe.conf加入install xxx即可。2.6内核则需修改/etc/rc.d/rc.sysinit文件。具体的过程可以看:http://blog.csdn.NET/ioriqqe/archive/2009/11/05/4772033.aspx

而在suse里,可以在root权限编辑/etc/sysconfig/kernel文件,添加需要启动的模块

Linux I2C设备驱动开发全流程:从设备树到模块加载 I2C设备驱动是嵌入式Linux系统中连接硬件与内核的关键技术,其核心在于设备树(Device Tree)声明与内核驱动模块的精准匹配。原理上,设备树通过compatible字符串实现硬件能力描述,驱动则依托of_match_table完成动态绑定;技术价值体现在软硬解耦、跨平台复用与可维护性提升。典型应用场景包括环境光传感器、温湿度模块等I2C外设的快速集成。本文以AP3216C为例,完整覆盖设备树引脚配置、pinctrl电气参数设置、i2c_driver注册机制、devm_kzalloc内存管理及sys 阅读详情

相关推荐

depmod命令 生成模块映射文件

depmod命令可产生模块依赖的映射文件,在构建嵌入式系统时,需要由这个命令来生成相应的文件,depmod命令支持内核版本为“2.5.48”以上,比此版本老的内核使用指令“depmod.old”。 语法格式:depmod [参数] 常用参数: -a 分析所有可用的模块 -b 指定内核模块目录 -e 输出无法参照的符号 -F 提供内核编译时生成的system.map文件 -n 将各种内核映射文件打印到标准输出 -A 快速模式 参考实例 显示可用模块: [root@linuxcool ~]# depmod -a 列出已挂载但不可用的模块: [root@linuxco

Ubuntu开机自动加载驱动模块

目前我知道有两种方式来实现开机自动加载内核,一种是将驱动模块放到 /lib/modules/uname -r/ 中,然后在修改 /etc 下的 modules 等文件;另一种是直接编写开启自启脚本,将驱动安装放入其中。本文主要介绍第一种。

Super辉sir的博客 8817

Win11实时字幕还能这么玩?手把手教你打造专属‘AI字幕机’,告别视频网站无字幕困扰

本文详细介绍了如何利用Win11的实时字幕功能打造全平台通用的AI字幕系统。通过C#抓取程序、Node.js中转服务和前端展示界面的组合,实现自动抓取系统字幕并实时推送到任意网页视频的方案,有效解决在线视频无字幕的困扰。

weixin_33735077的博客 395

Linux命令描述,Linux命令介绍

Linux命令介绍depmod -a这个命令一般放在make modules_install之后。depmod可检测模块的相依性,供modprobe在安装模块时使用。严格说来,depmod -a命令和编译过程并没有关系,它是生成模块间的依赖关系,这样你启动新内核之后,使用modprobe命令加载模块时就能正确地定位模块。System.mapSystem.map是一个特定内核的内核符号表。它是你当前...

weixin_31185473的博客 563

基于Python+OpenCV中文及符号检测

一、项目背景与意义在图像处理、文档识别、自动翻译等场景中,中文及符号的准确检测是一个重要且复杂的任务。传统的字符检测方法往往对英文等拉丁字母系的识别效果较好,但对中文及特殊符号的识别准确率较低。本项目旨在利用Python编程语言结合OpenCV库,开发一个能够高效、准确地检测图像中中文及符号的系统,为相关领域的研究和应用提供技术支撑。二、技术实现图像预处理:利用OpenCV的图像处理功能,对输入的图像进行灰度化、二值化、滤波去噪等预处理操作,以提高中文及符号检测的准确性[1]。

2301_79809972的博客 1121

Windows非分页缓冲池内存泄漏实战:PoolMon与RAMMap高效排查指南

本文详细介绍了Windows系统中非分页缓冲池内存泄漏的实战排查方法。当系统出现卡顿且内存占用异常增长时,通过RAMMap工具快速定位非分页缓冲池异常,并利用PoolMon监控内核内存分配标签,精准锁定泄漏源。文章提供了从确认症状、安装工具到使用findstr命令溯源驱动文件的完整五步排查流程,并总结了常见泄漏标签与解决方案,帮助用户高效解决深层系统内存问题。

weixin_28455801的博客 1014

linux下的模块加载

一、什么是 modules?   modules 的字面意思就是模块,在此指的是 kernel modules;简单来说,一个模块提供了一个功能,如 isofs、minix、nfs、lp 等等。传统来讲,模块化有两个方法解决:设计者可以把各项功能分离到单独的叫做线程的处理中去,或者是将内核以包含/排除一些功能的方式重新编译。如果把功能分离到线程中去,那么内核就叫做“微内核”(micro-ker

zy799894671的专栏 1万+

33、密码学中的选择密文攻击与Cramer - Shoup加密方案

本文详细介绍了密码学中选择密文攻击的背景及其对Cramer-Shoup公钥加密方案的影响。该方案在决策Diffie-Hellman假设和抗碰撞哈希函数的基础上,能够有效抵御自适应选择密文攻击,并且其安全性无需依赖随机预言机模型。文章还分析了Cramer-Shoup方案的设计原理、加密与解密过程,以及其在标准假设下的安全性证明方法。此外,通过一系列相关练习,帮助读者进一步理解密码学概念如密文不可区分性、ElGamal加密、Goldwasser-Micali方案等。最后,文章展望了密码学的未来发展趋势,包括量子

vscode6remote的博客 100

一文看懂[driver]linux内核动态加载模块【值得收藏】

有时候需要一次性加载许多模块,需要在一个地方统一配置modprobe的选项等,有一个比较重要的文件: /etc/modprobe.conf , 在opensuse中,和它有关的还有modprobe.d/文件夹下的许多文件和 modprobe.conf.local 文件,在 /etc/modprobe.conf 里会include其它所有的文件,/sbin/modprobe。对于开机自动挂载模块,在redhat系统里,网上说在内核启动的过程中,init执行/etc/rc.d/rc.sysinit后,

m0_74282605的博客 2065

OP-TEE虚拟化支持详解

OP-TEE虚拟化支持解析 OP-TEE提供实验性虚拟化方案,支持多虚拟机共享安全执行环境。核心特性包括: 配置选项:CFG_VIRTUALIZATION启用虚拟化,CFG_VIRT_GUEST_COUNT限制虚拟机数量并分配均等内存资源; Hypervisor协作:需实现虚拟机生命周期通知、SMC参数转换、内存固定等关键协议; 当前限制:仅支持Armv8架构,硬件资源共享有限,采用静态内存配额机制; 架构实现:通过MMU分区切换和扩展内存分配器实现多租户隔离,Nexus核心层管理虚拟机上下文。该方案适用于

Linux内核架构师 109

从源码编译CesiumForUnreal

从源码编译CesiumForUnreal插件

专注GIS开发 5644

嵌入式学习linux内核驱动5——动态编译和plantform总线

系统维护文档记录已使用的type值。推荐使用未被占用的ASCII字符作为type。通过_IOC宏自动生成复合命令码。

m0_57137282的博客 1064

OpenClaw Manager Pro - 可视化管理工具

OpenClaw Manager Pro 是一个现代化的 Web 管理界面,用于管理多个 OpenClaw Gateway 实例。🎨美观的界面:深色主题,渐变设计,现代化 UI📡实时监控:WebSocket 实时推送状态和日志🔧完整管理:创建、编辑、删除、启动、停止 Gateway📊多渠道支持:飞书、Telegram、Discord、Slack、微信、钉钉🧩技能管理:可视化配置 61+ 个技能🌍跨平台:支持 macOS、Linux、Windows使用自定义模型系统会自动在中创建},

Maynor的博客 3087

【亲测免费】 推荐:Datto Block Driver - 轻松实现Linux实时快照备份

推荐:Datto Block Driver - 轻松实现Linux实时快照备份 在数据安全的世界里,高效可靠的备份方案至关重要。Datto Block Driver是一款开源的Linux内核模块,它解决了Linux系统实时快照的难题,带来了与Windows VSS类似的功能,让您的服务器备份变得更加简单和高效。 项目简介 Datto Block Driver(dattobd)是一个旨在解决实时、无...

gitblog_00092的博客 896

2026年3月GESP真题及题解(C++七级):物流网络

2026年3月GESP真题及题解(C++七级):物流网络

王老师青少年编程 1127

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Linux驱动管理

Linux驱动管理是一个复杂且重要的领域,涉及到驱动程序的开发、加载和管理。在Linux系统中,设备驱动程序通常以内核模块的形式存在,可以动态地加载和卸载。驱动程序的主要任务是将硬件设备的功能告知操作系统,并通过提供接口的方式完成硬件设备电子信号与操作系统及软件高级编程语言之间的互相翻译。Linux驱动管理工具如Linux Driver Manager可以帮助开发者管理驱动代码,编译成ko模块,并快速调试。

如无必要,勿增实体。 2658

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

动态加载驱动模块

1,修改Kconfig之前config下为布尔bool类型,非1即0,现在需要将模块改成tristate(三态)2,make menuconfig,发现从原来的方括号[]变为尖括号<>,将对应模块配置成 M3,修改Makefileobj- +=xxx.o一共有三种情况-y:把xxx.c编译进内核,即静态编译进内核镜像-m:把xxx.c编译成独立模块,即编译为独立.ko模块-$(CONFIG_xxx):条件编译,根据配置项决定编译方式(Kconfig中)

2501_92777307的博客 661

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

内核设备访问被拒?不是权限问题!VMware在Kernel 6.8+中遭遇的CAP_SYS_MODULE绕过失效真相(附systemd-boot参数级强制加载方案)

快速解决VMware无法打开内核设备问题!针对Kernel 6.8+中CAP_SYS_MODULE绕过失效导致的模块加载失败,提供systemd-boot参数级强制加载方案,无需降级内核或修改权限。适用于Arch/Ubuntu等主流发行版,稳定兼容新内核,值得收藏。

DebugLoom的博客 182

内核启动时,设备及驱动初始化的实现( 版本2.6.35.4)

<br />内核启动时,设备及驱动初始化的实现( 版本2.6.35.4)<br /> 参考了网页:http://blog.youkuaiyun.com/lemon_fantasy/archive/2009/02/17/3900590.aspx<br /> http://blog.chinaunix.net/u2/68846/showart_694377.html<br /><br /><br /> Uboot完成系统的引导并将Linux内核拷贝到内存之后,bootm -> do_bootm_linux()跳转到k

jinhongzhou的专栏 914

[Linux driver]解密module_init

在Linux底下写过driver模块的对这个宏一定不会陌生。module_init宏在MODULE宏有没有定义的情况下展开的内容是不同的,如果这个宏没有定义,基本上表明阁下的模块是要编译进内核的(obj-y)。 1.在MODULE没有定义这种情况下,module_init定义如下: #define module_init(x)        __initcall(x); 因为 #def

embedded_man2011 技术空间 1296

20260123 - Linux驱动学习笔记SPI子系统的匹配机制深度解析

时机MasterDeviceDriver匹配函数结果系统启动spi-imx.ko加载自动创建未加载无master和device已关联已存在已存在正在注册匹配并调用probe已存在已存在已绑定无直接使用private_data已存在已存在已绑定无沿指针链调用。

qq_50932511的博客 366

x4412开发板&ibox卡片电脑项目实战12-linux驱动的加载方法

http://blog.youkuaiyun.com/armeasy/article/details/39621265 在类unix操作系统中,驱动加载方式一般分为:静态加载和动态加载。静态加载就是把驱动程序直接编译到内核里,系统启动后直接被调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译下载内核,效率较低。动态加载利用了LINUX的module特性,可以在系统启动后用insmo

keleming1的博客 855

linux加载与使用ko驱动

linux驱动和有两种形式: 1:编译到内核 2:编译为ko模块 这里记录下ko模块使用方法. 首先cd到/var/lib/(内核版本)/drivers/ 在这里面找到要装载的模块ko文件 modprobe 驱动名 (不用加扩展名.ko) rmmod 可以用卸载模块 可以通过dmesg | tail 查看模块输出的一些信息,通过lsmod指令能看到加载了哪些模块...

dingquyuan5725的博客 561
上一篇: 基于Rook的Kubernetes存储方案
下一篇: /etc/resolv.conf文件中的search项作用
hxpjava1
博客等级 码龄19年 1365粉丝 511原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值