什么是汇编
汇编(Assembly Language)是针对特定处理器架构得一种低级语言。它使用的是人易于识记的符号来代表机器指令,即机器码(Opcode),以及内存的相对地址。机器码和每一条汇编的指令是可以一一对应的,但在其他高级语言中却不一定可以。在执行一个二进制文件时,计算机真正做的是按周期执行的是一个个机器指令。
汇编可以直接对各种硬件部件操作,但是实现的代价十分高昂。汇编可以说是比机器码编程仅仅高一级。每一条指令执行一个简单的操作(当然现在是有指令可以一条搞定两个浮点数的乘法的,但大部分广泛使用的指令操作却并不复杂),结果是你哪怕向实现一个简单的功能都可能动辄上千条指令。而且相比于其他语言而言汇编基本上就是结构化编程的反面例子,各种流程用的是跳转实现。
为什么是汇编
或者说为什么学汇编?汇编有什么用?我的回答是:汇编的确没有什么用,但是学习的目的是源于提问者自身。
在今天,任何一种高级语言都可以比汇编更容易上手,更容易编写,更容易移植,汇编可以说是一门已经过气的语言,实用价值并不高。但是在实际情况下,你还是会不经意地碰到它:
- 参加CTF,拿到逆向的题之后发现要人肉反编译算法,你只能阅读汇编分析
(当然一上来就开IDA按F5的或者直接一把梭的当我没有说)
- 某天在调试一个编译器优化后的程序出现了玄学问题,例如打不上断点,或者执行结果有误,这时你要在在汇编级别的代码调试排除问题(这时确实可以关掉优化,但这不是一劳永逸的)
- 在Github上阅读代码时,发现编写者为了优化运行速度或者实现硬件功能而采用了内联汇编或者完全汇编的代码。实际上,Linux Kernel的源码中有一部分是内联汇编
- ……
为了达成其他目的而学习汇编,像极了学习数学的过程。虽然说我们日常应用中汇编编程的机会微乎其微,但是学习的过程会让你对某些计算机相关的内容有更深的理解。比如说你可以回答上来堆栈是什么?它是怎么运作的?x86中的保护模式和实模式是什么?在底层的角度上看函数调用的过程是怎样的?在解决“计算机中的XX究竟是如何运行”这类问题中,汇编或许能给你很多详细的非纯硬件层面的解答。
怎么学汇编
这个问题严格上说挺空泛的。这就像有个人跑过来问你:我应该怎么学编程?你可能不知道怎么回答或者给他贴个C语言的教程就算了。汇编也有很多种,跟CPU架构直接相关,前面已经说过了。可以是Intel的IA-32指令集(或者说x86指令集),ARM的Thumb-2,还有可能在你家路由器上跑的MIPS指令集等。其中x86作为目前PC主流的架构我们一般非常容易接触,所以我们一般讨论学汇编的时候都是针对x86。如果说是要对各种CPU底层有个基本印象的话,其余两种可以跳过,除非你以后打算做嵌入式天天和ARM的处理器打交道的工作。
首先要知道指令集和执行环境里面有什么,这个课本上应有,纯工具性内容可以直接查得到
其次是运作原理,这些指令做了什么?它们是如何相互作用的?
还有这些指令中对事件的处理机制(中断、异常)是怎样的?
如果说想系统性学习汇编的,可以看看这本《汇编语言:基于x86处理器》,不过是以Windows下的MASM为基础的,对Linux用户不太友好
如果说其他网上的资料太零散的话可以试试看这本书 Intel® 64 and IA-32 Architectures Software Developer’s Manual,Intel官方的编程手册,不过是全英文版的。本来是一本用来随时查阅的工具书,但前面几章其中有对32位和64位CPU指令和执行环境详尽的描述,前面讲环境的内容很全,耐心看完它应该上手阅读汇编不难
如果你想看看一些Linux汇编的代码的话,可以试着用把你自己曾经写过的C代码用gcc汇编:gcc -S test.c
,看看编译器给出的汇编是什么样的。你还可以调用一些函数或者加入一些控制语句,观察编译器是怎么处理。这也不妨为一种原始的学习方式。另外,如果你还懂一些gdb的调试方法的话,你还可以把你自己写的代码切换到反汇编,然后单步执行观察堆栈和寄存器的变化情况,加深一下印象。如果是在Windows下的话可以用MinGW来引入gcc和gdb
最后,祝你在学汇编的路上找到那种对原来知识深入理解后“恍然大悟”的乐趣😆