news 2026/9/29 13:34:19

Linux 0.01内核编译实践:在Redhat 9.0下重编与Bochs启动

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 0.01内核编译实践:在Redhat 9.0下重编与Bochs启动

简介:这份PDF面向操作系统学习者与内核开发爱好者,是一篇关于Linux 0.01早期内核改造实践的技术文献,尤其适合希望从源码层面理解操作系统启动过程的读者。其基于Redhat 9.0平台,完整讲解约9000行代码的Linux 0.01编译、运行与启动方法,内容涵盖编译环境与GNU工具链选择、AT&T语法汇编器适配、源代码语法修正、动态链接系统调用添加,以及选用Linux 0.11根文件系统的依据,并对两个版本的文件系统代码做了对比分析,对理解早期Linux内核结构和系统复现实验有直接参考价值。压缩包只有一个PDF文档,大小约211KB,以期刊论文形式组织,正文包含改造思路、关键步骤与运行实例,适合配合内核源码逐节研读。目前已有348人浏览学习,适用于操作系统课程设计、内核入门分析及Linux系统开发等场景。

1. Linux 0.01:9000 行代码,却是最值得重编一次的操作系统

如果你正在做操作系统课程设计或编译原理实验,大概率会遇到同一个困境:手边能拿到的 Linux 源码动辄几百万行,打开源码树根本不知道该从哪下刀。Linux 0.01 是 Linus 最早发布的版本,全部代码只有 9000 行左右,却已经具备多任务、多用户机制、进程管理、设备管理、内存管理和文件系统这些核心部件,被很多人当作“操作系统的 Hello World”。但它的原始代码有一个硬伤:1991 年的工具链早就变了,as86 汇编器、老式 gcc 内嵌汇编语法、被删除的编译选项,导致代码拿到今天直接编译必挂。这篇 PDF 记录的正是基于 Redhat 9.0 平台把 Linux 0.01 改造、编译、并在 bochs 虚拟机里独立启动的全过程,包括 Makefile 修改、bootloader 重写、动态链接系统调用补全和根文件系统选型。适合想在一两个晚上完整走一遍“改内核源码 → 编内核 → 引导启动”整条链路的人。

2. 环境选型:为什么是 Redhat 9.0,以及 Makefile 的三个改名三个去选项

2.1 先接受一个现实:Linux 0.01 的原始代码在今天已经编不过

我第一次拿到 Linux 0.01 源码时,第一反应是在 Ubuntu 上直接 make,结果在内嵌汇编那一关就翻车。原因不复杂:当年 Linus 的开发环境是 as86 汇编器加老式 gcc,其中 boot.s 用 Intel 语法写成,其余汇编文件全部是 AT&T 语法;到了 Redhat 9.0 时代,as86 已经退出主流,GNU 工具链的 as 成了事实标准。更麻烦的是老 gcc 支持的那些优化选项,比如 -fcombine-regs、-mstring-insns,在今天会被直接判定为非法参数。

所以改造的第一原则不是“把代码升级到新语法”,而是“选一个语法代差最小的平台”。Redhat 9.0 的工具链保留了部分老 GNU 时代的习惯,和 0.01 源码之间的鸿沟比现代发行版小得多;加上 bochs 对那个时代硬件抽象的支持非常完整,所以论文选它作为编译环境是有充分理由的。我当时在虚拟机里装了一个 Redhat 9.0,把 gcc、binutils、make 都装齐,整个实验就在这一套环境里完成,没有去折腾交叉编译。

2.2 开发环境准备:装好 gcc、binutils、make 和 bochs

进入源码目录之前,先把工具链检查一遍。Redhat 9.0 默认安装通常已经带有 gcc 和 binutils,但为了确认,建议先跑一遍:

# 检查核心工具是否存在,同时看版本,判断是不是 GNU 工具链 gcc --version as --version ld --version make --version bochs --version

