make-doom-for-mips

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cross-Compiling C Programs for MIPS VM Environments

为MIPS VM环境交叉编译C程序

Overview

概述

This skill provides guidance for cross-compiling complex C programs to run on MIPS-based virtual machines with custom runtime environments. The primary challenge involves creating freestanding executables that work without standard system libraries, implementing custom syscall interfaces, and ensuring the compiled binary actually produces expected output in the target VM.
本技能提供了为搭载自定义运行时环境的MIPS虚拟机交叉编译复杂C程序的指导。主要挑战在于创建无需标准系统库即可运行的独立可执行文件、实现自定义系统调用接口,以及确保编译后的二进制文件能在目标VM中输出预期结果。

Critical Success Criteria

关键成功标准

Before declaring any task complete, verify the actual acceptance criteria are met:
  1. Identify what output the VM expects (e.g., frame files, console output, specific exit codes)
  2. Run the compiled binary in the VM and confirm expected artifacts are created
  3. Never accept "the program runs some instructions" as success - verify end-to-end functionality
在宣告任务完成前,需验证是否满足以下实际验收标准
  1. 明确VM期望的输出类型(例如帧文件、控制台输出、特定退出码)
  2. 在VM中运行编译后的二进制文件,确认生成了预期的产物
  3. 绝不能将"程序执行了部分指令"视为成功——必须验证端到端的功能

Approach

实施步骤

Phase 1: Environment Analysis

阶段1:环境分析

Before writing any code, thoroughly analyze the target environment:
  1. Read the VM implementation completely - Understand:
    • Available syscalls and their exact signatures
    • File system abstractions and path handling
    • Memory layout expectations
    • How the VM handles program termination
    • Any special requirements for input/output
  2. Analyze the source program's dependencies:
    • List all required standard library functions
    • Identify file I/O patterns (WAD files, config files, output files)
    • Understand the main loop structure and when output occurs
    • Map out initialization sequence and failure points
  3. Document the interface contract:
    • What syscall numbers map to what operations
    • Expected calling conventions
    • Return value semantics and error handling
在编写任何代码前,需全面分析目标环境:
  1. 完整阅读VM实现代码——理解:
    • 可用的系统调用及其精确签名
    • 文件系统抽象与路径处理方式
    • 内存布局要求
    • VM如何处理程序终止
    • 输入/输出的特殊要求
  2. 分析源程序的依赖项
    • 列出所有需要的标准库函数
    • 识别文件I/O模式(WAD文件、配置文件、输出文件)
    • 理解主循环结构及输出触发时机
    • 梳理初始化流程与故障点
  3. 记录接口约定
    • 系统调用编号与操作的映射关系
    • 预期的调用约定
    • 返回值语义与错误处理机制

Phase 2: Systematic Stdlib Implementation

阶段2:系统化标准库实现

Create custom standard library implementations methodically:
  1. Audit all required functions upfront - Do not add functions one-by-one as errors appear. Instead:
    • Grep for all function calls in the source
    • Create a complete list before starting implementation
    • Group by category: string ops, memory ops, I/O, math
  2. Implement complete functionality for critical functions:
    • printf
      ,
      sprintf
      ,
      snprintf
      - Implement actual formatting, not stubs returning 0
    • sscanf
      - Implement actual parsing if the program uses it
    • File operations - Ensure paths resolve correctly in the VM
  3. Create comprehensive stub headers - For each system header:
    • Define only what the program actually uses
    • Avoid pulling in real system headers that conflict
有条理地创建自定义标准库实现:
  1. 预先审核所有所需函数——不要在出现错误时才逐个添加函数。正确做法:
    • 搜索源码中的所有函数调用
    • 在开始实现前创建完整的函数列表
    • 按类别分组:字符串操作、内存操作、I/O、数学运算
  2. 为关键函数实现完整功能
    • printf
      sprintf
      snprintf
      ——实现实际的格式化逻辑,而非返回0的桩函数
    • sscanf
      ——如果程序用到该函数,需实现实际的解析逻辑
    • 文件操作——确保路径在VM中能正确解析
  3. 创建全面的桩头文件——针对每个系统头文件:
    • 仅定义程序实际用到的内容
    • 避免引入会产生冲突的真实系统头文件

