什么是机器级表示?
计算机执行机器代码,用字节序列编码低级的操作,包括处理数据、管理内存、读写存储设备上的数据,以及利用网络通信。编译器基于编程语言的规则、目标机器的指令集和操作系统遵循的惯例,经过系列的阶段生成机器代码。GCC C语言编译器以汇编代码的形式产生输出,汇编代码是机器代码的文本表示,给出程序中的每一条指令。然后GCC调用汇编器和链接器,根据汇编代码生成可执行的机器代码。在本章中,我们会近距离地观察机器代码,以及人类可读的表示——汇编代码。
当我们用高级语言编程的时候(例如C语言,Java语言更是如此),机器屏蔽了程序的细节,即机器级的实现。与此相反,当用汇编代码编程的时候(就像早期的计算),程序员必须指定程序用来执行计算的低级指令。高级语言提供的抽象级别比较高,大多数时候,在这种抽象级别上工作效率会更高,也更可靠。编译器提供的类型检查能帮助我们发现许多程序错误,并能够保证按照致的方式 来引用和处理数据。 通常情况下,使用现代的优化编译器产生的代码至少与一个熟练的汇编语言程序员手工编写的代码一样有效。最大的优点是,用高级语言编写的程序可以在很多不同的机器上编译和执行,而汇编代码则是与特定机器密切相关的。
为什么要学习机器代码?
即使编译器承担了生成汇编代码的大部分工作,对于严谨的程序员来说,能够阅读和理解汇编代码仍是一项很重要的技能。以适当的命令行选项调用编译器,编译器就会产生一个以汇编代码形式表示的输出文件。通过阅读这些汇编代码,我们能够理解编译器的优化能力,并分析代码中隐含的效率。
此外,也有些时候,高级语言提供的抽象层会隐藏我们想要了解的程序的运行时行为。例如,用线程包写并发程序时,了解不同的线程是如何共享程序数据或保持数据私有的,以及准确知道如何在哪里访问共享数据,都是很重要的。这些信息在机器代码级是可见的。另外再举一个例子, 程序遭受攻击(使得恶意软件侵扰系统)的许多方式中,都涉及程序存储运行时控制信息的方式的细节。许多攻击利用了系统程序中的漏洞重写信息,从而获得了系统的控制权。了解这些漏洞是如何出现的,以及如何防御它们,需要具备程序机器级表示的知识。程序员学习汇编代码的需求随着时间的推移也发生了变化,开始时要求程序员能直接用汇编语言编写程序,现在则要求他们能够阅读和理解编译器产生的代码。