作者:拍友2602924913 | 来源:互联网 | 2023-01-29 02:50
我正在研究x86汇编语言,遵循Kip Irvine的书"用于x86处理器的第7版Edi的汇编语言".
在第4章中,作者谈到了机器指令
我的问题是,为什么机器指令中没有al
(或表示al
)A0 00010400
?如果al
没有,机器怎么知道我们想要将地址的值移动00010400
到al
?
============ 编辑1 ===============
我试过mov bl var1
并生成了一个机器代码bl
.386
.MODEL FLAT, STDCALL
.STACK 4096
ExitProcess PROTO, dwExitCode: DWORD
.DATA
var1 BYTE 10h
.CODE
main PROC
MOV BL, var1
invoke ExitProcess, 0
main ENDP
END main
1> Johan - rein..:
作为一般规则,寄存器值是存在于机器指令.
然而,x86指令集中存在许多遗留的"包袱".
引入8086时,指令的长度会影响执行时间:更短的指令运行得更快.
的A
寄存器(AX/AL
)被称为"累加器"并且使用是在CPU中最通用寄存器.它具有特殊的短版本指令(以前)运行得更快(在原始的8086/8088上).在x86的后续迭代中,其他寄存器被升级为更通用的.现在你几乎可以使用任何寄存器用于所有目的.
您可以在x86操作码地图上清楚地看到这一点,请参阅:http://sparksandflames.com/files/x86InstructionChart.html
请注意,mov al,[absolute address]
有2个编码执行相同的操作:
A0和8A 05
0: a0 00 00 00 00 mov al,BYTE PTR ds:0x0
5: 8a 05 00 00 00 00 mov al,BYTE PTR ds:0x0
回想起来,这很浪费.但是当时使用累加器寄存器更快地制作指令似乎是个好主意.由于向后兼容,这些错误现在无法纠正.
有可能在新的X64指令集中消除这种重复,但AMD不想做太多改动,所以我们永远坚持这些历史文物.
2> Cody Gray..:
我的问题是,为什么机器指令中没有al
(或表示al
)A0 00010400
?
因为MOV
指令(0xA0
)的特殊编码始终将AL
寄存器作为其目标操作数.其余的代码字节专用于指定源操作数,在本例中是源操作数0x00010400
- var1
该.DATA
部分的地址.
你可以在这张表中看到.您还可以看到有其他特殊编码的指令,像0xA1
一个MOV
用AX
/ EAX
作为其目的地操作数,0xA2
对于一个版本MOV
,其操作数反转(例如,mov var1, al
).
这些替代编码存在的原因是在生成的机器代码中保存字节.正如Hans Passant评论的那样,在20世纪70年代中期到x86处理器构思和设计时,这种事情很重要.当时内存非常昂贵,总线速度要慢得多,因此节省空间非常重要 - 即使代价是使处理器的指令解码器更加复杂.鉴于8088上的非常小的(4字节)提取队列,使用这些特殊的单字节指令编码可以显着提高特定代码序列的速度.然而,现在,这个设计在40年后仍在使用,这是英特尔继续遭受的x86平台的一些传统包袱.现代x86芯片必须将不成比例的大部分硅专用于复杂的指令解码器,即使内存非常便宜,因为这些类型的优化并没有真正帮助任何人.
当其中一个操作数是累加器寄存器时,这些特殊编码不仅可用,而且这是特殊编码的最常见情况.
但是,通常情况下,指令使用操作码字节进行编码,然后是每个操作数的字节.这就是你所看到的mov bl, var1
.操作码mov reg8, r/m8
是0x8A
.接下来0x1D
将DL
寄存器指定为目标操作数.这里有一个方便的操作码表,或者您可以在英特尔的IA-32架构手册中找到每个单独指令的信息.这个网站非常有用,提供"备忘单"作为说明.你可以在Stack Overflow上的x86标签wiki中找到更多这样的链接.