ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SerenityOS 移植 mednafen 实战:两个关键补丁背后的兼容性改造

SerenityOS 移植 mednafen 实战:两个关键补丁背后的兼容性改造 SerenityOS 移植 mednafen 实战两个关键补丁背后的兼容性改造【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity导读本文以 SerenityOS 仓库中 mednafen多机种模拟器移植包的补丁说明文档Ports/mednafen/patches/ReadMe.md为核心深入拆解移植过程中必须解决的两个底层兼容性问题SerenityOS 不支持 copy relocations复制重定位导致的 PIC/PIE 编译调整以及缺少PTHREAD_MUTEX_ERRORCHECK互斥锁类型时的 POSIX 线程接口替换。读完本文你将理解 SerenityOS 移植第三方软件时的典型思路掌握补丁的组织方式、具体改动内容及其背后的内核/运行库依据并能在自己移植软件时复用这套发现差异 → 最小化补丁 → 记录原因的流程。一、mednafen 移植包概览mednafen 是一个多平台游戏机模拟器在 SerenityOS 的移植体系中归属于Ports/目录。整个移植包的构成非常简单Ports/mednafen/package.sh移植构建脚本Ports/mednafen/patches/0001-Make-mednafen-compile-with-PIC-PIE.patch补丁一恢复 PIC/PIE 编译Ports/mednafen/patches/0002-Replace-PTHREAD_MUTEX_ERRORCHECK-with-PTHREAD_MUTEX_.patch补丁二替换互斥锁类型Ports/mednafen/patches/ReadMe.md两份补丁的配套说明文档从 package.sh 可以看到移植的版本与依赖关系#!/usr/bin/env -S bash ../.port_include.sh portmednafen version1.31.0-UNSTABLE files( https://mednafen.github.io/releases/files/mednafen-${version}.tar.xz#bfcff72e370e09e12ba3791600782187fbf5e2cc9d6b5fe4f9f3471642046367 ) workdirmednafen useconfiguretrue use_fresh_config_subtrue use_fresh_config_guesstrue depends(SDL2 zlib flac)几个关键字段的含义port与version声明移植的软件名与版本本例为 mednafen 1.31.0-UNSTABLE。files上游源码压缩包的下载地址及其 SHA-1 校验和。#后为校验值构建系统会校验下载文件的完整性。workdir解压后的源码目录名mednafen。useconfiguretrue启用经典的./configure make make install构建流程。use_fresh_config_sub/use_fresh_config_guess使用 SerenityOS 提供的较新版本的config.sub/config.guess脚本以正确识别*-pc-serenity目标三元组避免 configure 阶段因无法识别主机架构而失败。depends编译运行所依赖的已移植软件这里是 SDL2、zlib 与 flac音频解码依赖。../.port_include.shPorts/.port_include.sh是整个移植体系的公共框架它负责设置交叉编译工具链环境${SERENITY_ARCH}-pc-serenity-*前缀、按MAKEJOBS并行度构建、支持 ccache 加速、在出错时以彩色日志标记失败步骤等。mednafen 的构建流程正是在这套框架下执行的。二、补丁一恢复 PIC/PIE绕开 copy relocations2.1 问题背景补丁一的说明原文如下Make mednafen compile with PIC/PIEWe currently dont support copy relocations and mednafen compiles with PIC/PIE disabled for performance reasons. This re-enables it and disables the compiler warning it emits for having it enabled.翻译过来就是SerenityOS 当前不支持 copy relocations而 mednafen 出于性能考虑默认关闭了 PIC/PIE位置无关代码/可执行文件。这个补丁重新开启 PIC/PIE同时屏蔽编译器因此产生的警告。这里的因果关系值得展开mednafen 关闭 PIC/PIE 后其可执行文件在链接时可能产生针对全局变量的copy relocation复制重定位。在 ELF 的 x86_64 ABI 中这是R_X86_64_COPY类型的重定位当共享库导出的全局数据符号被可执行文件引用时链接器会在可执行文件的.bss中复制一份数据并把所有引用指向这份副本。而 SerenityOS 的 ELF 加载器Userland/Libraries/LibELF并不支持处理这类重定位因此带有 copy relocation 的程序将无法在 SerenityOS 上正确加载或运行。在 x86_64 的动态重定位类型定义 中可以看到SerenityOS 的 LibELF 虽然枚举了R_X86_64_COPY但整套重定位支持以ABSOLUTE、GLOB_DAT、JUMP_SLOT、RELATIVE、IRELATIVE等为主copy relocation 并不在加载器实际处理的路径中——这正是移植说明里我们目前不支持 copy relocations的源码级印证。2.2 补丁的具体改动补丁一修改了两个文件共 4 行新增改动 1configure脚本中清空 no-PIC/PIE 标志 -19954,6 19954,8 cat confdefs.h _ACEOF #define MEDNAFEN_VERSION_NUMERIC $MEDNAFEN_VERSION_NUMERIC _ACEOF NOPICPIE_FLAGS NOPICPIE_LDFLAGS AM_CFLAGS$ALTIVEC_FLAGS $OPTIMIZER_FLAGS $WARNING_FLAGS $CODEGEN_FLAGS $CODEGEN_CFLAGS $NOPICPIE_FLAGSmednafen 的 configure 会生成NOPICPIE_FLAGS与NOPICPIE_LDFLAGS通常形如-fno-pic -fno-pie/-no-pie。补丁把它们显式置为空字符串使后续的AM_CFLAGS不再携带关闭 PIC/PIE 的编译选项从而让整个工程以默认的 PIC/PIE 方式编译。改动 2src/types.h中屏蔽编译警告 -14,6 14,8 #include config.h #endif #define MDFN_DISABLE_PICPIE_ERRWARN 1 mednafen 源码会检查是否以 PIC/PIE 方式编译若检测到开启则会发出-Werror级别的警告因为上游默认期望非 PIC/PIE 以获得性能。通过定义MDFN_DISABLE_PICPIE_ERRWARN可以关闭该警告避免编译因警告被当作错误而失败。补丁头部还保留了作者信息From: Luke Wilde lukewserenityos.org与时间戳符合 git format-patch 的标准格式便于溯源与后续更新。2.3 为什么选择开启 PIC/PIE而非支持 copy relocation从移植策略看SerenityOS 团队选择了成本更低、风险更小的方案与其在系统加载器LibELF中实现 copy relocations 的支持不如通过补丁让 mednafen 采用标准的 PIC/PIE 构建方式从而从根源上避免产生R_X86_64_COPY重定位。代价是 mednafen 会失去一部分关闭 PIC/PIE 带来的性能收益但换来了在 SerenityOS 上能够正常链接和加载。这也是 SerenityOS 移植第三方软件时的一贯取舍优先适配现有系统能力把对系统的改动留给真正需要的地方。三、补丁二用 PTHREAD_MUTEX_NORMAL 替换 PTHREAD_MUTEX_ERRORCHECK3.1 问题背景补丁二的说明原文Replace PTHREAD_MUTEX_ERRORCHECK with PTHREAD_MUTEX_NORMALWe currently dont support the PTHREAD_MUTEX_ERRORCHECK mutex type.mednafen 的多线程封装src/mthreading/MThreading_POSIX.cpp在创建互斥锁时原本使用pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ERRORCHECK)。而 SerenityOS 的 LibC 目前只支持PTHREAD_MUTEX_NORMAL与PTHREAD_MUTEX_RECURSIVE两种互斥锁类型。这在源码中有直接证据pthread_mutexattr_settype的实现Userland/Libraries/LibC/pthread.cpp#L261-L269只接受两种取值int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type) { if (!attr) return EINVAL; if (type ! PTHREAD_MUTEX_NORMAL type ! PTHREAD_MUTEX_RECURSIVE) return EINVAL; attr-type type; return 0; }也就是说如果 mednafen 继续传入PTHREAD_MUTEX_ERRORCHECK该调用会直接返回EINVAL随后 mednafen 的CreateMutex会把它当作错误抛出异常对应代码中的throw MDFN_Error(...)分支导致模拟器启动失败。补丁二正是为消除这个运行期错误而存在。3.2 补丁的具体改动补丁二只修改了一个文件、一行代码--- a/src/mthreading/MThreading_POSIX.cpp b/src/mthreading/MThreading_POSIX.cpp -295,7 295,7 static void CreateMutex(Mutex* ret) throw MDFN_Error(ene.Errno(), _(%s failed: %s), pthread_mutexattr_init(), ene.StrError()); } - if((ptec pthread_mutexattr_settype(attr, PTHREAD_MUTEX_ERRORCHECK/*PTHREAD_MUTEX_NORMAL*/))) if((ptec pthread_mutexattr_settype(attr, PTHREAD_MUTEX_NORMAL))) { ErrnoHolder ene(ptec);注意被替换行的注释/*PTHREAD_MUTEX_NORMAL*/这说明 mednafen 上游其实已经预见到在某些平台上ERRORCHECK类型可能不可用并预留了NORMAL作为备选。SerenityOS 的补丁正是激活了这个备选分支。从功能上看PTHREAD_MUTEX_ERRORCHECK会检测死锁、重复加锁等错误用法并在检测到时返回错误码牺牲性能换取诊断能力。PTHREAD_MUTEX_NORMAL不进行错误检查行为最简单、开销最小也是 SerenityOS LibC 中pthread_mutexattr_init的默认类型pthread.cpp#L249-L253。用NORMAL替换ERRORCHECK后mednafen 的互斥锁功能完全不受影响其代码本身并不依赖 ERRORCHECK 的错误检测语义只是少了一层额外的死锁自检。在 SerenityOS 的 pthread 头文件Userland/Libraries/LibC/pthread.h#L70-L72中还可以看到PTHREAD_MUTEX_DEFAULT同样被定义为PTHREAD_MUTEX_NORMAL也就是说在 SerenityOS 上默认互斥锁即 NORMAL 类型这与补丁二的替换方向完全一致。四、从两份补丁看 SerenityOS 的移植方法论把两份补丁放在一起可以提炼出 SerenityOS 移植第三方软件时的通用模式4.1 补丁即文档ReadMe.md 的角色Ports/mednafen/patches/ReadMe.md 虽然只有短短数行却承担了重要的决策记录职能每份补丁都以代码块标题形式列出补丁文件名紧跟一句主题摘要再附一段为什么的说明。例如补丁一的说明明确写出我们目前不支持 copy relocations补丁二则写明我们目前不支持 PTHREAD_MUTEX_ERRORCHECK 互斥锁类型。这种改了什么 为什么改的双层记录让后来者或 CI 维护者无需阅读完整 diff 就能理解每份补丁存在的必要性也方便在上游更新版本时逐一评估补丁是否还需要保留。4.2 最小化补丁原则两份补丁的改动量都非常克制一个 4 行、一个 1 行。它们没有重写 mednafen 的任何功能逻辑而是精准地绕开与 SerenityOS 运行库/加载器不兼容的少数 API 用法。这种最小差异策略带来的好处是与上游同步升级时冲突少、易解决行为改动面小便于定位问题补丁语义清晰每一份都能对应到明确的系统能力差异。4.3 差异源于系统设计取舍两处差异的本质都是 SerenityOS 尚未实现 POSIX/Linux 生态中的某些细节copy relocations 不支持属于 ELF 动态链接层面的能力缺口由 Userland/Libraries/LibELF 的加载器能力边界决定PTHREAD_MUTEX_ERRORCHECK 不支持属于 LibC pthread 实现的能力边界从 pthread.cpp 的EINVAL校验可见一斑。移植补丁的存在正是为了让第三方软件在 SerenityOS 当前的能力范围内以最小的适配成本运行起来。五、如何验证与复现如果你希望在本地环境中验证这套移植配置可参考以下路径SerenityOS 的移植构建需要先完成工具链与构建目录的配置具体步骤见 BuildInstructions.md检查补丁内容直接阅读两份补丁文件即可核对与本文描述一致Ports/mednafen/patches/0001-Make-mednafen-compile-with-PIC-PIE.patchPorts/mednafen/patches/0002-Replace-PTHREAD_MUTEX_ERRORCHECK-with-PTHREAD_MUTEX_.patch执行移植构建在已配置的 SerenityOS 构建环境中运行 mednafen 的构建脚本Ports/mednafen/package.sh构建系统会自动下载 1.31.0-UNSTABLE 源码包、校验哈希、依次应用两份补丁然后进入 configure/make/install 流程。验证互斥锁行为若临时移除补丁二pthread_mutexattr_settype会因收到PTHREAD_MUTEX_ERRORCHECK而返回EINVALmednafen 的CreateMutex随即抛出MDFN_Error——这与 pthread.cpp 中的校验逻辑完全对应。结语mednafen 的两份移植补丁表面上是两处不起眼的代码改动背后却分别对应着 SerenityOS 在 ELF 动态链接不支持 copy relocations与 POSIX 线程不支持 ERRORCHECK 互斥锁类型两个层面的系统实现边界。通过 ReadMe.md 的说明文档我们可以快速理解每次适配的动机而结合 LibELF 与 LibC/pthread.cpp 的源码又能把为什么需要这些补丁落实到具体实现细节上。这种补丁说明 系统源码互证的研究方式同样适用于阅读 SerenityOS Ports 目录下的其他数百个移植包。【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表