实现一个反汇编器
实现一个反汇编器
上文《反汇编器源码剖析》,我们对一反汇编器源码进行了学习,了解了反汇编器的实现原理。反汇编是汇编的逆过程,其也是包含三个主要部分:
- 汇编指令集
- 二进制指令集
- 二进制指令到汇编指令的映射
有了这三部分之后,我们就可以对二进制指令,将其翻译成汇编指令,也就完成了反汇编过程。
我们的二进制指令集和汇编指令集还是沿用之前的指令集。
下面我们先给出实现的反汇编器,然后对相关代码进行解释。
// 实现一个反汇编器 #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 国庆假期 于家中
(完)
文档信息
·版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
·博客地址:http://www.cnblogs.com/unixfy
·博客作者:unixfy
·作者邮箱:goonyangxiaofang(AT)163.com
·如果你觉得本博文的内容对你有价值,欢迎对博主 小额赞助支持