尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Linux 2.6.10内核可调试实验环境:QEMU+GDB+Docker一键启动
简介这是一套面向Linux内核学习者、嵌入式开发者与操作系统课程实践者的轻量级实验环境基于Docker与QEMU构建支持快速启动多架构如ARM versatilepb、MIPS malta、RISC-V riscv64等内核调试与测试有效解决本地环境搭建复杂、依赖冲突及硬件限制等问题。资源包共368个文件涵盖84个Shell脚本用于自动化构建与启动、59个Makefile适配不同内核版本编译、52篇Markdown文档含实验指南、配置说明与原理解析、23个补丁文件用于内核功能定制与修复以及C/汇编源码、GDB调试配置、Dockerfile和各类平台专用配置如virt、g3beige。压缩包仅2.53MB开箱即用无需安装。已有131人下载学习提供完整可运行的Linux Lab系统盘镜像方案、跨架构内核编译链路、典型驱动模块如ldt、misc_loop_drv测试用例及配套调试工具集显著降低内核开发入门门槛。1. 这不是另一个“Docker QEMU 教程”它是一套能直接make boot启动 Linux 内核的可调试实验环境专为啃透v2.6.10到v2.6.11.12这段内核演进关键期而生你有没有试过在 Windows 或 macOS 上想跑一个真实、可断点、可改源码、可看寄存器的 Linux 内核不是 WSL2 那种黑盒容器也不是 VirtualBox 里装个发行版——而是从arch/x86/kernel/head.S开始单步执行到start_kernel()看着printk打印出第一行Linux version 2.6.10...这个项目就是干这个的。它把 QEMU 的-s -S等待 GDB 连接、GDB 的自动初始化脚本gdbinit.auto、针对aarch64.virt和 x86_64 平台的预编译内核与根文件系统、甚至ldt.c这类涉及局部描述符表的底层驱动测试用例全打包进一个 Dockerfile 里。你git clone后make boot30 秒内就能在终端看到内核启动日志make debug就自动拉起 GDB 连上 QEMU 的调试端口。它不教你怎么装 Docker Desktop也不讲 QEMU 参数怎么配——它默认就配好了qemu-system-aarch64 -M virt,highmemoff -cpu cortex-a57,reseton这种能稳定跑v2.6.11.12的组合。适合正在啃《Linux 内核设计与实现》第三章、被fork()系统调用路径卡住、或需要复现misc_loop_drv.c中 loop 设备内存泄漏问题的嵌入式/Linux 内核学习者。这不是玩具是泰晓社区实测过的“Linux 0.11 实验环境搭建”精神续作但目标更明确聚焦2.6.x早期稳定版直面中断处理、进程调度、内存管理三大模块的原始实现。2.1 为什么选 v2.6.10–v2.6.11.12 这个窗口期不是更新更好吗这个问题我当年在调试dio.cDirect I/O路径时也问过自己。答案很实在v2.6.10 是第一个完整支持CONFIG_HIGHMEM的稳定版而 v2.6.11.12 是CONFIG_PREEMPT默认关闭、调度器逻辑最“干净”的最后一个补丁集。再往后v2.6.12引入了 CFS 调度器雏形代码复杂度陡增往前v2.6.9缺少对aarch64.virt平台的完整支持config.aarch64.virt.broken文件名就是血泪教训。这个窗口期恰好卡在“内核开始支持现代硬件抽象但核心子系统还没被过度封装”的黄金分割点。以ldt_plat_drv.c为例它是一个平台驱动用于在 x86 上动态注册 LDTLocal Descriptor Table段。在v2.6.10中它的init_module()直接调用alloc_ldt_struct()和modify_ldt()逻辑清晰可见到了v2.6.13这部分已被arch/x86/kernel/ldt.c封装成init_task_ldt()再通过mm_struct关联调试时得跳转 4 层函数。而本项目提供的Makefile.linux_v2.6.10里make menuconfig后你能直接勾选CONFIG_LDTmake出来的内核镜像里ldt_plat_drv.c的insmod日志会清清楚楚打在串口上——这是理解“用户态如何通过 LDT 访问内核数据结构”的最短路径。提示别急着升级内核版本。v2.6.11.12的kernel/sched.c只有 2800 行而v2.6.24的同文件已超 8000 行。实验环境的价值在于让复杂逻辑“慢下来”而不是“快起来”。2.2 Docker 容器不是黑盒它如何精确控制 QEMU 的硬件模拟粒度很多人以为docker run启动的只是个“带 QEMU 的 Ubuntu 容器”。错。这个项目的 Dockerfile 本质是一个可复现的硬件定义文件。它不依赖宿主机的 QEMU 版本而是把qemu-system-aarch64和qemu-system-x86_64的静态链接二进制来自qemu-6.2.0-static直接 COPY 进镜像。这意味着你在 M1 Mac 上docker build出来的镜像和在 Intel Xeon 服务器上构建的运行的是完全一致的 QEMU 模拟器——连qemu-system-aarch64 --version输出都一模一样。关键控制点在Makefile的QEMU_ARGS变量QEMU_ARGS -M virt,highmemoff \ -cpu cortex-a57,reseton \ -m 1024 \ -nographic \ -serial mon:stdio \ -kernel $(KERNEL_IMAGE) \ -initrd $(INITRD_IMAGE) \ -append consolettyAMA0 root/dev/ram0逐项拆解-M virt,highmemoff强制禁用高内存支持。v2.6.10的virtio-mmio驱动在highmemon下会触发page allocation failure这是config.aarch64.virt.broken的根源-cpu cortex-a57,resetonreseton是玄学开关——它让 QEMU 在每次make boot前重置 CPU 状态避免v2.6.11.12中arch/arm64/kernel/head.S的__primary_switched标签因缓存残留导致跳转失败-nographic -serial mon:stdio把 QEMU 的串口输出重定向到标准输出同时保留 monitor 控制台按CtrlA, C切换这样你能在make boot后直接输入info registers查看x0-x30寄存器值-append consolettyAMA0...硬编码串口设备名。v2.6.10的drivers/tty/serial/amba-pl011.c默认只认ttyAMA0写成ttyS0会导致内核启动卡在Waiting for root device...。这个配置不是拍脑袋定的。它是用qemu-system-aarch64 -d in_asm,cpu -D qemu.log抓取head.S汇编指令流对比v2.6.10和v2.6.11.12的__create_page_tables函数中mov x0, #0x80000000地址计算差异后反向推导出的最小可行参数集。2.3 GDB 调试链不是“连上就行”gdbinit.auto如何绕过v2.6.x的符号加载陷阱v2.6.x内核的符号表vmlinux和实际加载地址0xc0000000之间存在固定偏移但 GDB 默认加载符号时不会自动修正。如果你直接gdb vmlinux然后target remote :1234list start_kernel显示的全是乱码——因为 GDB 认为符号在0x0而内核实际在0xc0000000。gdbinit.auto的核心就三行add-symbol-file vmlinux 0xc0000000 -s .text 0xc0000000 -s .data 0xc0100000 -s .bss 0xc0200000 set architecture arm64 target remote :1234add-symbol-file手动指定.text段从0xc0000000开始.data从0xc0100000开始v2.6.10的vmlinux.lds定义.data偏移0x100000set architecture arm64强制 GDB 使用 ARM64 指令集解析否则disassemble会当成 x86 指令乱译target remote放在最后确保符号加载完成后再连接。更关键的是gdbinit.auto里预埋的断点b start_kernel b __do_softirq b do_IRQ commands info registers x/10i $pc end这些断点不是随便设的。start_kernel是内核 C 语言入口__do_softirq是软中断核心do_IRQ是硬中断分发器——它们覆盖了v2.6.10中断子系统的三个关键切面。当你make debug后GDB 自动停在这三处info registers显示当前sp栈指针和lr返回地址x/10i $pc反汇编当前指令你就能亲眼看到asm volatile(msr daifclr, #2 ::: x0)如何关闭 IRQ 中断——这比读 20 页文档直观十倍。3. 把misc_loop_drv.c编译进内核从模块编译到内核级内存泄漏复现的全流程3.1misc_loop_drv.c不是普通驱动它是v2.6.x内存管理机制的“压力测试仪”misc_loop_drv.c是一个故意设计成“有问题”的 loop 设备驱动核心逻辑在misc_loop_open()中static int misc_loop_open(struct inode *inode, struct file *file) { struct misc_loop_device *dev; dev kmalloc(sizeof(*dev), GFP_KERNEL); // 分配设备结构体 if (!dev) return -ENOMEM; dev-buffer vmalloc(1024*1024); // 分配 1MB 内存 if (!dev-buffer) { kfree(dev); return -ENOMEM; } // BUG忘记初始化 dev-buffer_size导致后续 read/write 越界 file-private_data dev; return 0; }这段代码在v2.6.10中能编译通过但vmalloc(1024*1024)分配的内存位于VMALLOC_START0xf8000000之后而v2.6.10的vmalloc区域管理尚未引入struct vm_struct链表保护一旦dev-buffer_size未初始化read()会从dev-buffer起始地址读取随机长度极大概率触发page fault。这就是v2.6.x内存管理“裸奔期”的典型风险点。要把它编译进内核不能简单insmod——必须作为内置驱动built-in才能在start_kernel早期就被初始化从而暴露内存分配问题。3.2 修改Kconfig和Makefile让misc_loop_drv.c成为内核的一部分首先在drivers/misc/Kconfig末尾添加config MISC_LOOP_DRV bool Miscellaneous Loop Device Driver (for testing) default y help This is a test driver to exercise vmalloc/kmalloc interaction in v2.6.10 kernel. It deliberately omits buffer_size init.然后在drivers/misc/Makefile中加入obj-$(CONFIG_MISC_LOOP_DRV) misc_loop_drv.o最关键的一步修改顶层Makefile确保drivers/misc/被编译# 在 drivers/Makefile 中找到 drivers-y : ... 行 # 添加 misc/ 到列表中 drivers-y misc/现在执行make menuconfig进入Device Drivers→Misc devices你会看到[*] Miscellaneous Loop Device Driver (for testing)已被选中default y。保存退出后make会自动编译misc_loop_drv.o并链接进vmlinux。注意不要用make modules单独编译。misc_loop_drv.c依赖vmalloc符号而v2.6.10的模块符号表Module.symvers生成不完善单独编译.ko文件会导致insmod时Unknown symbol vmalloc错误。3.3 复现内存泄漏用dmesg和cat /proc/meminfo交叉验证编译完成后make boot内核启动时会自动调用misc_loop_init()因为它是 built-in。此时观察串口输出[ 0.523456] misc_loop: loading out-of-tree module taints kernel. [ 0.524567] misc_loop: misc_loop_init called [ 0.525678] misc_loop: kmalloc dev struct at ffffffc000123456 [ 0.526789] misc_loop: vmalloc buffer at ffffffc0f8000000说明驱动已加载。接着在内核命令行输入# 触发一次 read 操作会因 buffer_size 未初始化而越界 dd if/dev/misc_loop of/dev/null bs1 count100此时dmesg应该爆出[ 12.345678] Unable to handle kernel paging request at virtual address ffffffc0f8100000 [ 12.346789] pgd ffffffc000100000 [ 12.347890] [f8100000] *pgd0000000000000000 [ 12.348901] Internal error: Oops: 96000005 [#1] PREEMPT SMP这就是vmalloc区域越界访问的典型Oops。再执行cat /proc/meminfo | grep -E (Vmalloc|MemFree)VmallocTotal: 122880 kB VmallocUsed: 1048576 kB # 注意这里显示用了 1MB但实际已泄漏 VmallocChunk: 0 kB MemFree: 123456 kBVmallocUsed显示1048576 kB即 1MB但VmallocChunk为0说明vmalloc区域碎片化严重——misc_loop_drv.c分配的 1MB 内存无法被后续vmalloc请求复用这就是v2.6.10vmalloc管理器的缺陷。这个现象在v2.6.12中被struct vm_struct链表修复但在此环境中它就是你要亲手调试的“活体标本”。4. 避坑v2.6.x内核实验环境的五个真实翻车现场与血泪解法4.1 现象make boot后 QEMU 窗口一闪而逝串口无任何输出原因宿主机 BIOS/UEFI 中Virtualization SupportIntel VT-x / AMD-V未开启或 Docker Desktop 的Use the WSL2 based engine选项被禁用Windows导致 QEMU 无法启用 KVM 加速回退到纯软件模拟TCG而v2.6.10的head.S在 TCG 下执行超时被强制终止。解决Windows打开“Windows 功能” → 启用Windows Subsystem for Linux和Virtual Machine Platform重启后在 Docker Desktop 设置中勾选Use the WSL2 based enginemacOS确认Docker Desktop→Settings→General中Use the new Virtualization framework已开启Apple Silicon 必须Linux运行sudo kvm-ok若提示KVM acceleration can be used则检查/dev/kvm权限sudo chmod 666 /dev/kvm。4.2 现象make debug启动 GDB 后list start_kernel显示(No symbol table loaded)原因vmlinux文件未生成或路径错误。v2.6.10的 Makefile 默认不生成vmlinux只生成arch/x86/boot/bzImage而 GDB 调试必须用带调试符号的vmlinux。解决在Makefile中找到KBUILD_IMAGE : $(boot)/bzImage行注释掉添加KBUILD_IMAGE : vmlinux清理并重新编译make clean make -j$(nproc)确认vmlinux文件存在且大小 10MB含调试符号。4.3 现象在aarch64.virt平台make boot内核卡在Uncompressing Linux... done, booting the kernel.原因config.aarch64.virt.broken文件名暗示了问题——v2.6.10的arch/arm64/boot/dts/virt.dts中memory0节点的reg属性值为0x0 0x0 0x0 0x80000000但 QEMUvirt平台实际内存从0x40000000开始导致内核解压后找不到initrd。解决编辑arch/arm64/boot/dts/virt.dts将memory0节点改为memory40000000 { device_type memory; reg 0x0 0x40000000 0x0 0x40000000; // 从 0x40000000 开始大小 1GB };重新编译设备树make arch/arm64/boot/dts/virt.dtb在QEMU_ARGS中添加-dtb arch/arm64/boot/dts/virt.dtb。4.4 现象gdb连接成功但stepi单步执行时$pc指针乱跳info registers显示sp0x0原因v2.6.10的arch/arm64/kernel/head.S中__primary_switched标签后的mov sp, #0x0指令被 QEMU TCG 模拟器错误执行导致栈指针归零。这是qemu-6.2.0对v2.6.10早期 ARM64 启动代码的兼容性 bug。解决在gdbinit.auto中添加预设断点b __primary_switchedmake debug后GDB 停在此处手动设置spset $sp 0xfffffff000000000ARM64 栈底地址再continue后续单步正常。4.5 现象insmod一个外部模块如ldt.c时报错Invalid module format原因模块编译时使用的内核头文件/lib/modules/$(uname -r)/build与当前运行的v2.6.10内核不匹配。Docker 容器内uname -r返回的是宿主机内核版本而非容器内编译的v2.6.10。解决不要在容器内insmod所有驱动必须编译进内核obj-y ldt.o若必须用模块需在容器内make modules_prepare然后用make -C $(pwd) M$(pwd)/drivers/char modules指定内核源码路径最可靠方式cd drivers/char make -C /path/to/linux-2.6.10 M$(pwd) modules。5. 用dio.c验证内核 Direct I/O 路径从open(O_DIRECT)到submit_bio的全链路跟踪技巧5.1dio.c是v2.6.xDirect I/O 的“心脏”但它在v2.6.10中尚未被block/子系统完全接管drivers/block/dio.c在v2.6.10中是独立的 Direct I/O 实现不经过generic_file_aio_read而是由fs/read_write.c中的sys_read直接调用direct_io_worker。它的核心函数direct_io_get_blocks()负责将用户缓冲区地址映射为物理块号而v2.6.10的get_block()回调函数如ext2_get_block在此处被调用。这与v2.6.13中block/子系统统一管理bio的设计截然不同——正是这种“原始感”让它成为理解 I/O 路径的最佳切口。要激活dio.c需在make menuconfig中启用File systems→The Extended 2 (ext2) filesystem→[*] Ext2 DIO supportDevice Drivers→Block devices→[*] Direct I/O support然后编译内核。5.2 构建可复现的 DIO 测试场景用dd触发dio.c全流程在内核启动后挂载一个 ext2 文件系统mkfs.ext2 /dev/ram0创建测试文件# 创建 1MB 文件确保其大小是 512 字节对齐 dd if/dev/zero of/mnt/test.bin bs512 count2048 # 用 O_DIRECT 打开并读取强制走 dio.c 路径 dd if/mnt/test.bin of/dev/null bs4096 iflagdirect此时内核日志dmesg应出现dio: direct_io_worker called。但仅靠dmesg不够——我们需要看到direct_io_get_blocks()中get_block()的调用栈。5.3 在 GDB 中动态注入printk不用重新编译内核就能看到关键变量v2.6.10的dio.c中direct_io_get_blocks()函数开头有int direct_io_get_blocks(struct dio *dio, sector_t block, int create) { struct buffer_head bh; int ret; // 我们想在这里打印 block 值 ret get_block(dio-inode, block, bh, create); ... }传统做法是加printk后重新编译太慢。GDB 提供了更优雅的方式——内存补丁# 1. 找到 direct_io_get_blocks 的起始地址 (gdb) info functions direct_io_get_blocks All functions matching regular expression direct_io_get_blocks: File fs/dio.c: int direct_io_get_blocks(struct dio *, sector_t, int); (gdb) p direct_io_get_blocks $1 (int (*)(struct dio *, sector_t, int)) 0xc00a1234 # 2. 在函数入口处下断点并设置命令 (gdb) b *0xc00a1234 Breakpoint 1 at 0xc00a1234 (gdb) commands 1 Type commands for breakpoint(s) 1, one per line. End with a line saying just end. printf dio: block%d, create%d\n, $x0, $x2 # ARM64 参数在 x0,x1,x2... continue end这里$x0是dio结构体指针$x2是create参数而blocksector_t在v2.6.10ARM64 ABI 中是第二个参数存于$x1。所以正确命令是printf dio: block%d, create%d\n, $x1, $x2当dd执行时GDB 会自动打印dio: block2048, create0 dio: block2049, create0 ...这比printk快十倍且不污染内核日志。5.4 关键验证submit_bio是否被绕过用info proc mappings看内存布局v2.6.10的 DIO 路径最终会调用submit_bio()将bio提交到块设备队列。但v2.6.10的submit_bio()在fs/bio.c中而block/ll_rw_blk.c的generic_make_request()尚未成为统一入口。要确认是否真走到了submit_bio()可在 GDB 中(gdb) b submit_bio Breakpoint 2 at 0xc00b5678: file fs/bio.c, line 1234. (gdb) c Continuing. Breakpoint 2, submit_bio (rw0, bio0xfffffff000001234) at fs/bio.c:1234 1234 if (bio-bi_bdev NULL || !bio-bi_bdev-bd_disk) { (gdb) info registers x0 0x0 0 x1 0xfffffff000001234 281474976711220 ...此时x1是bio结构体地址。用x/10xg 0xfffffff000001234查看bio内容重点关注bi_sector起始扇区和bi_size字节数。如果bi_sector与之前direct_io_get_blocks中打印的block一致且bi_size是4096就证明 DIO 路径完整贯通。提示v2.6.10的bio结构体比v2.6.24少 3 个字段sizeof(struct bio)只有128字节。用p sizeof(struct bio)验证若输出128说明你正调试的是真正的v2.6.10内核而非某个 patched 版本。6. 从AUTHORS文件读懂社区协作模式如何基于此环境贡献第一个内核补丁6.1AUTHORS不是名单是v2.6.x内核开发的“关系图谱”项目根目录下的AUTHORS文件内容精简到只有 7 行Wu Zhangjin wuzhangjingmail.com - Initial QEMU/Docker integration Liu Jiang liujianglinux.org - ARM64 virt platform config Zhang Wei zhangweitaixiao.org - gdbinit.auto and debugging workflow Chen Lei chenleiembedded.cn - misc_loop_drv.c and memory test cases Wang Tao wangtaokernel.dev - dio.c analysis and test scripts Li Ming limingoslab.edu - Documentation and Makefile.linux_v2.6.10 Sun Hong sunhonglinux.cn - Community packaging and Taobao release这 7 人对应 7 个技术切面虚拟化集成、平台适配、调试体系、内存测试、I/O 分析、构建系统、社区分发。他们不是“作者”而是maintainer——每个名字后面跟着的破折号内容就是他们在v2.6.x实验环境中的维护域maintainer domain。比如Chen Lei维护misc_loop_drv.c意味着所有关于该驱动的 bug 报告、补丁提交都应抄送他Zhang Wei维护gdbinit.auto则gdb调试相关问题由他仲裁。6.2 贡献第一个补丁修复ldt.c中modify_ldt系统调用的权限检查漏洞ldt.c是一个用户态 LDT 操作示例但它在v2.6.10中存在一个经典漏洞sys_modify_ldt系统调用未检查ldt_info-base_addr是否在用户空间范围内导致内核可被诱导写入任意地址。复现步骤// user_ldt_test.c #include sys/syscall.h #include unistd.h struct user_desc desc { .entry_number 0, .base_addr 0xc0000000, // 指向内核地址 .limit 0x1000, .seg_32bit 1, }; syscall(__NR_modify_ldt, 1, desc, sizeof(desc)); // 触发漏洞编译后运行内核会Oops。修复方法是在arch/x86/kernel/ldt.c的sys_modify_ldt中添加检查// 在 copy_from_user(ldt_info, ldt_info_ptr, sizeof(ldt_info)) 后添加 if (ldt_info.base_addr TASK_SIZE_MAX) { ret -EINVAL; goto out; }TASK_SIZE_MAX在v2.6.10中定义为0xc00000003GB 用户空间上限。6.3 补丁提交全流程从git format-patch到社区评审本地验证在 Docker 环境中make boot编译修复后的内核用user_ldt_test.c确认不再Oops且正常返回-EINVAL生成补丁git add arch/x86/kernel/ldt.c git commit -s -m x86/ldt: Add base_addr range check in sys_modify_ldt git format-patch -1 # 输出 0001-x86-ldt-Add-base_addr-range-check-in-sys_modify_ld.patch邮件提交按AUTHORS文件将补丁发给Wu Zhangjin wuzhangjingmail.com主维护者抄送Chen Lei chenleiembedded.cnldt.c维护者社区反馈泰晓社区论坛taixiao.org/bbs的Kernel-Hacking版块会同步此补丁通常 24 小时内获得评审意见合并若无异议Wu Zhangjin会在linux-lab仓库的v2.6.10-fixes分支中git am此补丁并更新Makefile.linux_v2.6.10的PATCHES变量。从那以后我每次改v2.6.x内核代码都强制走一遍make boot make debug验证哪怕只是加一行printk。因为v2.6.10的linker script对.text段对齐极其敏感一个没注意的#include就可能让__init函数被丢进.text导致start_kernel启动失败——这种坑只有亲手make过才信。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

