mbedtls嵌入式ARM移植实战:从源码到QEMU验证的全流程记录
简介面向ARM嵌入式开发与芯片验证人群的mbedtls移植实操记录完整演示了从源码仓库获取、工程模板创建到库目录拷贝、Makefile编译选项修改及自测函数调用的全流程。文档以PDF文件呈现包内仅1个文件压缩后约199KB轻量易用适合快速查阅。目前已累计有330人学习浏览。内容重点覆盖mbedtls在armv9架构下的典型移植步骤包括将library、include目录接入自定义工程开启MBEDTLS_SELF_TEST等编译宏以及通过添加mbedtls_sha256_self_test()调用完成自测。文档还结合qemu模拟环境演示了如何将这些程序打包进buildroot并运行验证便于读者在无真实硬件条件下完成功能检查。对想了解嵌入式安全库基础移植流程、希望在真实项目中进行安全组件集成的开发者这是一份简洁但步骤清晰的参考笔记。1. mbedtls 还停留在“看看源码”嵌入式 ARM 芯片上把它跑起来才算移植入门做嵌入式 ARM 开发的人大概都遇到过这种场景新拿到的 SOC 板卡工具链刚从供应商那边拷过来还没想好先跑什么程序验证一下环境。很多人的第一反应是点个 LED但点灯只能证明 GPIO 通了证明不了 CPU、中断、内存和工具链都正常。我现在的习惯是直接跑一遍 mbedtls 的自测程序——AES 和 SHA-256 这类算法对指令周期和内存布局非常敏感能一路跑通说明芯片、交叉编译环境和运行链路基本是通的。mbedtls 移植不是新鲜事但真正把它从源码拉下来、编进自己的工程模板、再放到 QEMU 里跑起来中间有一堆细节值得记一笔。这篇笔记就是我从零走通整个流程的记录包含完整的操作步骤、Makefile 修改方法和几个栽过跟头的地方适合所有拿到新 ARM 板卡想快速验证软件栈的嵌入式工程师。2. 移植前先别急着敲 make模板、源码和目录结构一次理清2.1 先分清“库移植”和“应用集成”很多第一次做 mbedtls 移植的人会卡在一个概念上到底是要把 mbedtls 编成一个独立的 .so 或 .a 库还是直接把源码编进自己的固件里这两条路差异很大。如果你是做嵌入式 Linux 用户态程序比如在 ARMv8 或者 armv9 的平台上跑安全启动相关工具常见做法是编译链接成动态库上层应用通过头文件调用但如果你是在裸机环境或者 RTOS 上做那源码级嵌入几乎是唯一选择。这份移植笔记走的是第二条路线把 mbedtls 的 library 和 include 目录直接拷贝到应用工程里随主程序一起编。好处是没有额外的库依赖烧进板子也好排查坏处是编译时间会长一点而且 Makefile 必须把参与编译的源文件列清楚。我建议刚开始做移植时也选这种方式因为你能直接看到每个模块的编译过程出错了可以精准定位到是哪个 .c 文件的问题而不是在黑匣子一样的静态库里猜。2.2 拉源码和模板工程版本别选错第一步是下载 mbedtls 源码。直接到代码托管平台把官方仓库 clone 下来这一步没什么好说的。但有两点需要提醒第一clone 完之后别着急用最新代码除非你想替社区做测试。我一般会先看一遍 release 分支或维护中的稳定分支至少保证你踩到的坑是别人踩过的而不是某个新提交刚引入的。第二源码目录里有大量测试代码和文档移植时用不到别一股脑往工程里搬。第二步是准备一个空的 C 语言工程模板。模板的作用是省掉你从头写 Makefile、启动文件和目录结构的时间。我自己维护了一个非常朴素的 native_c_template 模板里面就是一个可执行的 C 工程骨架src 目录下放主程序顶层放 Makefile编译产物输出到 out 目录。这份移植笔记里用的就是这种通用模板你完全可以用自己现有的工程替代关键是目录职责要清楚后面拷贝 mbedtls 时才不会乱。模板拿到手之后执行拷贝命令生成一个独立的移植工程比如叫 mbedtls_testcp native_c_template mbedtls_test -r cd mbedtls_test这一步看似简单但-r参数偶尔会被忽略尤其是在你习惯用cp native_c_template mbedtls_test不加参数的情况下。如果没加-r目录内容根本拷不过去后续所有操作都会扑空。拷完之后建议先看一眼目录结构确认模板内容完整再进入下一步。2.3 目录拷贝拷完先做一次结构体检接下来把 mbedtls 里的 include 和 library 两个目录拷到工程里。这一步的命令同样很简单# 假设你 clone 的 mbedtls 在 mbedtls_src 目录下 cp -r mbedtls_src/include mbedtls_test/ cp -r mbedtls_src/library mbedtls_test/ cd mbedtls_test拷贝完成后我强烈建议先跑一下tree或者find确认目录结构长什么样tree -L 2正常情况你应该看到 include/mbedtls 下有一大堆头文件library 下有 aes.c、sha256.c、sha512.c 等几十个源文件。这里有一个非常隐蔽的问题mbedtls 的配置头也在 include 目录里不同版本的配置头文件名不一样。早期版本叫 config.h后来的版本改成了 mbedtls_config.h。如果你拷贝的版本和你参考的文档对不上编译时第一个报错就是找不到头文件。我那次就因为这个浪费了半天时间后来养成了先看目录再动手的习惯。另外library 里有些文件依赖特定的平台宏才能编译比如和时间、文件系统相关的模块。这些对于裸机或最小化移植来说可能用不上你可以先不管等编译报错时再回头检查配置。真正需要做的是把 include 路径加入 Makefile 的搜索路径以及决定把哪几个源文件加进编译列表。这两个问题下一章具体讲。3. 让 Makefile 替你干活工具链、源文件与宏开关的配合3.1 指定交叉编译工具链先解决“用哪个编译器”模板工程默认用的可能是本机 gcc如果直接在 ARM 目标平台上运行那没问题但绝大多数情况是我们用 x86 的电脑交叉编译出 ARM 架构的程序再拷到板子或者 QEMU 镜像里执行。所以 Makefile 第一件事就是修改编译工具链前缀。打开模板工程的 Makefile一般会有类似这样的定义# 交叉编译工具链前缀根据你的 SOC 供应商提供的工具链修改 CROSS_COMPILE aarch64-none-linux-gnu- CC $(CROSS_COMPILE)gcc LD $(CROSS_COMPILE)gcc AR $(CROSS_COMPILE)ar把CROSS_COMPILE改成你实际使用的工具链前缀即可。比如有些 SOC 厂商给的是arm-none-eabi-裸机有些给的是aarch64-linux-gnu-Linux 用户态这决定了你编译出来的程序是跑在 Linux 系统上还是直接跑在硬件上。如果你不确定先用$(CROSS_COMPILE)gcc -v验证一下工具链能否正常运行。这一步出错的现象通常是command not found原因多半是前缀写错或者工具链没加入 PATH。3.2 SRCS 别漏文件SHA-256 自测缺了它就报链接错工具链配好后最关键的改动是 Makefile 里的 SRCS 变量。模板工程默认只有 main.c我们要把 mbedtls 需要用到的源文件加进去。以跑 SHA-256 和 AES 自测为例至少要包含SRCS src/main.c \ library/aes.c \ library/sha256.c这里有个坑要提前说aes.c 本身会依赖一些公共模块比如platform.c或者memory_buffer_alloc.c具体依赖哪些要看你的配置宏。如果你只加了源文件但不加依赖编译能过链接时会报undefined reference to ...那一串错误跟天书一样特别打击信心。我的建议是第一次跑最小化自测时直接在 library 目录下用通配符把常用的算法源文件全部加进来SRCS src/main.c \ $(wildcard library/*.c)这个写法的好处是省事缺点是些用不到的模块也编进去了。但既然是移植验证先把体积和编译时间放一边全量编译能最快排除源文件缺失导致的问题。等自测跑通了再按照你的实际需求裁剪逐个去掉不需要的文件。对应的 include 路径也要加进 MakefileCFLAGS -Iinclude3.3 打开 SELF_TEST 宏主函数里一个调用跑通全流程mbedtls 的设计很有意思默认情况下自测代码是被编译进库里的但要不要执行取决于主函数里是否调用xxx_self_test函数。这个函数不是平台相关的不会因为你换了芯片就去掉。不过它受一个宏控制如果编译时没开启MBEDTLS_SELF_TEST相关函数的实现会被预编译指令排除掉你调用了也只能得到一个undefined reference错误。在 Makefile 里加宏CFLAGS -DMBEDTLS_SELF_TEST然后在 main.c 里添加调用。以 SHA-256 为例#include stdio.h #include mbedtls/sha256.h int main(void) { int ret mbedtls_sha256_self_test(1); if (ret ! 0) { printf(SHA-256 self test failed: %d\n, ret); return 1; } printf(SHA-256 self test passed.\n); mbedtls_aes_self_test(1); // 如果你也把 aes.c 编进来了 return 0; }注意mbedtls_sha256_self_test的入参是一个整型传 1 表示打印详细的运行信息传 0 则只返回结果。第一次跑建议传 1能看到每一步的输入、输出和期望值排查起来直观很多。如果你用的是较新的版本函数名前缀可能会有细微差异比如mbedtls_sha256_self_test在多数版本下是一致的但建议打开头文件确认一下避免复制代码后编译报错。编译命令就是传统三板斧make clean make编译成功后out 目录下会生成可执行文件。第一次跑通时那种“多个 .c 文件真的编进去了”的感觉还是很踏实的。但编译通过只是第一步真正的麻烦往往在后面。4. 移植避坑自测通过不代表万事大吉4.1 现象头文件找不到报fatal error: mbedtls/config.h: No such file or directory原因是多方面的最常见的是 include 目录没拷全或者 Makefile 里的-Iinclude路径没加对还有一种情况是版本差异新版的配置头叫mbedtls_config.h源码里#include mbedtls/config.h在预处理时会被替换如果目录里只有新文件就找不到了。解决路径分两步。第一在工程根目录执行find include -name *.h | head确认所有头文件都到位第二在 Makefile 里把 CFLAGS 的-I路径写成绝对路径防止因为 make 的工作目录不同导致搜索路径失效。如果问题还在用gcc -E -Iinclude src/main.c -v手动展开预处理看看到底卡在哪个 include 路径上。这一步能看到完整的头文件搜索顺序比瞎改 Makefile 高效得多。4.2 现象函数能编译通过但自测程序没有任何输出这个坑更隐蔽。编译和链接都成功说明源文件都编进去了但运行起来屏幕上一行字都没有。第一次遇到时我还以为是 printf 的问题查了半天发现是优化等级惹的祸。当-O2或更高的优化等级被打开时编译器可能把没有副作用的自测调用给优化掉了因为self_test(1)的返回值没有被使用编译器觉得这段代码可以“不执行”。解决方法是显式使用返回值并且在编译时降低优化等级。比如把主函数写成int ret mbedtls_sha256_self_test(1); if (ret ! 0) { return 1; }同时在 Makefile 里加CFLAGS -O0对于移植验证阶段-O0是最保险的既不会被优化掉也方便调试。等稳定性验证完了再开优化避免优化带来的时序差异干扰你的判断。4.3 现象移植到 ARM 平台后自测输出一堆错误但同源码在 PC 上正常这是最让人崩溃的问题以为移植环境的差异导致了算法错误但实际上大概率跟字节序有关。mbedtls 默认支持大小端但部分平台或者配置宏组合不对时内部字节序处理会出问题。尤其当你跑在 SOC 模拟器或者某些自定义平台上架构指令集和字节序组合可能跟你预想的不一样。排查顺序很关键先看自测输出有没有算出一个“可能”的值再确认平台架构。通常在 Makefile 里加上-DMBEDTLS_PLATFORM_C会解决一部分平台相关的初始化问题同时检查配置头里有没有误开了MBEDTLS_NO_DEFAULT_ENTROPY之类的硬开关。还有一个快速验证方法是只跑 SHA-256因为哈希算法对字节序的处理相对简单如果连 SHA-256 都错基本可以确定是配置宏问题而不是算法实现问题。4.4 现象在 QEMU 环境运行起来就崩溃段错误或者直接无响应编译链接都正常拷进 QEMU 镜像后一运行就崩这是新手最容易误判为“代码写错”的情况。实际上大多数原因是运行环境的栈空间太小。mbedtls 的自测程序会分配较大的临时缓冲区如果你的链接脚本或者启动参数把栈设为 4KB、8KB跑 AES 轮函数时可能直接越界。解决思路是在链接脚本中把栈空间调到至少 256KB或者如果是用户态程序在启动脚本用ulimit -s看一下栈限制。另一个常见做法是调用mbedtls_platform_set_printf这类平台函数把输出重定向到调试串口否则 printf 可能因为缓冲机制卡死。这一步容易被忽略但它就是 QEMU 上“运行正常但控制台没输出”的直接原因。4.5 现象链接时出现一堆重复符号或者行为诡异当你把 library 整个目录的通配符加进 SRCS 之后重复定义的概率大幅上升。比如某些平台版本的 library 里同时存在platform.c和platform_util.c它们的函数会有重叠。再说一个容易混淆的场景你的系统库或者第三方库可能早就提供过 SHA-256 的同名函数或者你之前编过的某个静态库里也有 mbedtls 的符号导致链接器不知道该用哪个实现。处理方案是编译后用 nm 检查生成的符号来源nm out/mbedtls_test | grep mbedtls_sha256看符号是 T 类型位于代码段还是 U 类型未解析如果是 U说明你的程序链接的是外部的实现不是 mbedtls 自带的。这时候要么给 mbedtls 的实现统一加前缀要么确认链接顺序把自己的 library 目录放在系统库之前。这个技巧在嵌入式环境里尤其管用能省掉很多肉眼找半天也发现不了的“同名污染”。5. 上 QEMU 验证把自测程序装进镜像串口里看输出5.1 打包进 rootfs重新生成镜像编译产物在 out 目录下按这份笔记的操作可执行文件名会是 mbedtls_test或者你自己起的名字。我们要把它放进 QEMU 启动的镜像里才能拿到目标环境里运行。我的常见做法是先把可执行文件拷到 buildroot 的 out 目录然后再走一遍 buildroot 的打包流程生成最终的启动镜像cp out/mbedtls_test /path/to/buildroot/output/target/root/ make -C /path/to/buildroot注意拷贝的目标路径不要放在系统目录比如/usr/bin之类那可能被后续的清理规则覆盖。放到/root或者/home下更安全。打包完成后启动 QEMU进入 shell 后直接执行./mbedtls_test如果自测输出正常打印出 SHA-256/AES 的测试结果说明整个工具链、运行时和镜像打包流程全部打通了。这个信号比点灯强得多。5.2 进阶技巧用返回码做批量回归我后来在验证不同 SOC 软件栈时会顺手把自测程序包装成一个简单的回归脚本效果不错。修改 main.c 让返回值直接对应测试结果然后在 QEMU 里用一个脚本连续运行多组测试./mbedtls_test -sha256 ./mbedtls_test -aes echo $?把$?的判断加进脚本就能在环境搭建时快速筛出问题。这个技巧看起来简单但真的能帮你省掉很多“手动看屏幕输出”的低效时间。尤其是 ARMv8/armv9 这种多核平台每个核的内存命名空间和启动方式不同用脚本批量跑远比肉眼靠谱。这套流程走完之后我发现移植 mbedtls 不再是心里发怵的事。从那以后我每次拿到新的 ARM 板卡或者切换到 armv9 安全相关项目时都会强制走一遍“拉源码、拷目录、改 Makefile、跑自测、装 QEMU 验证”这个流程。它像一块试金石能把环境问题、工具链问题、运行问题一次性暴露出来。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