Phase 3: Cross-Compilation Setup

阶段3:交叉编译环境配置

Configure the toolchain correctly:
  1. Compiler flags:
    • Use
      -ffreestanding
      to avoid system library assumptions
    • Use
      -nostdlib
      to prevent linking against host libraries
    • Use
      -msoft-float
      if the VM lacks FPU support
    • Address ABI warnings (hard-float vs soft-float) - these cause runtime failures
  2. Linker configuration:
    • Provide appropriate linker script if needed
    • Ensure entry point is correctly specified
    • Verify symbol resolution for all custom implementations
正确配置工具链:
  1. 编译器标志
    • 使用
      -ffreestanding
      以避免依赖系统库的假设
    • 使用
      -nostdlib
      以防止链接到主机库
    • 如果VM不支持FPU,使用
      -msoft-float
    • 解决ABI警告(硬浮点 vs 软浮点)——这些会导致运行时故障
  2. 链接器配置
    • 必要时提供合适的链接脚本
    • 确保入口点指定正确
    • 验证所有自定义实现的符号解析

Phase 4: Iterative Testing with Verification

阶段4:带验证的迭代测试

Test against actual success criteria at each step:
  1. After first successful compilation:
    • Run in VM immediately
    • Check if expected output files are created
    • If program terminates early, investigate why
  2. When program terminates unexpectedly:
    • Examine the termination address
    • Add debug output at key checkpoints
    • Verify resource loading (WAD files, data files)
    • Check if required command-line arguments are provided
  3. Trace program flow:
    • Understand when the expected output should be generated
    • If output depends on game loop iterations, verify the loop runs
    • Check tick counters or frame counters if output is periodic
在每个步骤中对照实际成功标准进行测试:
  1. 首次编译成功后
    • 立即在VM中运行
    • 检查是否生成了预期的输出文件
    • 如果程序提前终止,排查原因
  2. 程序意外终止时
    • 检查终止时的程序计数器——该地址对应的函数/代码是什么?
    • 在关键检查点添加调试输出
    • 验证资源加载(WAD文件、数据文件)
    • 检查是否提供了所需的命令行参数
  3. 追踪程序流程
    • 明确预期输出应何时生成
    • 如果输出依赖游戏循环迭代次数,验证循环是否正常运行
    • 如果输出是周期性的,检查计时计数器或帧计数器

Verification Strategies

验证策略

Pre-Completion Checklist

完成前检查清单

Before declaring the task complete:
  • VM implementation has been read and understood
  • All syscalls used by custom stdlib match VM's implementation
  • Critical functions (printf, file I/O) have working implementations, not stubs
  • Resource files (WAD, data) are accessible via VM's file system
  • Program runs to the point where expected output should be generated
  • Expected output files actually exist after VM execution
  • Program executes a reasonable number of instructions (not early termination)
在宣告任务完成前:
  • 已阅读并理解VM实现代码
  • 自定义标准库使用的所有系统调用与VM实现匹配
  • 关键函数(printf、文件I/O)具备可正常工作的实现,而非桩函数
  • 资源文件(WAD、数据文件)可通过VM的文件系统访问
  • 程序运行到应生成预期输出的阶段
  • VM执行后确实生成了预期的输出文件
  • 程序执行了合理数量的指令(未提前终止)

Debugging Early Termination

调试提前终止问题

When a program terminates prematurely:
  1. Check the program counter at termination - what function/code is at that address?
  2. Add print statements at initialization milestones
  3. Verify file open operations succeed (check return values)
  4. Ensure required arguments are passed to main()
  5. Check if errno or error handlers are being triggered
当程序提前终止时:
  1. 检查终止时的程序计数器——该地址对应的是哪个函数/代码?
  2. 在初始化关键节点添加打印语句
  3. 验证文件打开操作是否成功(检查返回值)
  4. 确保main()函数接收到了所需的参数
  5. 检查是否触发了errno或错误处理程序

Validating Output Generation

验证输出生成