逻辑说明:gcc 负责 C 源码编译,as 负责 AT&T 语法的汇编,ld 负责链接,make 负责按 Makefile 组织构建,bochs 提供 x86 保护模式的仿真环境。五个工具缺一个,后面每一步都没法继续。Redhat 9.0 自带的 gcc 版本比较接近 0.01 年代的语法习惯,这正是它作为实验平台的价值——如果非要在 gcc 13 上硬编,光内嵌汇编的约束写法就够改半天。

参数说明:--version只做存在性和版本确认;如果哪一条提示 command not found,用 Redhat 9.0 安装光盘里的 RPM 包补上。装完后建议顺手打开源码目录里的 include/linux/sys.h 扫一眼,确认 sys_call_table 的声明结构,后面补系统调用要频繁用到它。

2.3 Makefile 的整体修改:三个改名、三个去选项、一个加选项

这是整个改造里最机械但也最容易漏的一步。Linux 0.01 源码里每个子目录都带独立 Makefile,不是只改根目录那一份就完事。论文明确列出了四类改动:工具名称改名、汇编选项调整、编译选项调整、CPU 指令集限制。

# 以根目录 Makefile 为例,改动点如下(其它子目录照做): # 1) 三个改名:gas -> as,gld -> ld,gar -> ar # 2) 去掉 as 的 -c 选项(老汇编器用来“只汇编不链接”,现在已不需要) # 3) 去掉 gcc 的 -fcombine-regs 与 -mstring-insns(选项本身已废弃) # 4) 增加 -m386,限制指令集,保证内核能在 80386 上跑 # 用 grep 找出所有 Makefile,逐个确认 find . -name Makefile -o -name makefile | xargs grep -n "gas\|gld\|gar"

逻辑说明:gas、gld、gar 是早期 GNU 工具链带前缀的命名,后来统一改成 as、ld、ar;Makefile 里还是旧名字的话,make 会直接报 command not found。-m386 把编译目标钉在 80386 指令集上,避免编译器生成 80486 之后才有的指令,这个在 bochs 默认 CPU 模型下尤其重要。

参数说明:find ... | xargs grep是为了把所有用到旧工具名的位置一次性找出来,避免漏改子目录。改完之后建议先执行 make clean 再 make,否则旧的目标文件会和新编译产物混在一起,产生一些难以定位的链接错误。

3. 汇编迁移:boot.s 重写成 AT&T 语法,再把内嵌汇编的寄存器约束删干净

3.1 boot.s:从 as86 迁移到 AT&T 语法,再用 objcopy 收尾

boot.s 是 Linux 0.01 的 bootloader,当年用 as86 汇编器加 Intel 语法写成。为了统一到 GNU as,需要按 AT&T 语法重写。文件很小,规模大概几百行,直接手工重写比用转换工具再整理更可控。重写后的启动代码大致长这样:

# boot.s 关键片段(AT&T 语法示意) .code16 .text .globl _start _start: movw %cs, %ax # cs 指向启动代码段 movw %ax, %ds # 初始化数据段寄存器 movw %ax, %es movw %ax, %ss movw $0x7c00, %sp # BIOS 加载 boot 到 0x7c00,栈从这里往下长 call load_kernel # 读软盘,把 setup 和 system 模块载入内存 ljmp $0x0000, $setup_start # 跳转到 setup 代码继续初始化

逻辑说明:boot.s 的核心任务是初始化段寄存器、建立临时栈、从软盘读入后续模块,最后跳转给 setup 代码。注意 AT&T 语法的方向是“源操作数在前、目的操作数在后”,和 Intel 语法正好相反,重写时最容易在这里翻车。$0x7c00是立即数,BIOS 把引导扇区加载到物理地址 0x7c00,栈指针设到这里是常规做法。

参数说明:.code16告诉 as 生成 16 位代码,因为引导扇区运行在实模式下;ljmp $0x0000, $setup_start里的 0x0000 是段地址,setup_start 是段内偏移。

