编译器构造:从零手写汇编与反汇编程序(二)

这个秋季,三碗饭会开始更新自己在秋季课程的笔记,主要包括Introduction to ML,可能还会有Complier Construction 以及 Computer Graphics.

本文将介绍Complier Construction中关于模拟器,汇编以及反汇编的知识,在下一章我们会从0写一个简易模拟器,以及汇编,反汇编程序。这门课如果没有兴趣,会非常无聊非常无聊,当然我一开始也觉得挺无聊的,毕竟搞AI Agent比这个有意思多,但我还是会尽量以简单的描述(避免复杂的解释),以及有意思的例子去讲这些知识。

1. 概要

了解下之后我们会完成的三个内容。
汇编器:

将人类可读的汇编代码(.uma)转换为机器码(.um)

相当于"翻译官",把人类语言翻译成机器语言

反汇编器

将机器码(.um)转换回汇编代码(.uma)

相当于"解码器",把机器语言翻译回人类语言

主要用于调试和验证

模拟器:

执行机器码(.um)

相当于"虚拟CPU",实际运行程序

负责程序的实际执行

2. 核心组件

2.1 指令结构

反汇编器使用与汇编器相同的指令结构:

cpp 复制代码
enum class BinIns {
    HALT,   // 停止程序
    IN,     // 输入
    OUT,    // 输出
    ADD,    // 加法
    SUB,    // 减法
    MUL,    // 乘法
    DIV,    // 除法
    LDC,    // 加载常数
    INVALID // 无效指令
};

struct Instruction {
    BinIns op;  // 操作码
    int arg;    // 参数
};

2.2 主要数据结构

反汇编器类中包含两个关键的映射表:

cpp 复制代码
class Disassembler {
private:
    // 指令映射表(从二进制到汇编)
    std::map<BinIns, std::string> binToAss;
    // 指令参数个数表
    std::map<BinIns, int> insArgNum;
};
  • binToAss: 存储二进制操作码到汇编指令字符串的映射
  • insArgNum: 记录每个指令需要的参数个数

3. 核心功能实现

3.1 初始化映射表

cpp 复制代码
void initMapping() {
    binToAss[BinIns::HALT] = "HALT";
    binToAss[BinIns::IN]   = "IN";
    binToAss[BinIns::OUT]  = "OUT";
    binToAss[BinIns::ADD]  = "ADD";
    binToAss[BinIns::SUB]  = "SUB";
    binToAss[BinIns::MUL]  = "MUL";
    binToAss[BinIns::DIV]  = "DIV";
    binToAss[BinIns::LDC]  = "LDC";
}

3.2 初始化参数个数表

cpp 复制代码
void initArgNumbers() {
    insArgNum[BinIns::HALT] = 0;
    insArgNum[BinIns::IN]   = 0;
    insArgNum[BinIns::OUT]  = 0;
    insArgNum[BinIns::ADD]  = 0;
    insArgNum[BinIns::SUB]  = 0;
    insArgNum[BinIns::MUL]  = 0;
    insArgNum[BinIns::DIV]  = 0;
    insArgNum[BinIns::LDC]  = 1;
}

3.3 单条指令反汇编

cpp 复制代码
std::string disassembleLine(const Instruction& inst) {
    if (inst.op == BinIns::INVALID) {
        return "; INVALID INSTRUCTION";
    }

    auto it = binToAss.find(inst.op);
    if (it == binToAss.end()) {
        return "; UNKNOWN INSTRUCTION";
    }

    std::string result = it->second;
    if (insArgNum[inst.op] > 0) {
        result += " " + std::to_string(inst.arg);
    }

    return result;
}

这个函数是反汇编器的核心,它:

  1. 检查指令的有效性
  2. 查找对应的汇编指令字符串
  3. 如果指令需要参数,添加参数值
  4. 返回完整的汇编指令字符串

3.4 程序反汇编

cpp 复制代码
std::vector<std::string> disassembleProgram(const std::vector<Instruction>& program) {
    std::vector<std::string> lines;
    for (const auto& inst : program) {
        lines.push_back(disassembleLine(inst));
    }
    return lines;
}

3.5 Main函数

cpp 复制代码
#include "../include/assembler.hpp"
#include "../include/disassembler.hpp"
#include <fstream>
#include <vector>
#include <string>

// 从文件读取程序
std::vector<std::string> readFile(const std::string& filename) {
    std::vector<std::string> lines;
    std::ifstream file(filename);
    if (!file) {
        throw std::runtime_error("Cannot open file: " + filename);
    }

    std::string line;
    while (std::getline(file, line)) {
        lines.push_back(line);
    }
    return lines;
}

