我正在尝试将原始机器代码字节作为0和1写入文本文件,并通过BIOS执行它。
然而,我在理解组合安排中的寻址,乘法,偏移,寻址,操作数和指令如何工作方面存在一些问题,即MOV AL, 07
和MOV BL, AL
之间的区别。
我的意思是它在汇编中是有意义的,但在机器码中,获取参数的想法变得非常困难。
所以我想知道的是:我怎样才能更好地理解这一点?我发现没有教程可以准确地解释/描述组合相关中的指令或数据传递,MMIO,寻址模式,算术等之间的连接中的0和1。
在这个网站上http://ref.x86asm.net/coder32.html#x00它会尝试,但我不明白这一点。
示例:假设我想将5移入AL ...我是否将二进制文件中的文字'5'指定为使用AL / MOV指令链接的二进制前缀中的操作码的一部分,或者我是否有一个固定的二进制每条指令的代码,无论价值如何?这就是我想知道的......如何解释如何编写机器代码。
答案 0 :(得分:5)
不幸的是,x86编码很复杂且不规则,理解它很难。编码的最佳“快速入门”是sandpile.org上的一组HTML页面(它简洁,但非常彻底)。
首先:http://sandpile.org/x86/opc_enc.htm - “指令编码”表显示了十几种编码指令的方式。每行中的白色单元表示指令中的必需字节;基于操作码中较早出现的各种字段,存在(或不存在)以下灰色单元格。您应该查看以白色“0Fh”开头的行以及第一行。在同一页面的底部是各种“扩展”操作码字段中出现的位域 - 你忽略了除“modrm / sib”行(第一行)之外的所有字段。
请注意,对于除第一行之外的所有行(即1字节操作码),“mod r / m”字节必须遵循操作码(对于1字节操作码,它取决于指令)。这对大多数2参数指令的参数进行编码。 http://sandpile.org/x86/opc_rm.htm处的表具有以下含义:其中一个参数必须是寄存器,另一个参数可以是寄存器或内存间接(“reg”字段对寄存器进行编码,“mod”和“r / m“字段编码另一个参数)。操作码中的其他地方通常还有一个“方向”位,表示参数的顺序。操作码还指示我们是否正在操作,例如AL,AX,EAX或RAX(即不同大小),或扩展寄存器之一,这就是为什么每个3位字段被列为参考许多不同寄存器的原因。 / p>
在modrm中,如果“mod”位为“11”,则“r / m”字段也指寄存器。否则,它通常是指通过将命名寄存器添加到modrm字节后出现的(可选)位移而构造的存储器地址(此常量长度为0,1或4个字节,具体取决于“mod”位)。例外情况是“r / m”位为“100”(即0x4),通常命名为“SP” - 在这种情况下,内存参数由紧跟在modrm字节之后的附加“sib”字节描述(任何modrm位移出现在同胞之后)。有关SIB的编码,请查看http://sandpile.org/x86/opc_sib.htm,或从modrm页面单击。
最后,要了解方向和大小的来源,请查看一些操作码:http://sandpile.org/x86/opc_1.htm。前四个条目都是“ADD”,参数有两个不同的顺序,并且有两个不同的宽度。所以在这种情况下,指令的底部位是编码方向和宽度。
答案 1 :(得分:1)
汇编程序助记符和机器指令之间存在(大多数)一对一映射。您可以在Intel Software Developers Manual第2卷中找到这些映射,其中包含完整的x86 16,32和64位指令集。您可能希望从第2章:指令格式开始,它描述了您尝试提供的翻译。
在mov al, 5
的情况下,就像你说的那样,你把文字放在那里。机器代码中的指令是:
b0 05
因为这是MOV r8, imm8
指令的MOV
形式。对于mov bl, al
,您需要MOV r/m8,r8
表单,在您的情况下将编码为:
88 c3
您可以在表2-2使用ModR / M字节的32位寻址表单中查找c3
,您将在{{}的交叉处看到它1}}行和BL
列。 (如果这是你所处的模式,也有一个16位的表 - 在这种情况下的值是相同的。)