我已经做了很多次,并继续这样做。在这种情况下,您的主要目标是阅读而不是编写汇编程序,我认为这是适用的。
编写自己的反汇编程序。不是为了制造下一个最大的反汇编程序,而是严格地为您准备。目的是学习指令集。是否在新平台上学习汇编程序,是否还记得我曾经知道的平台的汇编程序。从仅几行代码开始,例如添加寄存器,然后在反汇编二进制输出与在输入端添加越来越复杂的指令之间进行乒乓操作:
1)学习特定处理器的指令集
2)了解如何以汇编方式为所述处理器编写代码的细微差别,以便您可以摆动每条指令中的每个操作码位
3)您比大多数使用该指令集谋生的工程师学得更好的指令集
在您的情况下,有两个问题,我通常建议您从ARM指令集开始,今天发货的基于ARM的产品比任何其他产品(包括x86计算机)都多。但是您现在使用ARM并且不了解足够的汇编程序来编写启动代码或其他知道ARM的例程的可能性可能会也可能不会帮助您尝试执行的操作。首先使用ARM的第二个也是更重要的原因是因为指令长度是固定大小且对齐的。诸如x86之类的可变长度指令的拆卸可能是您的第一个项目,这是一场噩梦,这里的目标是学习指令集而不是创建研究项目。第三ARM是一个做得很好的指令集,寄存器的创建是相等的,并且没有单独的特殊差别。
因此,您将必须弄清楚要使用哪种处理器。我建议先使用msp430或ARM,然后再使用ARM,然后再使用x86的混乱。无论使用哪种平台,任何值得使用的平台都具有数据手册或程序员参考手册,这些手册可从供应商获得,其中包括指令集以及操作码的编码(机器语言的位和字节)。为了学习编译器的功能以及如何编写编译器不必为之苦恼的代码,最好了解一些指令集,并了解在每个编译器进行每次优化时,如何在每个指令集上实现相同的高级代码设置。您不想仅仅为了发现代码已使一个编译器/平台变得更好而对其他编译器/平台却变得更差而优化代码。
哦,这是为了分解可变长度的指令集,而不是像在ARM中那样从头开始简单地通过内存线性地分解每个四个字节的单词,或者像msp430那样每两个字节线性地分解(msp430具有可变长度的指令,但是您仍然可以通过如果从中断向量表的入口点开始,则线性地通过内存)。对于可变长度,您想基于向量表或有关处理器如何启动并按执行顺序遵循代码的知识来找到入口点。您必须完全解码每条指令才能知道使用了多少字节,然后,如果该指令不是无条件分支,则假定该指令之后的下一个字节是另一条指令。您还必须存储所有可能的分支地址,并假设这些是更多指令的起始字节地址。有一次我成功通过二进制文件进行了多次传递。从入口点开始,我将该字节标记为一条指令的开始,然后通过内存进行线性解码,直到遇到无条件分支为止。所有分支目标都标记为指令的起始地址。我多次遍历二进制文件,直到没有找到新的分支目标为止。如果您在任何时候发现说一个3字节的指令,但由于某种原因将第二个字节标记为指令的开头,则您遇到了问题。如果代码是由高级编译器生成的,那么除非编译器做恶事,否则不应该发生这种情况,如果代码具有手写汇编程序(例如旧的街机游戏),则很有可能存在永远不会发生的条件分支,如r0 = 0,然后是跳转(如果不为零)。您可能需要手动编辑二进制以外的内容才能继续。对于我认为将在x86上执行的近期目标,我认为您不会遇到问题。
我建议使用gcc工具,如果以x86为目标,则mingw32是在Windows上使用gcc工具的简便方法。如果不是mingw32 plus,那么msys是一个优秀的平台,可以从binutils和gcc源生成交叉编译器(通常非常简单)。mingw32与cygwin相比有一些优势,例如程序速度明显提高,并且可以避免cygwin dll地狱。gcc和binutils将允许您使用C或汇编语言进行编写和反汇编代码,并且网页数量比您所读的更多,向您展示了如何进行这三种方法中的任何一种或全部。如果要使用可变长度的指令集进行此操作,我强烈建议您使用包含反汇编程序的工具集。例如,使用x86的第三方反汇编程序将是一个挑战,因为您永远不知道它是否正确反汇编。其中一些也依赖于操作系统,目标是将模块编译为二进制格式,其中包含来自数据的信息标记指令,以便反汇编程序可以执行更准确的工作。对于这个主要目标,您的另一个选择是拥有一个可以直接编译为汇编程序以供您检查的工具,然后希望当它编译为二进制格式时会创建相同的指令。
简短的回答(可以稍微短一点)。编写反汇编器以学习指令集。我将从像ARM这样具有风险且易于学习的内容开始。一旦知道了一个指令集,通常在几个小时内,其他指令就变得容易得多,通过第三个指令集,您几乎可以立即使用数据手册/参考手册中的语法开始编写代码。所有值得使用的处理器都有一个数据表或参考手册,其中描述了指令的内容,包括操作码的位和字节。学习足够的ARM之类的RISC处理器和x86之类的CISC,足以了解它们之间的差异,诸如必须对所有内容进行寄存器检查或能够使用更少或没有寄存器直接在内存上执行操作。三个操作数指令对两个指令,等等。在调整高级代码时,编译多个处理器并比较输出。您将学到的最重要的事情是,无论编写的高级代码的质量如何,编译器的质量和做出的优化选择都将在实际指令中产生巨大的差异。我建议llvm和gcc(与binutils),都不产生好的代码,但是它们是多平台和多目标的,并且都具有优化器。两者都是免费的,您可以轻松地从源代码为各种目标处理器构建交叉编译器。