闪学it-领跑-AI变现实战课:自媒体+AI漫剧+短视频+智能体全流程创作(国学养生/电商带货/口播/数字人)

闪学it-领跑-AI变现实战课:自媒体+AI漫剧+短视频+智能体全流程创作(国学养生/电商带货/口播/数字人)

告别低效剪辑:AI批量产出国学养生与电商带货短视频的生产体系搭建在国学养生垂类的短视频赛道,很多中小创作者长期卡在产能瓶颈里:一条30秒的口播短视频,从选题、写脚本、拍素材到后期剪辑加字幕,至少要花两三个小时&a…

2026/10/15 5:30:21 阅读更多 →
深度学习文本分类:从BiLSTM+Attention到预训练模型微调

深度学习文本分类:从BiLSTM+Attention到预训练模型微调

这个任务前前后后写了五篇,Task5算是把文本分类系列往深水区推了一步。如果你是从Task1一路跟过来的,应该已经熟悉了数据清洗、特征工程、传统机器学习模型和简单神经网络这些环节。如果只是单独拿到这个任务,也没关系,这篇会从“…

2026/10/15 5:30:21 阅读更多 →
HALCON 22.05升级迁移与性能优化实战:算子、深度学习与排障笔记

HALCON 22.05升级迁移与性能优化实战:算子、深度学习与排障笔记