汇编完成后,as 默认输出 ELF 格式,但引导扇区需要的是纯二进制镜像,所以必须转换:

# 把 boot.o 里的代码段提取成纯二进制,供引导扇区使用 as -o boot.o boot.s objcopy -O binary -j .text boot.o boot.bin

逻辑说明:-j .text只提取代码段,-O binary去掉 ELF 头输出原始二进制。这一步不做的话,bochs 会把 ELF 文件头当成可执行代码执行,开机直接就死。

参数说明:tools/build.c 也要同步调整,它负责把 boot、setup、system 三段拼接成最终的内核镜像文件,如果 boot 的输出格式变了而 build.c 没跟上,拼接结果会错位。

3.2 C 引用汇编变量的下划线问题,以及 align 参数变化

老版本汇编器在引用 C 语言全局变量时,要求变量名前加一个下划线,例如_counter;现在的 gcc 生成符号时已经不需要这个下划线,所以源码里所有汇编文件引用 C 变量的地方都要去掉_。这个改动看着简单,但涉及面很广,boot、kernel、mm、fs 每个目录的 .s 文件里都有。

# 先把所有引用 C 变量的下划线找出来,逐个确认再改 grep -rn "_[a-zA-Z][a-zA-Z0-9_]*" boot/ kernel/ mm/ fs/

逻辑说明:.s文件里形如movl _jiffies, %eax的代码,改成movl jiffies, %eax即可。注意只动汇编文件里对全局符号的引用,不要动 C 源码里的变量名。

参数说明:grep 的结果里会混入字符串常量和注释,所以要人工逐个过一遍。另一个隐蔽坑是 align 指令:早期版本用乘方数表示对齐量,align 2意思是 2 的 2 次方即 4 字节对齐;现在的 as 直接使用字节数,所以align 2要改成align 4。对照关系如下:

早期写法(乘方数)实际对齐字节数现在写法
align 01align 1
align 12align 2
align 24align 4
align 38align 8
align 416align 16

参数说明:这个表只用于汇编指令 align 的换算。如果你编译通过但内核运行到某个边界就异常,回头查一下是不是 align 值没换算,数据对齐错了会引发 GP 异常。

3.3 内嵌汇编:删寄存器约束,别连指令一起删掉

Linus 在 0.01 里大量使用内嵌汇编,但当时的语法要求人工指定变量使用的 CPU 寄存器,后来编译器已经能够自动分配寄存器,这些指定就成了多余甚至有害的代码。论文里明确提到要删掉asm("ax")这类代码,以及内嵌汇编中所有对寄存器内容的无效声明,比如"cx","di","si"。

/* 修改前:手写 clobber 列表和寄存器约束 */ __asm__("movl %1, %%eax\n\t" "addl %2, %%eax" : "=a" (result) : "a" (a), "c" (b) : "cx", "di", "si"); /* 修改后:交给编译器自动分配寄存器 */ __asm__("movl %1, %%eax\n\t" "addl %2, %%eax" : "=r" (result) : "0" (a), "r" (b));

逻辑说明:修改前"=a"强制结果放在 eax,"cx","di","si"告诉编译器这些寄存器会被改动,但实际内嵌汇编里根本没有改动它们,这是无效声明;修改后用"=r"让编译器自行选择寄存器,输入操作数"0"表示与输出操作数共享同一个寄存器。

参数说明:冒号分隔的输出操作数、输入操作数、clobber 区是三段式结构,删的时候别把逗号结构弄乱。最稳妥的做法是每个文件改完先单独编译,比如gcc -c kernel/sched.c,确认没有语法错误再继续下一个文件,避免一次性改完几十个文件后找不到问题源头。

4. init() 与动态链接:从引导到 Shell,中间隔着三个关键改造

4.1 init() 函数的执行顺序:setup、打开 tty0、然后才轮到 fork