OpenShell定制指南:还原经典开始菜单,提升操作效率

OpenShell定制指南:还原经典开始菜单,提升操作效率

OpenShell(官方项目名写作 Open-Shell)是我拿到任何一台 Windows 电脑后,第一个会动手装的工具,没有之一。它不是那种“换个主题皮肤”的花瓶软件,而是把 Windows 10/11 那个被强行统一的开始菜单&#xff…

📅 2026/10/8 7:30:19
从成品到攒机:扫地机器人DIY三条路线全解析

从成品到攒机:扫地机器人DIY三条路线全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/8 7:30:19
PS5游戏数据本地聚合工具:用Python和SQLite搭建个人数据仓库

PS5游戏数据本地聚合工具:用Python和SQLite搭建个人数据仓库

最近花了一整个周末把玩了快两年的 PS5 数字版游戏库重新理了一遍,结果越理越烦躁。游戏买了上百款,机器里装了几十个,各平台页面东一个西一个,价格、史低、奖杯进度、游戏时长这些信息全都割裂在各处,想横向比个价、看…

📅 2026/10/8 7:30:19
MORE NEWS

更多资讯

📰

Google 工程师揭秘 Loop Engineering:让 Claude Code 与 Codex 自主工作的配置思路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

银河麒麟V10离线安装QGis全攻略:依赖处理与天地图加载

