我有一个code.c文件,其中目标代码文件为code.o是具有十六进制表示形式的多字节序列:
55 89 e5 8b 45 0c 03 45 08 01 05 00 00 00 00 5d c3
CPU如何对要执行的字节分组?例如,我们预先知道55对应于push,89和e5对应于mov,但是某些指令包含三个字节或更多字节,那么CPU如何知道'55 89 e5'是两个指令而不是一个指令? >
答案 0 :(得分:3)
部分CPU是指令解码器(例如,参见Central Processing Unit上的Wikipedia文章)。指令解码器的任务是确定从指令指针指向的地址开始,有多少字节是当前指令的一部分,并将其解码成其组成部分。
在某些架构(当今大多数是微控制器)中,所有指令的大小均相同。在64位Intel / AMD架构(x86-64 a.k.a. AMD64)上,指令大小在1到15个字节之间变化,并且指令编码相当complex。
答案 1 :(得分:2)
特别是在x86上,指令编码是这样的,解码器可以从每个字节中了解到后面还有多少个字节。
例如,让我向您展示解码器如何解码此指令流。
55
解码器看到55
并知道这是push ebp
(单字节指令)。因此它将解码push ebp
并转到下一条指令。
push ebp
89
解码器看到89
,即mov r/m32,r32
。该指令后跟一个 modr / m字节,用于指定操作数。
push ebp
89 e5
modr / m字节为e5
,指示ebp
为r / m操作数,esp
为r操作数,因此指令为mov ebp, esp
。
push ebp
mov ebp, esp
8b
此指令为mov r32,r/m32
,后跟一个modr / m字节。
push ebp
mov ebp, esp
8b 45
此modr / m字节的r操作数为eax
,r / m32操作数为[ebp + disp8]
,位移为8位,随下一个字节一起出现
push ebp
mov ebp, esp
8b 45 0c
位移为0c
,所以指令为mov eax, [ebp + 0xc]
push ebp
mov ebp, esp
mov eax, [ebp + 0xc]
03
此指令再次为add r,r/m32
,后跟一个modr / m字节。
push ebp
mov ebp, esp
mov eax, [ebp + 0x0c]
03 45
与以前相同,r操作数为eax
,而r / m操作数为[ebp + disp8]
。位移为08
。
push ebp
mov ebp, esp
mov eax, [ebp + 0x0c]
add eax, [ebp + 0x08]
01
此指令为add r/m32, r
,后跟一个modr / m字节。
push ebp
mov ebp, esp
mov eax, [ebp + 0x0c]
add eax, [ebp + 0x08]
01 05
此modr / m字节指示r操作数为eax
和r / m操作数为[disp32]
。位移紧随其后的四个字节为00 00 00 00
。
push ebp
mov ebp, esp
mov eax, [ebp + 0x0c]
add eax, [ebp + 0x08]
add [0x00000000], eax
5d
指令5d
是pop ebp
,单字节指令。
push ebp
mov ebp, esp
mov eax, [ebp + 0x0c]
add eax, [ebp + 0x08]
add [0x00000000], eax
pop ebp
c3
指令c3
是ret
,单字节指令。该指令将控制权转移到其他地方,因此解码器从此处停止解码。
push ebp
mov ebp, esp
mov eax, [ebp + 0x0c]
add eax, [ebp + 0x08]
add [0x00000000], eax
pop ebp
ret
在实际的x86处理器中,采用了复杂的并行解码技术。这是可能的,因为处理器可能会欺骗并预读可能是也可能不是任何指令一部分的指令字节。