init() 是内核启动后的第一个用户态进程入口,Shell 能不能弹出来,很大程度上看这个函数的执行顺序。论文给出的关键代码,按逻辑恢复 OCR 错误后如下:

static char *argv[] = { "-", NULL }; static char *envp[] = { "HOME=/usr/root", NULL }; static char vmsg[] = "\r\nLinux-0.01-rh9 ==="; static char gmsg[] = "Adapted\r\n\r\n"; void init(void) { int i, pid; setup(); /* 读硬盘分区参数,mount 根文件系统 */ (void) open("/dev/tty0", O_RDWR, 0); /* 打开终端 */ (void) dup(0); /* 复制句柄 -> 标准输出 */ (void) dup(0); /* 再复制 -> 标准错误 */ printf("%d buffers = %d bytes buffer space\n\r", NR_BUFFERS, NR_BUFFERS * BLOCK_SIZE); printf(vmsg); printf(gmsg); while (1) { if ((i = fork()) < 0) printf("Fork failed in init\r\n"); else if (!i) { /* 子进程 */ close(0); close(1); close(2); setsid(); (void) open("/dev/tty0", O_RDWR, 0); (void) dup(0); (void) dup(0); _exit(execve("/bin/sh", argv, envp)); } pid = wait(&i); printf("child %d died with code %04x\n", pid, i); sync(); } _exit(0); /* NOTE! _exit, not exit() */ }

逻辑说明:setup() 在第一行执行,它读取硬盘分区参数并装入根文件系统;随后以读写方式打开 /dev/tty0,并用两次 dup(0) 复制出标准输出和标准错误句柄。之后进入无限循环:fork 出子进程后,子进程先关闭继承自父进程的三套标准句柄,再重新打开 tty0 并用 dup 重建 stdin/stdout/stderr,最后调用 execve 把 /bin/sh 装入内存运行。父进程则通过 wait() 阻塞,等 Shell 退出后打印状态并再次循环。

参数说明:这里最需要注意的细节是最后一行_exit(0)而不是exit(0)。init 进程处在内核初始化上下文,exit() 会多做用户态缓冲区 flush 一类的事,在这个阶段会导致行为异常;用 _exit 直接退出才是正确姿势。Shell 每次退出都会让父进程打印一行死亡状态,这其实是调试时可以观察的重要信号。

4.2 补动态链接系统调用:这部分得对照 Linux 0.11 抄作业

Shell 能启动不代表所有命令都能跑。多数 Shell 命令是动态链接的,运行时需要内核提供完整的系统调用接口,而 Linux 0.01 的系统调用表比 0.11 少了不止一项。论文的做法是分析 0.01 与 0.11 的文件系统代码,发现二者在文件系统和可执行文件加载部分没有本质差别,于是参照 0.11 补齐缺失的系统调用。

# 把 0.11 的系统调用声明表和分发表拿来做 diff,这是最直接的抄作业入口 diff -u linux-0.01/include/unistd.h linux-0.11/include/unistd.h | less diff -u linux-0.01/include/linux/sys.h linux-0.11/include/linux/sys.h | less

逻辑说明:include/unistd.h 里定义了__NR_开头的系统调用号宏;include/linux/sys.h 里的 sys_call_table 是系统调用分发表,内核根据调用号在这里查表跳转。diff 出来的差异项,就是 0.01 缺失的调用。需要重点核对的调用包括 fork、execve、waitpid、open、close、read、write、dup、mount、signal、getdents、time、uname 等,这些是 Shell 及其外部命令运行时的基础依赖。

参数说明:不要直接把 0.11 的 unistd.h 和 sys.h 整个替换过来,0.11 里新增的数据结构和系统调用实现,会带来新一轮语法不兼容。正确做法是只迁移与动态链接、Shell 运行相关的部分,迁移完后在 sys.c、fork.c、exit.c 里补齐对应实现。

