zoukankan      html  css  js  c++  java
  • 实现一个反汇编器

    实现一个反汇编器

             上文《反汇编器源码剖析》,我们对一反汇编器源码进行了学习,了解了反汇编器的实现原理。反汇编是汇编的逆过程,其也是包含三个主要部分:

    • 汇编指令集
    • 二进制指令集
    • 二进制指令到汇编指令的映射

             有了这三部分之后,我们就可以对二进制指令,将其翻译成汇编指令,也就完成了反汇编过程。

             我们的二进制指令集和汇编指令集还是沿用之前的指令集。

             下面我们先给出实现的反汇编器,然后对相关代码进行解释。

    // 实现一个反汇编器
    #include <iostream>
    #include <sstream>
    #include <string>
    #include <vector>
    #include <map>
    using namespace std;
    
    enum BinIns;
    
    // 二进制指令结构体
    // 指令码+操作数
    struct Instruction
    {
        BinIns op;  // 指令码只占一个字节
        int    arg; // 操作数,占四个字节
    };
    
    // 枚举类型的二进制指令集
    enum BinIns
    {
        binHalt, binIn, binOut, binAdd, binSub, binMul, binDiv,
        binDup,
        binLd, binSt, binLdc, binJlt, binJle, binJgt, binJge, binJeq, binJne, binJmp,
        binInvalid
    };
    // 枚举类型说明:
    // enum后面定义的是枚举类型名
    // 花括号内部是该枚举类型可以取的值
    
    // 初始化汇编指令集
    void InitAssembleInstructions(vector<string>& assIns)
    {
        assIns.clear();
    
        assIns.push_back("HALT");
        assIns.push_back("IN");
        assIns.push_back("OUT");
        assIns.push_back("ADD");
        assIns.push_back("SUB");
        assIns.push_back("MUL");
        assIns.push_back("DIV");
    
        assIns.push_back("DUP");
    
        assIns.push_back("LD");
        assIns.push_back("ST");
        assIns.push_back("LDC");
        assIns.push_back("JLT");
        assIns.push_back("JLE");
        assIns.push_back("JGT");
        assIns.push_back("JGE");
        assIns.push_back("JEQ");
        assIns.push_back("JNE");
        assIns.push_back("JMP");
    }
    
    // 初始化
    // 指令-参数个数
    void InitInstrctionArgNumber(map<BinIns, int>& insArgNum)
    {
        insArgNum.clear();
    
        insArgNum[binHalt] = 0;
        insArgNum[binIn]   = 0;
        insArgNum[binOut]  = 0;
        insArgNum[binAdd]  = 0;
        insArgNum[binSub]  = 0;
        insArgNum[binMul]  = 0;
        insArgNum[binDiv]  = 0;
    
        insArgNum[binDup]  = 0;
    
        insArgNum[binLd]   = 0;
        insArgNum[binSt]   = 0;
    
        insArgNum[binLdc]  = 1;
        insArgNum[binJlt]  = 1;
        insArgNum[binJle]  = 1;
        insArgNum[binJgt]  = 1;
        insArgNum[binJge]  = 1;
        insArgNum[binJeq]  = 1;
        insArgNum[binJne]  = 1;
        insArgNum[binJmp]  = 1;
    
        insArgNum[binInvalid] = 0;
    }
    
    // 建立二进制指令到汇编指令的映射
    // 初始化
    void InitBinaryToAssemble(const vector<string>& assIns, map<BinIns, string>& binToIns)
    {
        binToIns.clear();
        for (auto i = 0; i != assIns.size(); ++i)
        {
            // assIns和BinIns的指令次序一致
            binToIns[static_cast<BinIns>(i)] = assIns[i];
        }
    }
    
    // 读入二进制指令
    void ReadBinary(vector<string>& bin)
    {
        bin.clear();
        string line;
        while (getline(cin, line))
        {
            bin.push_back(line);
        }
    }
    
    // 显示二进制指令
    void Display(const vector<string>& bar)
    {
        for (auto i = 0; i != bar.size(); ++i)
        {
            cout << bar[i] << endl;
        }
    }
    
    // 将读入的二进制指令转换为Instruction形式
    void BinaryToAssemble(const vector<string>& bin,
                          vector<string>& ass,
                          const map<BinIns, string>& binToIns,
                          map<BinIns, int>& insArgNum)
    {
        ass.clear();
        string binLine;
        for (auto i = 0; i != bin.size(); ++i)
        {
            binLine += bin[i] + '	';
        }
        
        cout << binLine << endl;
    
        istringstream sin(binLine);
        string strOp, strArg;
        string op;
        string arg;
        string assIns;
        BinIns opBin;
        while (sin >> strOp)
        {
            opBin = static_cast<BinIns>(atoi(strOp.c_str()));
            auto cit = binToIns.find(opBin);
            if (cit == binToIns.end())
            {
                // 非法二进制指令
                // 忽略处理
                ;
                break;
            }
            op = cit->second;
            int argNum = insArgNum[cit->first];
            if (argNum > 0)
            {
                sin >> strArg;
                arg = strArg;
            }
            else
            {
                arg = "";
            }
            assIns = op + '	' + arg;
            ass.push_back(assIns);
        }
    }
    
    // 二进制字符串为十进制字符串
    string StringToNum(const string& str)
    {
        string ret;
        int num = 0;
        for (auto i = 0; i != str.size(); ++i)
        {
            num = num * 2 + str[i] - '0';
        }
        char tmp[101];
        itoa(num, tmp, 10);
        ret = tmp;
        return ret;
    }
    
    // 二进制指令转换为十进制指令
    // 针对输入的二进制指令为二进制编码形式的情况
    void BinaryToDec(vector<string>& bin)
    {
        for(auto i = 0; i != bin.size(); ++i)
        {
            istringstream sin(bin[i]);
            string tmp, ins;
            while (sin >> tmp)
            {
                ins += StringToNum(tmp) + '	';
            }
            bin[i] = ins;
        }
    }
    
    int main()
    {
        // 汇编指令集
        vector<string> assIns;
        InitAssembleInstructions(assIns);
    
        // 二进制指令-操作数个数
        map<BinIns, int> insArgNum;
        InitInstrctionArgNumber(insArgNum);
    
        // 汇编指令到二进制的映射
        map<BinIns, string> binToAss;
        InitBinaryToAssemble(assIns, binToAss);
    
        vector<string> bin; // 保存读入的二进制指令
        ReadBinary(bin);
    
        cout << endl;
        Display(bin);
        cout << endl;
    
        vector<string> ass; // 保存转换后的汇编指令
        BinaryToAssemble(bin, ass, binToAss, insArgNum);
    
        Display(ass);
    
        cout << endl;
    
        return 0;
    }

             测试用例:

             反汇编器的实现与汇编器实现整体框架基本一致。二进制指令集和汇编指令集完全一样,不同点在于汇编器是从汇编指令到二进制指令的转换,反汇编器是从二进制指令到汇编指令的转换。

             我们对输入的二进制指令先将其保存,然后将其逐个扫描,将其解析出对应的二进制值,找到该指令对应的汇编指令,如果该指令具有操作数,则继续将操作数读取出来,并入到汇编指令中。顺序扫描整个二进制指令,即得到其对应的汇编指令。

             另外,默认情况下,我们认为输入的二进制指令其表示形式为十进制的,如果输入的是二进制的形式,那么可以调用BinaryToDec函数,将二进制形式的指令转换为十进制形式的指令,进而进行反汇编操作。

             到此为止,我们剖析了汇编器和反汇编器的源码,了解了汇编器和反汇编器的原理,并实现了简单的汇编器和反汇编器。

             汇编器和反汇编器其主要包含三部分:二进制指令集的定义、汇编指令集的定义、二进制指令集和汇编指令集之间的相互转换关系。

             下面我们给出汇编器和反汇编器的简单模型:

             接下来,我们将继续学习stack_machine源代码。此外,学习一些C++方面的东西。

             2013.10.6 0:33 国庆假期 于家中

  • 相关阅读:
    pdf文件的导入导出
    扩展方法用法整理
    c#批量插入数据库Demo
    Linq表达式和Lambda表达式用法对比
    Lambda表达式的诞生过程
    LeetCode77. Combinations(剑指offer38-2)
    LeetCode47.Permutations II(剑指offer38-1)
    LeetCode567. Permutation in String
    LeetCode46. Permutations
    图解HTTP-1.web和网络基础
  • 原文地址:https://www.cnblogs.com/unixfy/p/3357827.html
Copyright © 2011-2022 走看看