int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cout << "Usage: " << argv[0] << " <input.asm> <mode>" << std::endl;
        std::cout << "Mode: asm - assemble, dis - disassemble" << std::endl;
        return 1;
    }

    try {
        // 读取源文件
        auto sourceCode = readFile(argv[1]);
        std::string mode = argv[2];

        if (mode == "asm") {
            // 显示源代码
            std::cout << "Source code:" << std::endl;
            for (const auto& line : sourceCode) {
                std::cout << line << std::endl;
            }
            std::cout << std::endl;

            // 创建汇编器并汇编代码
            Assembler assembler;
            auto program = assembler.assembleProgram(sourceCode);

            // 显示汇编结果
            std::cout << "Assembled code:" << std::endl;
            assembler.outputBinary(program);
        }
        else if (mode == "dis") {
            // 创建汇编器和反汇编器
            Assembler assembler;
            Disassembler disassembler;
            
            // 先汇编代码(这里假设输入是汇编代码)
            auto program = assembler.assembleProgram(sourceCode);
            
            // 显示反汇编结果
            std::cout << "Disassembled code:" << std::endl;
            disassembler.outputAssembly(program);
        }
        else {
            std::cout << "Invalid mode. Use 'asm' for assembly or 'dis' for disassembly." << std::endl;
            return 1;
        }

    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

4. 测试方式

4.1 命令行接口

程序支持两种模式:

bash 复制代码
./assembler <input.asm> asm    # 汇编模式
./assembler <input.asm> dis    # 反汇编模式

5 测试结果

assembly 复制代码
你的文件目录 .\build\assembler.exe test/test_disasm.asm dis
Disassembled code:
LDC 42
IN
ADD
OUT
LDC 10
MUL
OUT
LDC 2
DIV
SUB
OUT
HALT
5.1 指令集说明
指令 参数 功能描述
LDC 数值 将一个常数加载到栈中
IN 从输入读取一个数字到栈中
ADD 将栈顶的两个数字相加
OUT 输出栈顶的结果
MUL 将栈顶的两个数字相乘
DIV 将栈顶的两个数字相除
SUB 将栈顶的两个数字相减
HALT 停止程序执行
5.1 指令序列
assembly 复制代码
LDC 42    ; 加载常数42
IN        ; 读取用户输入
ADD       ; 相加
OUT       ; 输出
LDC 10    ; 加载常数10
MUL       ; 相乘
OUT       ; 输出
LDC 2     ; 加载常数2
DIV       ; 相除
SUB       ; 相减
OUT       ; 输出
HALT      ; 结束
5.2 执行步骤
  1. 将常数42和用户输入的数字相加
  2. 输出第一次计算结果
  3. 将上一步结果乘以10
  4. 输出第二次计算结果
  5. 将上一步结果除以2
  6. 减去最初的输入值
  7. 输出最终结果
  8. 程序结束
5.3 示例执行

假设用户输入值为8,程序的执行过程如下:

步骤 操作 计算过程 结果
1 加法 42 + 8 50
2 输出 输出50 50
3 乘法 50 * 10 500
4 输出 输出500 500
5 除法 500 / 2 250
6 减法 250 - 8 242
7 输出 输出242 242
8 结束 程序终止 -
5.4 栈操作说明

每个操作都会影响栈的状态:

  • LDC: 将数值压入栈顶
  • IN: 将输入值压入栈顶
  • ADD/MUL/DIV/SUB: 弹出栈顶两个值,计算后将结果压回栈顶
  • OUT: 输出栈顶值(但不弹出)
  • HALT: 终止程序执行
相关推荐
草莓熊Lotso19 小时前
Linux 权限管理进阶:从 umask 到粘滞位的深度解析
linux·运维·服务器·人工智能·ubuntu·centos·unix
美狐美颜sdk21 小时前
直播美颜SDK特效功能实战:从API调用到效果调优的全过程
人工智能·1024程序员节·美颜sdk·直播美颜sdk·第三方美颜sdk
sali-tec1 天前
C# 基于halcon的视觉工作流-章56-彩图转云图
人工智能·算法·计算机视觉·c#
梦想画家1 天前
基于PyTorch的时间序列异常检测管道构建指南
人工智能·pytorch·python
Elastic 中国社区官方博客1 天前
在 Elasticsearch 中使用 Mistral Chat completions 进行上下文工程
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
一碗绿豆汤1 天前
机器学习第二阶段
人工智能·机器学习
用什么都重名1 天前
DeepSeek-OCR 深度解析
人工智能·ocr·deepseek-ocr
河南骏1 天前
RAG_检索进阶
人工智能·深度学习
灯火不休时1 天前
95%准确率!CNN交通标志识别系统开源
人工智能·python·深度学习·神经网络·cnn·tensorflow
mit6.8241 天前
[手机AI开发sdk] Aid_code IDE | PC浏览器同步访问
ide·人工智能·智能手机