提示:补系统调用时先在 sys_call_table 里占好位置,再写函数实现,最后回填 unistd.h 的调用号宏。顺序反了容易出现“调用号对不上、查表查到空指针”的问题。

4.3 根文件系统选用 Linux 0.11:要用 Minix 结构,不能拿现代发行版顶替

这步决定内核能不能 mount 上根文件系统。Linux 0.01 和 0.11 使用的都是早期 Minix 文件系统,而现代发行版默认的 ext4/xfs 无论是结构还是工具都不兼容,所以不能直接拿当前系统的根文件系统顶上。论文实测对比了多个 0.11 根文件系统镜像,最终选定了一个 60M 的镜像,CHS 结构是 121 个柱面、16 个磁头、每道 63 扇区。

# 如果自己从头生成根文件系统镜像,几何参数必须与 bochs 配置严格一致 # 121 柱面 * 16 磁头 * 63 扇区 * 512 字节 = 62,447,616 字节,接近 60M dd if=/dev/zero of=hdc-0.11.img bs=512 count=$((121*16*63)) mkfs.minix -c hdc-0.11.img # 更省事且与论文一致的做法:用现成 0.11 镜像,losetup 挂载后检查命令 losetup /dev/loop0 hdc-0.11.img mount -t minix /dev/loop0 /mnt/root ls -l /mnt/root/bin /mnt/root/usr/bin # 确认 sh、ls、gcc 等是否可执行 umount /mnt/root losetup -d /dev/loop0

逻辑说明:dd 的 count 计算很关键,121×16×63=121968 个扇区,正好等于镜像文件总大小,bochs 才能按这个几何参数正确寻址。mkfs.minix 生成 Minix 文件系统,挂载后可以往里补充 /bin/sh、/bin/ls、/usr/bin/gcc 等命令。

参数说明:CHS 结构不是随便填的,它必须和 bochs 配置文件里的 cylinders、heads、spt 完全一致,否则内核读磁盘时计算出的扇区偏移就是错的,根文件系统自然挂不上。论文正文某处写的是 4 个磁头,但 bochs 配置脚本和最终运行结果用的是 16 磁头,我倾向认为那是排版笔误,实际以 121/16/63 为准。

5. 编译运行避坑:五个真实踩过的坑,现象、原因、解决一次讲清

老内核编译的坑从来不缺,下面这五条是我按这条链路走下来最典型的,按“现象 → 原因 → 解决”记录。遇到同类问题可以直接对号入座。

5.1 坑一:改完 Makefile 依然 command not found

现象:make 刚开始执行,第一行就报xxx: command not found,连编译都进不去。

原因:只改了根目录的 Makefile,子目录的 Makefile 里还写着 gas、gld、gar 这些旧工具名;或者当前 PATH 里找不到 as/ld,安装的 binutils 不在默认路径。

解决:先用find . -name Makefile -o -name makefile | xargs grep -n "gas\|gld\|gar"把所有旧名字位置揪出来,逐个改成 as/ld/ar;再which as ld确认工具路径存在。改完统一执行 make clean 再重编。

5.2 坑二:4 磁头与 16 磁头之争,根文件系统挂不上去

现象:内核启动到 init() 阶段,mount 根文件系统失败,屏幕停在打印版本信息之后,没有任何错误提示或者提示看不懂。

原因:根文件系统镜像的 CHS 几何参数和 bochs 配置不一致。论文正文某处写 4 磁头,但 bochs 配置脚本用的是 16 磁头,几何参数一旦错位,内核计算磁盘偏移就全偏了。

解决:统一以 bochs 配置里的 121 柱面、16 磁头、63 扇区为准;如果自己生成镜像,dd 的 count 严格用 121×16×63=121968。这属于典型的“看正文被带偏”的玄学问题,实际以运行脚本为唯一标准。

5.3 坑三:删内嵌汇编约束时把指令也删了

