PS2游戏二进制重编译:从MIPS到x86-64的逆向工程实战

news2026/5/14 19:01:14
1. 项目概述与核心价值最近在折腾PS2游戏《Agent SKILL》的逆向工程与重编译项目这个由hkmodd大佬在GitHub上开源的“ps2-recomp-Agent-SKILL”项目可以说是我近期见过最硬核、也最有启发性的游戏技术实践之一。简单来说它不是一个简单的模拟器或者修改器而是一个针对特定PS2游戏Agent SKILL的二进制代码重编译器。它的目标是将原本只能在PS2的MIPS架构CPU上运行的机器码通过静态分析和动态翻译技术转换成能在现代x86-64架构PC上原生运行的高效代码。这听起来是不是有点像高级版的模拟器但它的思路完全不同。传统模拟器如PCSX2是在软件层面虚拟出一个完整的PS2硬件环境CPU、GPU、内存总线等游戏代码依然以原始的MIPS指令形式存在由模拟器的“解释器”或“动态编译器JIT”一条条翻译执行开销巨大。而这个重编译项目则是一次性、离线地将整个游戏的代码块分析透彻直接生成一份等价的、优化过的x86-64程序。最终产物是一个可以独立运行的.exe或.elf文件其运行效率理论上可以无限接近原生PC游戏因为它彻底摆脱了模拟器框架的束缚。对于开发者、逆向工程爱好者和怀旧游戏技术研究者来说这个项目的价值是多维度的。首先它提供了一个极其珍贵的逆向工程与二进制翻译的实战案例涉及反汇编、控制流分析、寄存器分配、系统调用Hooking等底层知识。其次它探索了游戏代码“现代化”的一种可能路径为那些源代码丢失、但二进制文件尚存的经典游戏提供了“重生”的机会。最后对于玩家而言虽然目前仅支持单一游戏但它展示了未来以更高性能、更佳兼容性体验经典主机的潜力。接下来我将深入拆解这个项目的技术脉络、实操要点以及我踩过的那些坑。2. 核心原理静态重编译与动态翻译的融合要理解这个项目必须搞清楚“重编译”Recompilation和“动态翻译”Dynamic Translation常指JIT的区别与联系。这是整个项目的基石。2.1 静态重编译的核心思想静态重编译顾名思义是在程序运行之前对整个二进制文件进行一次性的分析、翻译和代码生成。它的工作流程可以概括为以下几个阶段加载与反汇编将PS2游戏的ELF可执行文件加载到分析工具中按照MIPS-III指令集规范将机器码反汇编成人类可读的汇编指令。这一步的关键在于正确区分代码Code和数据Data因为二进制文件中两者是混合存放的。项目通常会利用ELF文件头中的段Section信息并结合启发式分析如寻找函数入口点、跳转目标来尽可能准确地划分。控制流图CFG构建分析反汇编出的指令识别出所有的分支、跳转和调用指令从而构建出函数的控制流图。这个图揭示了代码的执行路径是理解程序逻辑和进行优化分析的基础。例如识别出循环结构、条件判断块等。中间表示IR生成与优化将MIPS汇编指令转换为一种与具体硬件架构无关的中间表示。这是一种高级的、更易于分析和优化的代码形式。在这一层可以进行许多重要的优化比如常量传播发现并替换掉那些值在编译期就能确定的变量。死代码消除移除永远不会被执行到的代码。循环优化对循环结构进行展开或强度削弱等优化。寄存器分配映射将MIPS的32个通用寄存器$0-$31和特殊寄存器映射到x86-64的有限寄存器集RAX, RBX, RCX, RDX, RSI, RDI, R8-R15等或栈内存位置。这是最复杂的一环因为两种架构的寄存器用途、调用约定Calling Convention完全不同。目标代码生成与链接将优化后的中间表示IR代码根据x86-64指令集规范生成最终的机器码。同时需要处理那些无法直接翻译的部分比如对PS2特有硬件如图形合成器GS、向量处理器VU的调用。这部分通常通过“运行时库”或“HLE高层模拟”来实现。最后将生成的所有代码块、数据以及运行时库链接成一个完整的、可执行的PEWindows或ELFLinux文件。静态重编译的优势在于它可以进行全局的、激进的分析和优化生成代码的质量可以非常高。但它的挑战也巨大间接跳转通过寄存器指定目标地址和自修改代码程序运行时修改自身的指令是静态分析的噩梦因为无法在运行前确定所有可能的执行路径。2.2 动态翻译JIT作为必要补充这正是“ps2-recomp-Agent-SKILL”项目以及许多类似项目采用混合策略的原因。对于静态分析无法解决的“顽疾”它会嵌入一个轻量级的动态翻译器JIT编译器作为后备方案。其工作方式是在重编译生成的主程序中会插入一些“桩代码”Stubs或“陷阱”Traps。当程序执行到一处静态分析时无法确定目标比如一个jr $t0指令跳转地址在运行时计算得出的间接跳转时就会陷入一个预先设置好的处理函数。这个函数在运行时根据当前的寄存器值计算出真实的跳转目标地址然后检查这个目标地址的代码是否已经被翻译过缓存。如果没有则立即启动一个快速的、优化较少的JIT编译流程将目标代码块翻译成x86-64代码并缓存。最后跳转到新生成的x86-64代码块继续执行。这种“静态为主动态为辅”的混合模式在保证大部分代码享有静态优化红利的同时又具备了处理复杂运行时行为的灵活性。项目代码中你会看到大量用于处理不同MIPS指令模式的翻译函数以及管理“代码缓存”Code Cache的逻辑。注意这种混合模型对调试是巨大的挑战。静态部分可以用常规调试器但动态生成的JIT代码其地址是运行时分配的符号信息缺失需要项目内置的专门调试工具或日志系统来跟踪。3. 项目环境搭建与初步分析拿到“hkmodd/ps2-recomp-Agent-SKILL”的源码仓库第一步不是急着编译而是理解它的结构和依赖。这个项目通常需要比较专业的开发环境。3.1 工具链准备编译环境项目核心是C需要支持C17或更高版本的编译器。在Windows上Visual Studio 2019/2022的MSVC是首选因为其对Windows平台生成原生代码的支持最好。在Linux/macOS上GCC或Clang是标准选择。务必确认你的CMake版本足够新3.15以上。逆向分析工具光有编译器不够你需要“读懂”PS2游戏。以下是黄金组合IDA Pro反汇编行业的标杆对MIPS架构支持极佳。它的交互式图形化界面、强大的交叉引用Xrefs和重命名功能是分析控制流、理解游戏逻辑不可或缺的。免费版的IDA 7.0也提供了基本的MIPS支持。GhidraNSA开源的神器完全免费。它的反编译能力将汇编转成类C代码有时比IDA还强对于理解复杂算法逻辑帮助巨大。虽然上手需要一点时间但对于预算有限的开发者是绝佳选择。PCSX2 调试器虽然目标是取代模拟器但PCSX2的调试功能在项目初期是无价之宝。你可以用它运行游戏设置断点观察内存和寄存器的实时变化验证你对某段代码功能的理解是否正确。这是一种“动态验证静态分析”的手段。辅助脚本与库项目可能依赖一些第三方库来处理ELF文件如libelf、进行二进制操作等。仔细阅读项目的README.md和CMakeLists.txt文件确保所有子模块git submodule都已正确拉取和初始化。3.2 源码结构导读克隆仓库后花些时间浏览目录结构这能帮你快速定位核心模块ps2-recomp-Agent-SKILL/ ├── src/ │ ├── recompiler/ # 重编译器核心 │ │ ├── static_analysis.cpp # 静态分析模块CFG构建等 │ │ ├── ir_generator.cpp # 中间表示生成 │ │ ├── x64_emitter.cpp # x86-64代码生成器 │ │ └── register_allocator.cpp # 寄存器分配器核心难点 │ ├── runtime/ # 运行时支持库 │ │ ├── ps2_hw/ # PS2硬件抽象层GS, VU, IOP等模拟 │ │ ├── memory_manager.cpp # 内存管理TLB模拟、缓存 │ │ └── syscalls.cpp # 系统调用文件I/O、线程等实现 │ └── frontend/ # 前端工具 │ └── main.cpp # 主程序入口协调整个流程 ├── tools/ # 辅助工具脚本如ELF解析器 ├── assets/ # 可能需要放置游戏ROM/BIOS的地方 ├── CMakeLists.txt └── README.md理解这个结构你就明白了整个重编译流水线frontend调用recompiler进行翻译翻译后的代码在运行时需要runtime提供的环境来执行。3.3 获取与分析目标游戏ROM这是合法且伦理上最关键的一步。你必须拥有《Agent SKILL》游戏的正版光盘并从中提取出ISO镜像。使用任何非官方来源的ROM都是不合规的。提取后你需要用二进制查看工具如hexdump或HxD或专门的PS2 ELF提取工具从ISO中找到主执行文件通常名为SLES_XXX.XX或类似其中包含游戏代码的ELF。将这个ELF文件加载到IDA Pro或Ghidra中。第一步是进行初步的符号识别。虽然游戏程序是去除了调试符号的但PS2 SDK中一些通用的运行时库函数如printf,memcpy,sceCdRead等的代码模式是已知的。你可以尝试匹配这些模式或者利用PCSX2在运行时打印的函数调用日志如果有来给反汇编代码中的子程序起上有意义的名字。这一步的成果会直接体现在重编译项目的“系统调用映射表”或“已知函数签名”配置文件中能极大提升翻译的准确性和可读性。4. 核心模块深度解析与实现难点4.1 寄存器分配从MIPS到x86-64的“乾坤大挪移”这是重编译器中最精妙也最易出错的部分。MIPS有32个通用寄存器$0-$31其中一些有特殊用途如$gp全局指针$sp栈指针$ra返回地址。x86-64有16个通用寄存器用途也非常固定如RSP栈指针RBP帧指针RAX返回值。直接的一对一映射是不可能的。策略通常是固定映射关键寄存器将MIPS的栈指针($sp)和帧指针($fp)直接映射到x86-64的RSP和RBP简化函数调用和栈操作。虚拟寄存器与溢出为剩余的MIPS寄存器分配一个虚拟的寄存器池。在翻译一个代码块时分配器会尝试将最活跃的虚拟寄存器分配到真实的x86-64寄存器上。当物理寄存器不足时就需要将某些寄存器的值“溢出”Spill到栈上的临时空间需要时再加载回来。这需要复杂的活跃变量分析。调用约定转换MIPS的前4个参数通过$a0-$a3传递返回值在$v0-$v1。x86-64在Windows和Linux上约定不同Windows用RCX, RDX, R8, R9Linux用RDI, RSI, RDX, RCX, R8, R9。重编译器在翻译函数调用指令jal时必须插入额外的代码来搬运参数和返回值并在必要时保存被调用者保存的寄存器Callee-saved registers。项目中register_allocator.cpp的实现通常会采用图着色算法或线性扫描算法。阅读这部分代码时要重点关注它如何处理寄存器压力大的循环以及它是如何与后续的x86-64代码生成器协同工作的。4.2 内存访问与TLB模拟PS2使用虚拟内存有一个软件管理的TLB来负责虚拟地址到物理地址的转换。这与x86-64硬件管理的MMU完全不同。重编译器不能简单地将MIPS的加载/存储指令lw,sw等翻译成x86-64的mov。常见的实现方式是地址转换钩子在翻译每条内存访问指令时不直接生成访问内存的代码而是生成一个对运行时转换函数的调用。这个函数接收虚拟地址查询模拟的TLB转换成主机PC的物理地址实际上是主机进程虚拟空间中的一个映射区域再进行访问。直接内存映射对于已知的、固定的内存区域如部分内核内存、显存可以在初始化时直接映射到主机内存的某个区间。这样访问这些区域的指令就可以被直接翻译成访问主机内存的指令效率极高。这需要精确的内存布局分析。// 伪代码示例翻译一条 MIPS lw t0, offset(a0) 指令 // 假设 a0 寄存器已被映射到主机寄存器 RDI void translate_load_word(IRBlock block, MIPSInst inst) { // 1. 计算虚拟地址: vaddr GPR[a0] offset emit_x64_lea(block, RAX, {RDI, inst.offset}); // RAX RDI offset // 2. 调用运行时函数进行地址转换并加载 emit_x64_call(block, Runtime::translate_and_load_32bit); // 函数原型: uint32_t translate_and_load_32bit(uintptr_t vaddr); // 返回值在 RAX (x86-64调用约定) // 3. 将结果存入映射给 t0 的主机寄存器 (例如 RBX) emit_x64_mov(block, RBX, RAX); }这种方式带来了巨大的性能开销。因此高级的重编译器会尝试进行别名分析如果能证明某些内存访问不会越界或冲突就可以安全地省略运行时检查直接访问映射的内存。4.3 PS2特有硬件的HLE实现游戏代码中充斥着对EE核心、VU向量单元、GS图形合成器、IOP输入输出处理器等硬件的直接操作。这些无法被翻译成x86-64指令必须用高层模拟HLE来替代。GS图形命令游戏通过向GS的寄存器写入命令来绘制图形。运行时库中的ps2_hw/gs_emulator.cpp需要模拟这些寄存器并将PS2的绘图命令转换为现代图形API如OpenGL、Vulkan或DirectX的调用。这是项目中最复杂的部分之一直接关系到游戏画面能否正确渲染。VU向量程序VU的微码程序本身就是一段可执行的二进制码。一种方法是解释执行但效率低。更激进的方法是为VU微码也实现一个动态二进制翻译器将其翻译成x86-64的SSE/AVX向量指令这能极大提升图形和物理运算的性能。IOP与驱动IOP负责处理手柄、记忆卡、光盘访问等。这部分通常通过实现对应的系统调用来完成例如将PS2的文件读请求重定向到主机操作系统的文件API。这些HLE模块的质量直接决定了重编译后游戏的兼容性、性能和稳定性。它们往往是漏洞Bug和性能瓶颈的集中地。5. 构建、调试与问题排查实战5.1 编译流程与配置假设项目使用CMake一个典型的构建命令序列如下# 在项目根目录 mkdir build cd build # 配置指定Release模式以获得最佳性能开启必要的调试符号 cmake .. -DCMAKE_BUILD_TYPERelWithDebInfo -DENABLE_LOGGINGON # 编译 cmake --build . --config RelWithDebInfo -j$(nproc)关键CMake选项可能包括-DENABLE_LOGGINGON启用详细的运行日志对调试至关重要。-DUSE_OPENGLON/-DUSE_VULKANON选择图形后端。-DPS2_BIOS_PATH/path/to/your/ps2/bios指定PS2 BIOS文件路径某些运行时功能需要。编译成功后你会得到重编译器前端工具例如ps2_recomp_frontend.exe和可能生成的运行时库。5.2 运行与调试技巧首次运行通常需要将PS2游戏ELF和必要的BIOS文件作为参数传递给前端工具。./ps2_recomp_frontend --elf SLES_123.45.ELF --bios scph10000.bin --output agent_skill_pc.exe这个过程可能会比较慢因为它正在进行静态分析和代码生成。如果成功你会得到一个agent_skill_pc.exe文件。运行生成的程序直接运行agent_skill_pc.exe。如果一切顺利游戏窗口会出现。但更可能的情况是它会崩溃或卡住。调试崩溃日志是第一生命线确保编译时开启了日志。程序崩溃后首先查看生成的日志文件如recomp.log。里面通常会有崩溃前最后执行的指令地址、寄存器状态、函数调用栈回溯等信息。结合IDA Pro将日志中报错的地址例如0x00123456复制到IDA Pro中跳转到该地址。查看周围的MIPS代码理解它在做什么。是访问了非法内存还是调用了一个未实现的系统调用使用调试器在Visual Studio或GDB中调试agent_skill_pc.exe。当崩溃发生时查看调用栈。虽然栈帧可能因为翻译而变得混乱但你通常能看到运行时库如memory_manager.cpp或某个HLE函数中的代码这能帮你定位问题是在翻译逻辑、运行时模拟还是HLE实现中。对比PCSX2在PCSX2中运行原版游戏在疑似出问题的代码段设置断点单步执行观察内存和寄存器的正确值应该是什么。然后将这些值与你的重编译程序运行时的值进行对比差异点往往就是Bug所在。5.3 常见问题与解决策略下表总结了我实践中遇到的一些典型问题及排查思路问题现象可能原因排查步骤与解决方案程序启动立即崩溃日志显示在某个固定地址访问违规。1. 静态分析错误将数据段误识别为代码段执行。2. TLB映射错误导致地址转换失败。3. 关键的系统调用或HLE函数未实现。1. 用IDA确认该地址在原始ELF中属于什么段.text代码段还是.data数据段。2. 检查运行时内存管理器的初始化日志看对应地址区间的映射是否正确建立。3. 在日志中搜索“unimplemented”或“syscall”补全对应的桩函数。游戏画面黑屏或花屏但声音和逻辑似乎正常。1. GS图形命令翻译或模拟错误。2. VRAM显存映射错误。3. 顶点数据格式解析错误。1. 开启GS模拟器的详细调试日志对比PCSX2在相同游戏场景下发出的GS命令包。2. 检查gs_emulator.cpp中关于帧缓冲、纹理上传的代码。3. 使用RenderDoc等图形调试器捕获一帧查看提交的几何数据和着色器状态。游戏运行速度极慢。1. 动态翻译JIT路径过多频繁陷入运行时翻译。2. 内存访问检查TLB模拟开销过大。3. HLE函数如文件I/O效率低下。1. 使用性能分析工具如VTune, perf找到热点函数。如果大量时间花在JIT编译上考虑优化代码缓存策略或增加静态分析的激进程度。2. 对连续、线性的内存访问如数组遍历尝试生成不使用运行时检查的优化代码块。3. 将同步的I/O调用改为异步或实现缓存。特定游戏功能如存档、手柄震动失效。对应的IOP系统调用或硬件特性未模拟。查阅PS2 SDK文档或PCSX2源码找到该功能对应的底层调用如sceMc系列函数用于记忆卡在syscalls.cpp或iop_emulator.cpp中实现其逻辑可能只需返回一个成功码或模拟一个简单的文件操作。生成的程序在某些CPU上崩溃在其他CPU上正常。生成的x86-64代码可能依赖了特定CPU的特性如某条SSE指令或者存在线程同步问题。1. 检查代码生成器x64_emitter.cpp的指令发射逻辑确保它没有默认使用过于新的指令集如AVX-512。可以添加一个“目标CPU特性”的编译选项。2. 检查多线程相关的HLE实现如果游戏使用了EE的多线程确保内存屏障和原子操作的正确性。实操心得调试此类项目最有效的方法是“差分调试法”。准备两个环境一个是能正常运行的PCSX2开启调试器一个是你的重编译程序。让两者执行相同的游戏操作例如都走到主菜单界面然后对比关键内存区域如某个代表角色生命值的变量地址的内容、关键函数的返回值、GS命令队列等。一旦发现差异就找到了问题的起点。这个过程极其枯燥但也是逆向工程的精髓所在。6. 性能优化与高级技巧当程序能基本运行后下一步就是让它跑得更快、更稳定。6.1 静态分析优化函数识别与内联通过更精确的模式匹配或调用图分析识别出更多的小型库函数如memcpy,sqrtf。一旦识别可以不按PS2的调用约定来翻译而是直接内联Inline其等价的、高度优化的x86-64实现甚至直接调用宿主机的标准库函数。这能消除大量的调用开销和上下文切换。循环优化在中间表示IR层面识别出循环后可以进行循环不变代码外提、强度削弱如将乘法替换为加法等优化。对于循环内的数组访问如果索引和边界可以分析清楚可以生成使用x86-64 SIMD指令SSE/AVX的向量化代码这是性能提升的“杀手锏”。6.2 运行时优化代码缓存与预热优化动态翻译器JIT的代码缓存管理。采用LRU最近最少使用策略并实现“预热”机制在游戏加载阶段主动地、按一定策略如按函数调用关系提前翻译一些可能用到的代码块避免在游戏运行时因翻译造成卡顿。直接内存访问优化实现一个“快速路径”Fast Path。对于经过分析确认是访问固定、已映射内存区域如全局变量区的指令生成直接的内存访问代码完全绕过TLB转换函数。这需要精确的别名分析和内存区域标记。线程与并发PS2的EE核心支持两个硬件线程。重编译后的程序可以利用宿主机的多核CPU将不同的硬件线程映射到不同的主机线程上执行甚至可以将VU模拟、音频处理等任务放到独立的线程中实现真正的并行化。6.3 图形后端优化这是视觉体验和性能的关键。如果使用OpenGL/Vulkan命令批处理不要每收到一条PS2 GS命令就立即调用一次OpenGL API。应该将一帧内的多个绘图命令缓冲起来合并状态变化最后一次性提交减少驱动开销。着色器生成PS2的固定功能管线可以翻译成现代的GLSL/HLSL着色器。为不同的PS2渲染模式如不同的纹理混合模式、雾化效果预编译生成对应的着色器程序并建立缓存。分辨率缩放与纹理增强这是HLE的优势所在。可以在渲染的最后阶段将帧缓冲的内容以更高分辨率渲染到屏幕上并对加载的纹理进行实时放大和过滤如使用xBRZ、FSR等算法让老游戏在现代显示器上焕然一新。这个项目就像一座连接过去与现在的技术桥梁每一行代码都充满了对旧硬件设计的理解和对新性能极限的挑战。它不是一个能一键使用的工具而是一个需要你深入芯片指令集、操作系统和图形学原理的实验室。成功让一个游戏从黑屏到出现logo再到可操作的角色每一步都伴随着无数次的失败和恍然大悟。对于有志于深入系统编程、编译器和逆向工程领域的朋友来说没有比这更好的练手项目了。它教会你的不仅仅是技术更是一种系统性解决问题的耐心和拆解复杂系统的能力。最后一个小建议从一个非常简单的、图形不复杂的PS2自制程序或Demo开始而不是直接挑战《Agent SKILL》这样的商业游戏会让你建立信心的过程顺利很多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2612837.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…