For frame-based output (like DOOM):
  1. Understand when frames are written (e.g., every N ticks)
  2. Verify the game loop executes enough iterations
  3. Check file write syscalls are being called
  4. Confirm output path is writable in VM environment
对于基于帧的输出(如DOOM):
  1. 明确帧的写入时机(例如每N个时钟周期)
  2. 验证游戏循环执行了足够的迭代次数
  3. 检查文件写入系统调用是否被调用
  4. 确认输出路径在VM环境中可写入

Common Pitfalls

常见陷阱

Stub Functions That Break Programs

破坏程序的桩函数

Problem: Implementing
printf
/
sprintf
as stubs returning 0 breaks programs that depend on formatted output for initialization or configuration parsing.
Solution: Implement actual formatting logic or at minimum ensure the output buffer receives expected content.
问题:将
printf
/
sprintf
实现为返回0的桩函数,会破坏依赖格式化输出进行初始化或配置解析的程序。
解决方案:实现实际的格式化逻辑,或至少确保输出缓冲区能接收到预期内容。

Ignoring Linker Warnings

忽略链接器警告

Problem: ABI mismatch warnings (hard-float vs soft-float) are dismissed but cause runtime failures when floating-point operations execute.
Solution: Ensure consistent floating-point ABI across all compiled objects and the VM's expectations.
问题:忽略ABI不匹配警告(硬浮点 vs 软浮点),但这些警告会导致浮点运算时出现运行时故障。
解决方案:确保所有编译对象与VM的预期保持一致的浮点ABI。

Premature Success Declaration

过早宣告成功

Problem: Seeing "program executed N instructions" and concluding success without verifying actual output.
Solution: Always verify the specific acceptance criteria (file creation, correct output content) before marking complete.
问题:看到"程序执行了N条指令"就判定成功,未验证实际输出。
解决方案:在标记任务完成前,务必验证具体的验收标准(文件创建、输出内容正确)。

Missing Resource Files

缺失资源文件

Problem: DOOM and similar programs require data files (WAD) that must be accessible via the VM's file system abstraction.
Solution: Verify the binary can locate and open required resources. Check if paths need adjustment for VM environment.
问题:DOOM及类似程序需要数据文件(WAD),这些文件必须能通过VM的文件系统抽象层访问。
解决方案:验证二进制文件能否定位并打开所需资源。检查是否需要针对VM环境调整路径。

Incomplete Dependency Analysis

依赖项分析不完整

Problem: Adding functions one-by-one as compilation errors appear leads to incomplete implementations and missed dependencies.
Solution: Systematically audit all function calls in the source code before starting implementation.
问题:在出现编译错误时才逐个添加函数,导致实现不完整且遗漏依赖项。
解决方案:在开始实现前,系统地审核源码中的所有函数调用。

Decision Framework

决策框架

When to Add Debug Output

何时添加调试输出

Add debug output when:
  • Program terminates after fewer instructions than expected
  • Expected output files are not created
  • Unsure if initialization completes successfully
在以下情况添加调试输出:
  • 程序执行的指令数少于预期就终止
  • 未生成预期的输出文件
  • 不确定初始化是否成功完成

When to Re-examine VM Implementation

何时重新检查VM实现

Re-read the VM code when:
  • Syscalls return unexpected values
  • File operations fail silently
  • Program behavior differs from expectations
在以下情况重新阅读VM代码:
  • 系统调用返回意外值
  • 文件操作静默失败
  • 程序行为与预期不符

When to Implement vs Stub a Function

何时实现函数 vs 使用桩函数

Implement fully when:
  • Function output is used by the program (printf formatting, string operations)
  • Function affects control flow (file open success/failure)
  • Function result is checked by caller
Stub with caution when:
  • Function is called but result is ignored
  • Function is for features not needed in VM context
  • Must document why stub is safe
在以下情况需完整实现函数:
  • 程序依赖该函数的输出(printf格式化、字符串操作)
  • 函数影响控制流(文件打开成功/失败)
  • 调用者会检查函数结果
谨慎使用桩函数的情况:
  • 函数被调用但返回值被忽略
  • 函数对应VM环境中不需要的功能
  • 必须记录使用桩函数的安全原因