现象:编译报 invalid operand,或者编译过了但内核运行到某条指令直接死掉。

原因:内嵌汇编的冒号分三段,输出操作数、输入操作数、clobber 区。手删 clobber 的时候把上一段末尾的逗号或某个输入操作数一并删了,编译器给报错还好,最怕编译过但语义变了。

解决:改之前每个文件先复制一份留底;只删 clobber 区,也就是最后一段冒号后面的内容,再处理输出/输入操作数里显式的"cx","di","si"声明。每个文件改完单独gcc -c验证一次,能省掉后面整体联调的排查时间。

5.4 坑四:全局替换下划线,把字符串常量也伤了

现象:编译和链接都正常,但启动后 printf 输出的版本信息变成乱码,或者字符串缺字符。

原因:批量替换下划线时用了类似sed -i 's/_\([a-zA-Z]\)/\1/g'的全局规则,把字符串常量里的下划线也一并替换掉了。

解决:只对 .s 汇编文件做符号名替换;更好的做法是先 nm 看未解析符号,再精准改引用点,字符串常量手工恢复。汇编文件数量本来就少,逐个人工过一遍比全局替换更可靠。

5.5 坑五:Shell 不启动、没有报错,多半是动态链接系统调用没补全

现象:init() 打印完版本信息后,光标停住或者系统直接重启,Shell 提示符始终没出现。

原因:execve("/bin/sh") 返回 ENOSYS。Shell 二进制依赖的动态链接系统调用在内核里还是空的,查 sys_call_table 发现该位置的函数指针没有初始化。

解决:回到第 4.2 节的 diff 流程,把缺失的系统调用补齐,并在 sys.c 里补函数实现。没有 strace 可用时,我通常会在 execve 失败分支临时加一行 printk 打 errno,看到 ENOSYS 就基本能确认是系统调用表问题。

6. 复现与进阶:bochs 启动参数、gcc 编译 hello,以及验证内核改动的一次实验

6.1 bochs 配置与启动命令

论文里给出的 bochs 运行脚本是整套复现的最后一块拼图。配置如下:

# bochsrc:16M 内存,软盘引导,硬盘挂 0.11 根文件系统镜像 megs: 16 floppy a: 1_44 = "linux-fd.img", status=inserted ata0-master: type=disk, path="hdc-0.11.img", mode=flat, cylinders=121, heads=16, spt=63 boot: a

逻辑说明:megs 把虚拟机内存设为 16M,够 Linux 0.01 跑;软盘镜像 linux-fd.img 放的是编译好的内核镜像,boot: a 告诉 bochs 从 A 盘引导;硬盘镜像 hdc-0.11.img 是根文件系统,mode=flat 表示整块磁盘不分区,直接按 CHS 参数寻址。

参数说明:cylinders=121、heads=16、spt=63 三个参数必须与根文件系统镜像的实际几何结构一致,前面避坑章节已经强调过。启动命令用bochs -f bochsrc -q,-q 跳过交互式配置直接启动。

启动后逐个执行下列命令验证系统可用性:

命令预期结果
df列出当前挂载的文件系统设备信息
pwd输出当前工作目录
ls显示当前目录内容
rm hello删除当前目录下的 hello 文件
gcc hello.c -o hello编译链接 C 程序,生成可执行文件
./hello输出 Hello, world!

6.2 把构建过程固化成一个脚本

整套流程手动操作容易漏,我习惯把编译、写软盘镜像、启动 bochs 串成脚本:

#!/bin/bash # 重新编译内核,先 clean 再 make,避免旧产物干扰 make clean make # 把生成的内核镜像写入软盘镜像,conv=notrunc 防止文件被截断 dd if=Image of=linux-fd.img bs=512 count=2880 conv=notrunc # 自动启动 bochs bochs -f bochsrc -q