很多做机器视觉的朋友私信问我,手里的项目到底要不要从 20.11 升到 HALCON 22.05 Progress,升完之后以前写的算子脚本能不能直接用,深度学习那套流程是不是真的像宣传说的那样顺手。我把这段时间在 22.05 上做迁移、写新功能、调性能、上产线…

2026/10/15 5:30:21 阅读更多 →

最新新闻

GC2145 datasheet实战:从寄存器手册到图像链路调试

GC2145 datasheet实战:从寄存器手册到图像链路调试

简介:GC2145数据手册面向嵌入式视觉、摄像头模组与图像采集方向的硬件工程师及驱动开发者,用于快速掌握这款1/5英寸UXGA CMOS图像传感器的规格与设计要点。资源包共1个PDF文件,约814KB,即Galaxy Core发布的GC2145 CSP Datasheet V…

2026/10/15 10:59:04 阅读更多 →
从宇树招股书读懂具身智能:先本体再模型、先运动再干活

从宇树招股书读懂具身智能:先本体再模型、先运动再干活

长跑具身智能这条赛道的人,应该都记得2025年底那则消息:宇树科技的科创板招股书正式获受理。我第一时间把招股书翻了一遍,最触动我的反而不是营收和利润数字,而是藏在发展脉络里的十二个字——先本体、再模型;先运动、…

