Assembly 一个操作码字节如何根据;寄存器/操作码“;领域那是什么?
如何确定字节数组将在机器代码中转换成什么 我知道如果我在开始时看到0f,它是一条2字节指令,但我看到了其他前缀,在x64调试器的一些反汇编中,我看到了奇怪的交互,如48 83 C4 38,我可以在操作码引用中看到48表示操作数是64字节 但是Assembly 一个操作码字节如何根据;寄存器/操作码“;领域那是什么?,assembly,x86-64,disassembly,machine-code,Assembly,X86 64,Disassembly,Machine Code,如何确定字节数组将在机器代码中转换成什么 我知道如果我在开始时看到0f,它是一条2字节指令,但我看到了其他前缀,在x64调试器的一些反汇编中,我看到了奇怪的交互,如48 83 C4 38,我可以在操作码引用中看到48表示操作数是64字节 但是83说根据名为“寄存器/操作码字段”的字段,它可以是7条不同的指令。什么? 有人能解释一下处理器如何使用这些字节来确定: 运行什么指令 指令使用的寄存器和/或地址(如果有) 这取决于特定的体系结构,不仅仅是x86-64,还取决于实际的芯片供应商。例如,您可以
83
说根据名为“寄存器/操作码字段”的字段,它可以是7条不同的指令。什么?
有人能解释一下处理器如何使用这些字节来确定:
这取决于特定的体系结构,不仅仅是x86-64,还取决于实际的芯片供应商。例如,您可以检查 这有一整章专门讨论字节码中命令的语法,然后是每个可用命令的另一章。图2.1为您提供了一个想法: 摘自上述手册。例如,如果您使用ARM,这将发生变化
人们可能需要多年的时间才能“流利地阅读”字节码,因此略读一下这一点只能让您大致了解语法或查找特定内容的良好资源。这取决于特定的体系结构,不仅仅是x86-64,还取决于实际的芯片供应商。例如,您可以检查 这有一整章专门讨论字节码中命令的语法,然后是每个可用命令的另一章。图2.1为您提供了一个想法: 摘自上述手册。例如,如果您使用ARM,这将发生变化
人们可能需要多年的时间才能“流利地阅读”字节码,因此略读一下这一点只能让您大致了解语法或查找特定对象的良好资源。
0x48
是REX前缀,W字段设置为1,意味着64位操作数大小。
(不是64字节)
许多指令即时版本的操作码,包括83
,使用ModR/M字节中的3位/r
字段作为3个额外的操作码位。英特尔的第二卷手册记录了这一点,我认为附录中的操作码表包括了这一点
这就是为什么大多数原始8086立即数指令,如和r/m,imm
仍然只允许2个操作数,这与shrd eax、edx、4
或imul edx、[rdi],12345
不同,其中两个ModRM字段都用于对操作数以及操作码隐含的立即数进行编码。SHRD/SHLD和添加386和imul立即。可能不幸的是,copy and and(和eax,edx,0xf
)不可编码,但至少x86可以使用LEA进行复制和添加/sub
每个指令都有自己的文档,例如显示编码,如
REX.W+83/0 ib
对于添加r/m64,imm8
,这就是您所拥有的
0xc4=0B11000000,因此reg字段=0。因此,我们的操作码是用英特尔的符号表示的83/0
。
其余的ModRM字段为:
- mode=0b11,因此rm字段编码的是寄存器操作数,而不是寻址模式的基址寄存器
- rm=0b100。reg#4=SPL/SP/ESP/RSP。(在本例中是RSP,因为它是64位操作数大小)。请参阅英特尔手册或表格
ndisam-b64
同意:
$ cat > foo.asm
db 0x48, 0x83, 0xC4, 0x38
$ nasm foo.asm # create a flat binary with those bytes, not an object file
$ ndisasm -b64 foo
00000000 4883C438 add rsp,byte +0x38
0x48
是REX前缀,W字段设置为1,表示64位操作数大小。
(不是64字节)
许多指令即时版本的操作码,包括83
,使用ModR/M字节中的3位/r
字段作为3个额外的操作码位。英特尔的第二卷手册记录了这一点,我认为附录中的操作码表包括了这一点
这就是为什么大多数原始8086立即数指令,如和r/m,imm
仍然只允许2个操作数,这与shrd eax、edx、4
或imul edx、[rdi],12345
不同,其中两个ModRM字段都用于对操作数以及操作码隐含的立即数进行编码。SHRD/SHLD和添加386和imul立即。可能不幸的是,copy and and(和eax,edx,0xf
)不可编码,但至少x86可以使用LEA进行复制和添加/sub
每个指令都有自己的文档,例如显示编码,如
REX.W+83/0 ib
对于添加r/m64,imm8
,这就是您所拥有的
0xc4=0B11000000,因此reg字段=0。因此,我们的操作码是用英特尔的符号表示的83/0
。
其余的ModRM字段为:
- mode=0b11,因此rm字段编码的是寄存器操作数,而不是寻址模式的基址寄存器
- rm=0b100。reg#4=SPL/SP/ESP/RSP。(在本例中是RSP,因为它是64位操作数大小)。请参阅英特尔手册或表格
ndisam-b64
同意:
$ cat > foo.asm
db 0x48, 0x83, 0xC4, 0x38
$ nasm foo.asm # create a flat binary with those bytes, not an object file
$ ndisasm -b64 foo
00000000 4883C438 add rsp,byte +0x38
我在一页上看到字母a,这可能是许多不同的单词,后面的字母是n。这可能是一个,答案,任何字数,所以我继续 x86和那个时代的其他机器代码就是这样工作的,特别是它直接派生的指令集 首先,也是最重要的一点,如果你只是把一个程序的所有字节都放在中间,这是没有任何意义的,很容易出错“快速棕色狐狸”“快速棕色信息”“ickbrow”这是什么?处理器根据指令集的规则启动和继续,处理器相当愚蠢,因为它遵循处理器手册中定义或至少记录的规则。只要
mov eax,0x12345678
mov ebx,0x12345678
mov ecx,0x12345678
mov edx,0x12345678
Disassembly of section .text:
00000000 <.text>:
0: b8 78 56 34 12 mov eax,0x12345678
5: bb 78 56 34 12 mov ebx,0x12345678
a: b9 78 56 34 12 mov ecx,0x12345678
f: ba 78 56 34 12 mov edx,0x12345678
mov eax,eax
mov eax,ebx
mov eax,ecx
mov eax,edx
0: 89 c0 mov eax,eax
2: 89 d8 mov eax,ebx
4: 89 c8 mov eax,ecx
6: 89 d0 mov eax,edx
a = 0
if(a == 0) goto somewhere
b = 7
1 a = 0;
2
1 if(a == 0) goto somewhere
2
3
1 b = 7.
2
3
1
2
3
1 b = 7.
2
3 <--- is a branch destination
1
2
3