逻辑说明:make clean 是为了彻底清理旧目标文件,老内核的 Makefile 依赖关系不完整,增量编译经常带出来一堆诡异错误;dd 把编译产物 Image 写入软盘镜像;最后启动 bochs。

参数说明:count=2880 对 1.44M 软盘正好是 2880 个扇区;conv=notrunc 避免 dd 把镜像文件尾部截掉。

6.3 进阶:改一行内核代码,观察重启后的可见变化

验证这套链路最好用的方法,不是反复跑 hello,而是故意改一行内核代码看效果。比如在 init() 提示字符串里追加一个编译时间宏,重新执行构建脚本,重启后看版本提示是否变化;或者改 kernel/sched.c 里时间片长度的默认值,观察 Shell 响应快慢的变化。改动越“肉眼可见”,越能确认“源码改动 — 编译 — 运行”整条链路是通的,而不是拿了个现成镜像在自欺欺人。

从那以后,我每次做内核实验都强制走一遍“改一行 → 重编 → bochs 验证”的闭环,再小的改动也不跳过,因为老内核几乎没有错误提示可用,跳过一步就是把问题往后推。这份 PDF 的改造思路和参数表值得放在手边对照着查,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 13:30:18

VMware虚拟化面试实战指南:从原理到排错全解析

简介&#xff1a;围绕VMware虚拟化技术常见考点整理的面试题集&#xff0c;适合虚拟化运维工程师、VMware管理员以及备考VCP等认证的读者使用&#xff0c;可快速检验对vSphere核心概念的掌握程度。题目聚焦vSphere组件、虚拟机属性、vCenter高可用、冷迁移条件、模板与快照、分…

作者头像 李华
网站建设 2026/9/29 13:28:36

长期运行与灾难恢复:专业工作站版、企业版、LTSC、Servers 版怎么选?

上个月帮一个小团队做恢复演练&#xff0c;他们的核心文件服务器是一台装了专业工作站版的台式机&#xff0c;另外一台跑企业版做域控&#xff0c;还有一台老机器死撑着企业 LTSC 版当专用采集机。演练做到第三步就卡住了——三台机器的还原方式完全不同&#xff0c;一个靠系统…

作者头像 李华
网站建设 2026/9/29 13:27:48

昇腾 Benchmark 配 TaoToken:统一 Key 接入与 config.toml 骨架

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

作者头像 李华
网站建设 2026/9/29 13:27:23

YOLOv11羽毛球追踪实战:小目标检测与轨迹预测算法剖析

简介&#xff1a;这份PDF文档面向计算机视觉学习者、体育科技研究者与目标检测开发者&#xff0c;系统讲解如何用YOLOv11实现实时羽毛球追踪与运动轨迹预测。全文共39页&#xff0c;从YOLOv11网络结构、锚框机制与损失函数讲起&#xff0c;逐步展开实时追踪系统的架构设计&…

作者头像 李华
网站建设 2026/9/29 13:27:21

802.3-2022 标准解读:400G 链路排障与 FEC 配置实战

简介&#xff1a;802.3-2022以太网标准2022版&#xff0c;是IEEE于2022年5月批准、7月发布的以太网最新修订版&#xff0c;取代2018版&#xff0c;规范1Mb/s至400Gb/s局域网操作&#xff0c;涵盖CSMA/CD协议、MII接口、各类PHY及管理信息库&#xff0c;面向网络工程师、协议开发…

作者头像 李华
网站建设 2026/9/29 13:26:34

Transformer预测波束成形:车载ISAC毫米波通信实战指南

简介&#xff1a;这份资源面向具备机器学习与无线通信基础的研究人员和工程师&#xff0c;聚焦车载网络集成感知与通信&#xff08;ISAC&#xff09;场景下的预测波束成形难题。针对传统方案依赖路侧单元获取信道状态信息、信令开销大的痛点&#xff0c;资源围绕回波卷积Transf…

作者头像 李华