2026/10/15 10:59:04 阅读更多 →
ePub排版避坑指南:从标签属性到CSS类选择器实战

ePub排版避坑指南:从标签属性到CSS类选择器实战

简介:这份文档面向电子书制作初学者与希望提升排版水平的爱好者,系统讲解ePub格式电子书的排版与样式知识,帮助解决标签使用不规范、样式设置混乱等常见问题。资源包内含1个doc文件,大小约869KB,以图文教程形式呈现&am…

2026/10/15 10:59:04 阅读更多 →
MIMO检测算法在瑞利衰落信道下的Matlab仿真与性能对比

MIMO检测算法在瑞利衰落信道下的Matlab仿真与性能对比

1. 项目背景与核心价值多输入多输出(MIMO)技术作为现代无线通信系统的核心技术之一,通过利用空间维度显著提升了信道容量和传输可靠性。在实际系统中,接收端需要准确分离同时到达的多路信号,这就涉及到MIMO检测算法的选…

2026/10/15 10:59:04 阅读更多 →
Uila全栈性能监控实战:从数据采集到根因定位的完整解析

Uila全栈性能监控实战:从数据采集到根因定位的完整解析

1. 从"黑盒"到"透视":数据中心性能监控到底在解决什么问题数据中心运维这行干久了,最怕的不是服务器宕机,而是"慢"。宕机至少还有个明确的告警,重启或者切流量就能恢复;但"慢"…

2026/10/15 10:59:04 阅读更多 →
基于Python的茶叶商城交易平台设计与实现

基于Python的茶叶商城交易平台设计与实现

选题背景与意义 随着互联网技术的迅猛发展和电子商务模式的不断成熟,传统零售行业正经历着深刻的数字化转型。在这一背景下,农产品电商化成为推动乡村振兴与农业现代化的重要路径之一。茶叶作为中国最具代表性的传统农产品之一,不仅具有深厚的…

2026/10/15 10:58:03 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/15 9:49:14 阅读更多 →