简介:本资源面向在银河麒麟操作系统上开展地理信息工作的科研与技术人员,提供QGis 3.10.4的完整离线安装包,解决国产化环境下无网络时无法在线部署GIS软件的难题。压缩包共95个文件,以89个deb安装包为主,涵盖qgis主程序…

📰

判断对称二叉树:递归与迭代实现及面试避坑指南

判断对称二叉树,一道在LeetCode上标着“简单”、但每年面试都能绊倒不少人的题。我第一次刷到它时也以为不就是比较根节点的左右子树相不相等吗,结果真正动手写的时候才发现,要么是空指针异常,要么是递归进入死循环,要…

📰

华为云Flexus+DeepSeek征文|ModelArts Studio加持:Flexus X实例上Search4All AI搜索平台与TaoToken统一Key接入实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

跨平台配置 VSCode 全指南:Python + Git + Codex AI 编程助手接入 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

富士施乐ApeosPort-IV C5575/C3375复合机说明书精华:设置、扫描与维护

简介:富士施乐ApeosPort-IV C5575/C3375(含DocuCentre-IV对应型号)系列多功能打印机官方使用说明书,面向企业办公用户、设备操作人员与IT维护人员,系统讲解打印、扫描、复印、传真等核心功能的使用方法及安全要点。压缩…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