每天进步一点点,不要浮躁,沉下心来。
什么是汇编语言
我们知道CPU是经过精心设计的电路组成的,里面有很多微小的门电路,门电路是通过输入电平控制的,电平分为高低,我们用1表示高电平,0表示低电平,所以让CPU工作就需要给它输入01序列。CPU是通用的,通过不同的01序列组合,它可以做不同的事情,编写01序列就是所谓的机器码编成,而机器码编程对程序员要求太高了,程序中出错也不好排查(比如01010111写错成了01000111),于是人们用符号来代替01序列,比如用 mov eax,0x1来表示b8 01 00 00 00指令(注意,在汇编中的数字通常都用十六进制表示,一个十六进制数字表示4个bit,表示范围从0到F,即十进制的0到15,这儿的b8 01 00 00 00如果写成二进制就是1011100000000001000000000000000000000000,很明显,二进制长度太长了,不易阅读)。
用符号表示机器码的编程语言就是汇编语言。
汇编语言的风格和种类
CPU的架构
既然汇编语言就是二进制0101的符号化表示,而0101又是CPU这种硬件电路的输入,那么不同的厂商生产的CPU的电路支持的输入又不一样,支持的01序列(指令集)也不同,那么每种CPU架构的上的汇编也是不同的。
常见的CPU架构有X86(16位和32位)、X86_64、ARM、MIPS、RISC-V等等。我们现在平常用的64位CPU(Intel和AMD生产的)都是X86_64架构的。
汇编风格
汇编语言(汇编语言不区分大小写)的书写风格有两种,一种是Intel风格,一种是AT&T风格。比如同样的一段汇编可以写成:
Intel风格的mov指令目的操作数在左边,源操作数在右边。
AT&T风格的mov指令目的操作数在右边,源操作数在左边,并且有大量的百分号。
我个人比较喜欢Intel风格,很多资料也推荐Intel风格。在反汇编二进制程序的时候,可以设置反汇编的风格,比如在gdb中,可以通过
set disassembly-flavor intel
或者set disassembly-flavor att
进行风格的切换:
(gdb) set disassembly-flavor intel
(gdb) disassemble/r main
Dump of assembler code for function main:
0x0000000000401110 <+0>: b8 01 00 00 00 mov eax,0x1
0x0000000000401115 <+5>: bf 01 00 00 00 mov edi,0x1
0x000000000040111a <+10>: 48 be 28 40 40 00 00 00 00 00 movabs rsi,0x404028
0x0000000000401124 <+20>: ba 0c 00 00 00 mov edx,0xc
0x0000000000401129 <+25>: 0f 05 syscall
0x000000000040112b <+27>: b8 3c 00 00 00 mov eax,0x3c
0x0000000000401130 <+32>: bf 00 00 00 00 mov edi,0x0
0x0000000000401135 <+37>: 0f 05 syscall
0x0000000000401137 <+39>: 66 0f 1f 84 00 00 00 00 00 nop WORD PTR [rax+rax*1+0x0]
End of assembler dump.
(gdb) set disassembly-flavor att
(gdb) disassemble/r main
Dump of assembler code for function main:
0x0000000000401110 <+0>: b8 01 00 00 00 mov $0x1,%eax
0x0000000000401115 <+5>: bf 01 00 00 00 mov $0x1,%edi
0x000000000040111a <+10>: 48 be 28 40 40 00 00 00 00 00 movabs $0x404028,%rsi
0x0000000000401124 <+20>: ba 0c 00 00 00 mov $0xc,%edx
0x0000000000401129 <+25>: 0f 05 syscall
0x000000000040112b <+27>: b8 3c 00 00 00 mov $0x3c,%eax
0x0000000000401130 <+32>: bf 00 00 00 00 mov $0x0,%edi
0x0000000000401135 <+37>: 0f 05 syscall
0x0000000000401137 <+39>: 66 0f 1f 84 00 00 00 00 00 nopw 0x0(%rax,%rax,1)
End of assembler dump.
(gdb)
X86汇编(X86_64汇编)
平时说的x86汇编,在以前主要指16位和32位的。现在64位CPU很普遍了,64位的x86叫x86_64或x_64。
64位CPU的寄存器
学习汇编的常用工具
汇编器
将汇编语言文本翻译成0101序列的工具叫做汇编器(高级语言中有所谓的编译器将高级语言文本编译成机器码或者汇编代码)。
常见的汇编器有NASM(Netwide Assembler)、MASM(Microsoft Macro Assembler)、GAS(GNU Assembler)等,推荐用NASM,各个操作系统都可以用,免费的。
调试器
GDB(LLDB),可以调试C、C++语言等语言,可以通过反汇编机器码看到汇编程序与C、C++语言的对应关系。
通过GDB调试C程序,查看其汇编可以搞清楚很多底层本质,比如函数的调用参数是怎么传递的,等等。