程序最美(寻路)

你还在坚持练习你的技术吗?运动员天天训练,音乐家也会演练更难的曲章。你呢?

实现一个反汇编器

实现一个反汇编器

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

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

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

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

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

// 实现一个反汇编器
#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] + '\t';
    }
    
    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 + '\t' + 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) + '\t';
        }
        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 国庆假期 于家中

posted on 2013-10-08 21:05  unixfy  阅读(2188)  评论(0编辑  收藏  举报

导航