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

这个秋季,三碗饭会开始更新自己在秋季课程的笔记,主要包括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: 终止程序执行
相关推荐
undsky_几秒前
【RuoYi-SpringBoot3-Pro】:将 AI 编程融入传统 java 开发
java·人工智能·spring boot·ai·ai编程
薛定谔的猫19823 分钟前
十二、基于 BERT 的中文文本二分类模型测试实战:从数据加载到准确率评估
人工智能·分类·bert
淮北4944 分钟前
Reinforce算法
人工智能·机器学习
shangjian0075 分钟前
AI-大语言模型LLM-概念术语-Dropout
人工智能·语言模型·自然语言处理
小鸡吃米…6 分钟前
机器学习 - 高斯判别分析(Gaussian Discriminant Analysis)
人工智能·深度学习·机器学习
香芋Yu6 分钟前
【机器学习教程】第01章:机器学习概览
人工智能·机器学习
HySpark12 分钟前
关于语音智能技术实践与应用探索
人工智能·语音识别
AI应用开发实战派13 分钟前
AI人工智能中Bard的智能电子商务优化
人工智能·ai·bard
FL162386312919 分钟前
MMA综合格斗动作检测数据集VOC+YOLO格式1780张16类别
人工智能·yolo·机器学习
应用市场19 分钟前
深度学习图像超分辨率技术全面解析:从入门到精通
人工智能·深度学习