ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

《计算机是如何工作的:人人都能懂的计算机软硬件工作原理》第 8 章 机器码与汇编语言 阅读笔记 8

《计算机是如何工作的:人人都能懂的计算机软硬件工作原理》第 8 章 机器码与汇编语言 阅读笔记 8 《计算机是如何工作的人人都能懂的计算机软硬件工作原理》第 8 章 机器码与汇编语言 阅读笔记 8我们已经介绍了计算机的物理部分内存、CPU和 I/O 设备。理解计算机的硬件部分很重要但是硬件只起一半作用。计算机的魔力在于软件。软件把计算机从固定用途的设备变成了高度灵活的设备它能轻松地实现新的功能本章将介绍底层软件——机器码和汇编语言。我发现交互方法是理解这些主题的最好方法所以本章的大部分内容都体现在设计中。8.1 软件术语要讨论软件需要首先介绍一些术语。告诉计算机做什么的指令被称为 “软件”​这与硬件形成了对比硬件是计算机的物理元素。完成任务的一组有序的软件指令被称为 “程序”​编程就是编写这种程序的行为。术语 “应用程序” 有时被用作程序的同义词尽管应用程序往往指的是直接与人进行交互的程序而不是与软件或硬件交互的程序。应用程序也可能由多个程序构成。app 这个词大约在 2008 年开始流行其中含有的其他意思将在第 13 章中介绍。另一个指代一组软件指令的名称是 “计算机代码” 或 “代码”​。CPU 执行 “机器码”​而软件开发人员一般用高级编程语言编写源代码。术语 “源代码” 是指由开发人员最初编写的程序文本。这种代码一般不会用 CPU 能直接理解的形式来编写因此在其能被计算机运行之前还需要进行其他处理。我将在第 9 章详细介绍源代码和高级编程语言但是现在我们先来看看软件的基础机器码。机器码是二进制机器语言指令形式的软件。如第 7 章所述CPU 的架构决定了 CPU 能理解的指令。就像人类语言是用词汇表构成的一样机器语言是用 CPU 系列已知的指令列表构成的。词汇表中的词语排列成句子来表达含义CPU 指令排列成程序后也具有相同功能。不管程序最初是如何编写的编写程序的方法有很多种​它最终都需要在 CPU 上作为一系列机器语言指令来执行。正如你所期望的CPU 指令可以归结为一系列 0 和 1就像计算机处理的所有其他事情一样。这里值得重复一下不论程序最初是如何编写的也不论用的是哪种编程语言更不论使用的是什么技术最后程序都会变成一系列的 0 和 1表示 CPU 可以执行的指令。几年前我有一项工作是关于诊断软件故障的。通常我要分析发生在其他公司编写的软件中的问题。我没有这类软件的源代码也没有很多关于它应如何工作的相关信息但是我的工作就是确定软件故障的原因我有个同事对此很淡然他常常提醒我 “这就是个代码”​。换句话说故障软件就是一组被 CPU 解释为指令的 1 和 0。如果 CPU 可以理解代码那么你也可以。8.2 机器指令示例我认为切入机器码主题的最简单方法就是看示例。我们来看看 ARM 系列处理器能理解的特定机器指令。你可能还记得大多数智能手机上都能发现 ARM 处理器所以你的手机可能也可以理解这条指令。我们的示例指令告诉处理器把数字 4 移动到寄存器 r7 中r7 是 ARM 处理器通用寄存器中的一个。回忆一下我们之前讨论的计算机硬件寄存器是 CPU 中的一种小容量存储位置。执行这个操作的 ARM 指令的二进制形式如下我们来看看 ARM CPU 是如何理解这条指令的如图 8-1 所示。注意我们跳过了无关的一些位。图 8-1 ARM 指令条件部分指示了在什么条件下该指令应该执行。1110 意味着这条指令是无条件执行的所以 CPU 应该总是执行它。虽然本例中不是这样的但是有些指令只需要在特定条件下执行。接下来的两位本例中为 00与我们的讨论无关所以跳过它们。立即数位告诉我们将要访问的是寄存器中的值还是指令本身指定的值称为立即数​。本例中立即数位为 1要访问的是指令中指定的数。如果立即数位是 0那么被访问寄存器将由指令中的其他位来指定。操作码表示 CPU 要执行的操作。本例中操作码是 mov意思是 CPU 要移动数据。目标寄存器 0111 告诉我们把值移动到寄存器 r70111 是十进制的 7中。最后立即数值 00000100 是十进制的 4这是我们想要移动到 r7 中的数。简单概括一下这个二进制序列告诉 ARM CPU 把数字 4 移动到 r7 寄存器中。CPU 总是用二进制处理各种事情但是绝大多数人很难处理这些 0 和 1。现在我们用十六进制表示同样的指令以便让它更容易读懂现在是不是好点啦好吧也许不是。这种格式比二进制格式更加紧凑也更容易区分但它的含义仍然不明显。对我们而言幸运的是还有另一种方法来表示这条指令汇编语言。汇编语言是一种编程语言它的每一条语句都直接表示一条机器语言指令。每种类型的机器语言都有对应的汇编语言—如 x86 汇编语言、ARM 汇编语言等。汇编语言语句由一个表示 CPU 操作码的助记符和其他必需的操作码比如寄存器或数值组成。助记符是人类可读的操作码形式它允许汇编语言程序员在代码中用 mov 而不是 1101。之前讨论过的相同的 ARM 指令也可以用如下汇编语言语句表示与相应的二进制和十六进制表示相比这个语句当然是表示 “把 4 移动到 r7 寄存器中的” 更好的方式最起码对人类来说更容易阅读。也就是说汇编语言语句只是为了人类方便。CPU 从不会执行文本格式的指令它只处理二进制格式的指令。如果程序员用汇编语言编写程序那么在计算机执行该程序之前汇编指令仍然必须转换成机器码。这要用 “汇编器” 来完成汇编器是一种把汇编语言语句转换成机器码的程序。汇编语言文本文件被送入汇编器汇编器输出的就是包含机器码的二进制目标文件如图 8-2 所示。图 8-2 汇编器把汇编语言转换成机器码8.3 用机器码计算阶乘现在我们已经查看了单条 ARM 指令接下来我们看看如何把多条指令组合在一起来执行有用的任务。我们来看一个计算整数阶乘的 ARM 机器码。你可能还记得在数学课上学过n 的阶乘写作 n!是小于或等于 n 的正整数的乘积。例如4 的阶乘为4!4×3×2×124现在我们已经有了阶乘的定义让我们来看看用 ARM 机器码如何实现阶乘算法。为了简单起见我们不查看完整的程序代码只看执行阶乘算法的部分。我们假设 n 的初始值保存在寄存器 r0 中并且当代码完成时计算结果也保存在 r0 中。如同计算机处理的任何其他数据一样在 CPU 访问机器码之前必须把它加载到内存中。下面的是机器码的 32 位4 字节十六进制表示以及每个值的内存地址。当我们的代码加载到内存时阶乘逻辑从地址 0001007c 开始。来看看从这个地址开始的内存内容。请注意0001007c 不是一个神奇的地址它只是恰好是本例中代码加载的地方。还要注意内存地址值增幅为 4因为每个数据值都需要 4 个字节来存放。每条 ARM 指令长度都为 4 字节所以这里的数据表示 5 条 ARM 指令。把这些指令看作十六进制的值并不能让我们深入理解它们的含义所以让我们对这些指令进行译码以便理解这个程序。在下面的清单中我已经把十六进制的数值转换成相应的汇编语言助记符。如果你好奇的话把机器语言手动翻译成汇编语言不是你需要了解的我们有完成这项功能的软件称为 “反汇编器”​。现在这本书就充当了你的反汇编器。下面列出了每条指令以及与之配对的汇编语句CPU 按顺序执行这些指令直到遇到分支指令比如 ble 或 bne​分支指令会让它跳转到程序的另一个部分。地址 00010090 标记着阶乘逻辑的结束。一旦到达这个地址阶乘运算结果就已经保存到 r0 了。此时CPU 执行位于地址 00010090 处的指令。你可能好奇这些指令是如何表示阶乘的计算的。对大多数人来说粗略地看一下这些指令不足以理解其所含的意思。采取循序渐进的方式在每条指令执行时跟踪寄存器的值能帮助你理解这个程序。我将给你提供一些必需的背景资料然后你可以尝试评估这个程序是如何工作的。为了理解这个程序你首先需要对每条指令的说明。在表 8-1 中我已经给出了这个程序中每条指令的解释。在这个表中我使用了寄存器的占位符名称比如 Rd 和 Rn。当你查看汇编代码时你将看到实际使用的寄存器名称比如 r0 和 r3。代码中列出的操作数顺序对应于表 8-1 中的操作数顺序。例如subs r3r0#1 表示从存储在 r0 中的值中减去 1并把结果存放到 r3 中。表 8-1 一些 ARM 指令的解释分支和状态寄存器分支指令实际并不查看前一条指令的数值结果。和大多数 CPU 一样ARM 处理器也有一个寄存器专门跟踪状态。这个状态寄存器有 32 位每个位对应一个特定的状态标志。例如位 31 是 N 标志当指令结果为负数时该标志置 1。只有某些指令会影响这些标志状态。例如subs 指令会改变标志的状态。如果某个减法运算结果是负的那么 N 标志会置 1否则它会清零。其他指令包括分支指令则查看状态标志位来决定该做什么。这看上去是一种迂回的方式但实际上它简化了像 bne 这样的指令——处理器可以根据单个位的值进行分支或不进行分支​。8.4 总结本章讨论了机器码即特定于 CPU 的一系列指令它们在内存中以字节表示。你学习了如何对示例 ARM 处理器指令进行编码以及如何用汇编语言表示该指令。你了解到汇编语言是一种源代码尤其是人类可读形式的机器码。我们还了解了怎样组合多条汇编语言语句来执行有用的操作。第 9 章将讨论高级编程语言。这种语言提供了CPU 指令集的抽象允许开发人员编写更容易理解且可以在不同计算机硬件平台之间移植的源代码。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表