汇编语言:基于x86处理器-学习笔记-第一二章
第一、二章学习笔记
汇编语言基本概念
1. 汇编语言可移植吗?
《汇编语言:基于x86处理器(原书第7版)》Page 3
一种语言,如果它的源程序能够在各种各样的计算机系统中进行编译和运行,那么这种语言被称为是可移植的 (portable)。
例如,一个C++程序,除非需要特别引用某种操作系统的库函数,否则它就几乎可以在任何一台计算机上编译和运行。Java语言的一大特点就是,其编译好的程序几乎能在所有计算机系统中运行。
汇编语言不是可移植的,因为它是为特定处理器系列设计的。 目前广泛使用的有多种不同的汇编语言,每一种都基于一个处理器系列。对于一些广为人知的处理器系列如 Motorola68x00
、x86
、SUN Sparc
、Vax
和 IBM-370
,汇编语言指令会直接与该计算机体系结构相匹配,或者在执行时用一种被称为微代码解释器 (microcode interpreter) 的处理器内置程序来进行转换。
2. 汇编语言与机器语言有什么关系?
《汇编语言:基于x86处理器(原书第7版)》Page 3
机器语言 (machine language) 是一种数字语言,专门设计成能被计算机处理器(CPU)理解。所有 x86
处理器都理解共同的机器语言。汇编语言 (assembly language) 包含用短助记符如 ADD
、MOV
、SUB
和 CALL
书写的语句。
汇编语言与机器语言是一对一 (one-to-one) 的关系:每一条汇编语言指令对应一条机器语言指令。
3. C++ 和 Java 与汇编语言有什么关系?
《汇编语言:基于x86处理器(原书第7版)》Page 3
高级语言如 Python
、C++
和 Java
与汇编语言和机器语言的关系是一对多 (one-to-many)。
比如,C++
的一条语句就会扩展为多条汇编指令或机器指令。这种转换需要多条语句,因为每条汇编语句只对应一条机器指令。
4. 汇编语言有规则吗?
《汇编语言:基于x86处理器(原书第7版)》Page 4
大多数汇编语言规则都是以目标处理器及其机器语言的物理局限性为基础的。 比如,CPU要求两个指令操作数的大小相同。
与 C++ 或 Java 相比,汇编语言的规则较少,因为,前者是用语法规则来减少意外的逻辑错误,而这是以限制底层数据访问为代价的。反之,汇编语言可以访问所有的内存地址。
5. 为什么高级语言这么发达还会用汇编语言?
《汇编语言:基于x86处理器(原书第7版)》Page 3
嵌入式程序是指一些存放在专用设备中小容量存储器内的短程序。高级语言可能生成很大的可执行文件,以至于超出设备的内存容量。由于汇编语言占用内存少,因此它是编写嵌入式程序的理想工具。
处理仿真和硬件监控的实时应用程序要求精确定时和响应。高级语言不会让程序员对编译器生成的机器代码进行精确控制。汇编语言则允许程序员精确指定程序的可执行代码。
电脑游戏要求软件在减少代码大小和加快执行速度方面进行高度优化。游戏程序员经常选择汇编语言作为工具,因为汇编语言允许直接访问计算机硬件,所以,为了提高速度可以对代码进行手工优化。
6. 汇编语言与高级语言的比较
《汇编语言:基于x86处理器(原书第7版)》Page 4
应用类型 | 高级语言 | 汇编语言 |
---|---|---|
商业或科学应用程序,为单一的中型或大型平台编写 | 规范结构使其易于组织和维护大量代码 | 最小规范结构,因此必须由具有不同程度经验的程序员来维护结构。这导致对已有代码的维护困难 |
硬件设备驱动程序 | 语言不一定提供对硬件的直接访问。即使提供了,可能也需要难以控制的编码技术,这导致维护困难 | 对硬件的访问直接且简单。当程序较短且文档良好时易于维护 |
为多个平台(不同的操作系统)编写的商业或科学应用程序 | 通常可移植。在每个目标操作系统上,源程序只做少量修改就能重新编译 | 需要为每个平台单独重新编写代码,每个汇编器都使用不同的语法。维护困难 |
需要直接访问硬件的嵌入式系统和电脑游戏 | 可能生成很大的可执行文件,以至于超出设备的内存容量 | 理想,因为可执行代码小,运行速度快 |
习题整理
(机器语言)是一种数字语言,专门设计成能被计算机处理器理解。
(汇编语言)是包含用短助记符如ADD
、MOV
和CALL
书写的语句,两者是(一对一)的关系。
(高级语言)如Python
、C++
等与汇编语言的是(一对多)的关系。
参考上文整理内容。
数据表示
整数存储大小
《汇编语言:基于x86处理器(原书第7版)》Page 9
在 x86
计算机中,所有数据存储的基本单位都是字节 (byte
),一个字节有8位。
其他的存储单位还有:
- 字 (
word
,2个字节) - 双字 (
doubleword
,4个字节) - 四字 (
quadword
,8个字节)
补码
《汇编语言:基于x86处理器(原书第7版)》Page 12
负整数使用补码表示。
将一个二进制整数按位取反(求补)再加 1,就形成了它的补码。将一个十六进制整数按位取反并加1,就生成了该十六进制整数的补码。
补码操作是可逆的。 以 8 位二进制数 $0000 \space 0001$ 为例,其补码为 $1111 \space 1111$ 。同时,$1111 \space 1111$ 的补码也为 $0000 \space 0001$。
习题整理
对于下列8位有符号数来说,哪个值最大?(A)
A. 81
B. 0010 1100
C. F5H
D. 1101 0110
A 为十进制数,值为 81;
B 为二进值数,值为 44;
C 为十六进制数,转换成二进值后为 $1111 \space 0101$,所以值为 -11;
D 为二进值数,值为 -42。
综上可得,A 的值最大
A. 将16位十六进制数 55AAH 转化为二进制数的值为($0101\space 0101\space 1010\space 1010$);
B. 将16位二进制数1100 1011 1001 0111B 转化为十六进制数的值为($CB97$);
C. 有符号十进制整数-46的8位二进制补码是($1101\space 0010$);
D. 十六进制整数A598 + 32A7=($D83F$)
A 易得 $0101\space 0101\space 1010\space 1010$;
B 易得 $CB97$;
C 将 $46D = 0010\space 1110B$,对 $0010\space 1110B$ 进行取反操作后 $+ 1$,可以到最终结果为 $1101\space 0010$;
D 通过 16 进制加法,可以计算出结果为 $D83F$。
A. 将16位十六进制数AAF0H 转化为二进制数的值为(1010 1010 1111 0000);
B. 将16位二进制数1011 1101 0110 1001B 转化为十六进制数的值为(BD69);
C. 有符号十进制整数-98的8位二进制补码是(1001 1110);
D. 十六进制整数3A7+32F6=(369D)
解析无
字长为8位的无符号数,其数值范围为(0)到(255)
数值范围为 $2^0 \sim (2^8-1)$,即 0 ~ 255。
将16位十六进制数6A8DH 转化为二进制数的值为(0110 1010 1000 1101);
将16位二进制数1010 0001 1110 1011B 转化为十六进制数的值为(A1EB);
有符号十进制整数-100的8位二进制补码是(1001 1100);
十六进制整数068A+7D08=(8392)。
解析无
将16位十六进制数7DF6H 转化为二进制数的值为(0111 1101 1111 0110);
将16位二进制数1110 1101 0111 1000B 转化为十六进制数的值为(ED78);
有符号十进制整数-89的8位二进制补码是(1010 0111);
十六进制整数0F3D+A256=(B193)。
解析无
将16位十六进制数8A5DH 转化为二进制数的值为(1000 1010 0101 1101);
将16位二进制数1010 0101 0110 1100B 转化为十六进制数的值为(A56C);
有符号十进制整数-98的8位二进制补码是(1001 1110);
十六进制整数753A+32F6=(A830)。
解析无
在8位二进制数01101011中,最高有效位(MSB)的值是(0),最低有效位(LSB)的值是(1)。
参考资料:LSB最低有效位和MSB最高有效位_聚优致成的博客-CSDN博客_最低有效位
最低有效位是指一个二进制数字中的即最低位,具有权值为 $2^0$,可以用它来检测数的奇偶性。在大端序中,LSB
指最右边的位。
最高有效位是指一个n位二进制数字中的最高位,具有最高的权值为 $2^n - 1$。在大端序中,MSB
即指最左端的位。对于有符号二进制数,负数采用反码或补码形式,此时 MSB
用来表示符号,MSB
为 1 表示负数,为 0 表示正数。
对于下列8位有符号数来说,最小的是:(D)
A. 0
B. 00101100B
C. 75H
D. 11010110B
A B C 都为正数。而 D 的符号位为 1,表示负数。
负数在内存里是以其哪种形式存放?(C)
A. 原码
B. 反码
C. 补码
D. 真值
参考上文整理内容。
对于下列8位有符号数来说,哪个值最大?(B)
A. FFH
B. 48H
C. 70
D. 11010110
A :-1;B:72;C:70;D:-42。
x86 处理器架构
基本微机设计
《汇编语言:基于x86处理器(原书第7版)》Page 23
上图给出了假想机的基本设计。
中央处理单元 (
CPU
) 是进行算术和逻辑操作的部件,包含了:- 寄存器 (register)
有限数量的存储位置。 - 一个高频时钟
时钟 (clock) 对CPU
内部操作与系统其他组件进行同步。 - 一个控制单元
控制单元 (control unit,CU
) 协调参与机器指令执行的步骤序列。 - 一个算术逻辑单元
算术逻辑单元 (arithmetic logic unit,ALU
) 执行算术运算,如加法和减法,以及逻辑运算,如AND
(与)、OR
(或) 和NOT
(非)。
- 寄存器 (register)
内存存储单元 (memory storage unit) 用于在程序运行时保存指令与数据。
它接受来自CPU
的数据请求,将数据从随机存储器(RAM
)传输到CPU
,并从CPU
传输到内存。由于所有的数据处理都在CPU
内进行,因此保存在内存中的程序在执行前需要被复制到CPU
中。程序指令在复制到CPU
时,可以一次复制一条,也可以一次复制多条。CPU 通过主板上 CPU 插座的引脚与计算机其他部分相连。大部分引脚连接的是数据总线、控制总线和地址总线。
总线 (bus) 是一组并行线,用于将数据从计算机一个部分传送到另一个部分。
一个计算机系统通常包含四类总线:数据类,I/O类、控制类和地址类。- 数据总线 (data bus) 在
CPU
和内存之间传输指令和数据。 - I/O总线在
CPU
和系统输入/输出设备之间传输数据。 - 控制总线 (control bus) 用二进制信号对所有连接在系统总线上设备的行为进行同步。
- 当前执行指令在
CPU
和内存之间传输数据时,地址总线 (address bus) 用于保持指令和数据的地址。
- 数据总线 (data bus) 在
时钟︰与 CPU 和系统总线相关的每一个操作都是由一个恒定速率的内部时钟脉冲来进行同步。
机器指令的基本时间单位是机器周期 (machine cycle) 或时钟周期 (clock cycle)。
一个时钟周期的时长是一个完整时钟脉冲所需要的时间。
执行一条机器指令最少需要1个时钟周期,有几个需要的时钟则超过了50个(比如8088处理器中的乘法指令)。
由于在CPU
、系统总线和内存电路之间存在速度差异,因此,需要访问内存的指令常常需要空时钟周期,也被称为等待状态 (wait states )。
指令执行周期
《汇编语言:基于x86处理器(原书第7版)》Page 24
三个步骤:取指 (Fetch)、译码 (Decode) 和执行 (Execute)。
操作数 (operand) 是指操作过程中输入或输出的值。
读取内存
《汇编语言:基于x86处理器(原书第7版)》Page 25
作为一个常见现象,计算机从内存读取数据比从内部寄存器读取速度要慢很多。
这是因为从内存读取一个值,需要经过下述步骤:
- 将想要读取的值的地址放到地址总线上。
- 设置处理器 RD(读取)引脚(改变 RD 的值)。
- 等待一个时钟周期给存储器芯片进行响应。
- 将数据从数据总线复制到目标操作数。
上述每一步常常只需要一个时钟周期,虽然一共只需要4个时钟周期。但是,与CPU寄存器相比,这个速度还是慢了,因为访问寄存器一般只需要1个时钟周期。
CPU 设计者想出了一个可以减少读写内存的时间的方法——将大部分近期使用过的指令和数据存放在高速存储器 cache
中。
其思想是,程序更可能希望反复访问相同的内存和指令。因此,cache
保存这些值就能使它们能被快速访问到。此外,当 CPU
开始执行一个程序时,它会预先将后续(比如)一千条指令加载到 cache
中,这个行为是基一种假设,即这些指令很快就会被用到。如果这种情况重复发生在一个代码块中,则 cache
中就会有相同的指令。
当处理器能够在 cache
存储器中发现想要的数据,则称为 cache
命中 (cache hit)。反之,如果 CPU
在 cache
中没有找到数据,则称为 cache
未命中 (cache miss)。
x86 系列中的 cache
存储器有两种类型:
- 一级
cache
(或主cache
)位于CPU
上 - 二级
cache
(或次cache
)速度略慢,通过高速数据总线与CPU
相连
这两种 cache
以最佳方式一起工作。
还有一个原因使得 cache
存储器比传统 RAM
速度快—— cache
存储器是由一种被称为静态 RAM
( static RAM)的特殊存储器芯片构成的。
习题整理
在微型计算机中,微处理器的主要功能是:(A)
A. 算术逻辑运算及全机的控制
B. 逻辑运算
C. 算术逻辑运算
D. 算术运算
解析无
中央处理单元是进行算术和逻辑操作的部件,包含了(寄存器)、高频时钟、(控制单元)和(算术逻辑单元)。
参考上文整理内容。
(总线)是一组并行线,用于将数据从计算机的一个部分传到另一部分。
其中,(数据总线)用于在内存和CPU
之间传递指令和数据;
(控制总线)使用二进制信号对所有连接在总线上的设备的行为进行同步。
参考上文整理内容。
当处理器能够在
cache
存储器中发现想要的数据,则称为cache
(命中)。
反之,如果CPU
在cache
中没有找到数据,则称为cache
(未命中)。
参考上文整理内容。
CPU可以用来描述计算机的:(A)
A. 运算速度
B. 输入功率
C. 磁盘转速
D. 更新频率
解析待添加
一条指令的执行通常可分为(取指)、(编码)和(执行)三个阶段。
解析见上文整理内容。
x86 处理器
操作模式
《汇编语言:基于x86处理器(原书第7版)》Page 27
x86处理器有四个主要的操作模式:
- 保护模式
- 实地址模式
- 系统管理模式
- 子模式:虚拟8086 (virtual-8086) 模式,这是保护模式的特殊情况。
地址空间
《汇编语言:基于x86处理器(原书第7版)》Page 27
在32位保护模式下,一个任务或程序最大可以寻址 4GB 的线性地址空间。
从 P6 处理器开始,一种被称为扩展物理寻址 (extended physical addressing) 的技术使得可以被寻址的物理内存空间增加到 64GB。
与之相反,实地址模式程序只能寻址 1MB 空间。
如果处理器在保护模式下运行多个虚拟8086程序,则每个程序只能拥有自己的1MB内存空间。
寄存器
《汇编语言:基于x86处理器(原书第7版)》Page 28
寄存器是直接位于 CPU
内的高速存储位置,其设计访问速度远高于传统存储器。
上图展示的是 32位 x86 处理器的基本程序执行寄存器 (basic program execution registers)。8个通用寄存器,6个段寄存器,一个处理器状态标志寄存器 (EFLAGS),和一个指令指针寄存器 (EIP)。下图为 64为 x86-64 处理器中的寄存器。
通用寄存器
通用寄存器主要用于算术运算和数据传输。其中,存在一些拥有特殊用法的通过寄存器:
- 乘除指令默认使用
EAX
。它常常被称为扩展累加器 (extended accumulator) 寄存器。 CPU
默认使用ECX
为循环计数器。ESP
用于寻址堆栈(一种系统内存结构)数据。它极少用于一般算术运算和数据传输,通常被称为扩展堆栈指针 (extended stack pointer) 寄存器。ESI
和EDI
用于高速存储器传输指令,有时也被称为扩展源变址( extended source index)寄存器和扩展目的变址 (extended destination index) 寄存器。- 高级语言通过
EBP
来引用堆栈中的函数参数和局部变量。除了高级编程,它不用于一般算术运算和数据传输。它常常被称为扩展帧指针 (extended frame pointer) 寄存器。
指令指针
指令指针 (EIP
) 寄存器中包含下一条将要执行指令的地址。某些机器指令能控制 EIP
,使得程序分支转向到一个新位置。
状态标志位
设置标志位时,该标识位 = 1;
清除(或重置)标识位时,该标志位 = 0。
- 进位标志位 (
CF
),与目标位置相比,无符号算术运算结果太大时,设置该标志位。 - 溢出标志位 (
OF
),与目标位置相比,有符号算术运算结果太大或太小时,设置该标志位。 - 符号标志位 (
SF
),算术或逻辑操作产生负结果时,设置该标志位。 - 零标志位 (
ZF
),算术或逻辑操作产生的结果为零时,设置该标志位。 - 辅助进位标志位 (
AC
),算术操作在8位操作数中产生了位3向位4的进位时,设置该标志位。 - 奇偶校验标志位 (
PF
),结果的最低有效字节包含偶数个1时,设置该标志位,否则,清除该标志位。一般情况下,如果数据有可能被修改或损坏时,该标志位用于进行错误检测。
习题整理
当无符号数算术运算结果超过目标位置大小时,应设置(进位)标志位;
当有符号数算术运算结果对目标位置而言太大或太小时,应设置(溢出)标志位;
当运算产生负数结果时,应设置(符号)标志位;
当运算结果为零时,应设置(零)标志位。
参考上文整理内容。
算术或逻辑操作产生结果为零时,设置(零)标志位;
与目标位置相比,有符号算术运算结果太大或太小时,设置(溢出)标志位。
参考上文整理内容。
下列标志位中,可用来判断无符号数运算结果太大的是:(B)
A. OF
B. CF
C. ZF
D. SF
参考上文整理内容。
下列几种存储器中,存取速度最快的是:(B)
A. Cache
B. 寄存器
C. 内存
D. 光盘
在存储器层次结构中,存储器速度从最快到最慢的排列顺序是:寄存器 -> cache
-> 主存 -> 辅存。
在程序执行过程中,EIP 寄存器保存的是?(B)
A. 上一条已执行指令的地址
B. 下一条即将要执行指令的地址
C. 正在执行指令的地址
D. 当前堆栈的栈顶
参考上文整理内容。
下列标志位中,可用来判断计算结果为零的是?($ZF$)
零标志位 (ZF
)、算术或逻辑操作产生的结果为零时,设置该标志位。
算数或逻辑操作产生负结果时,设置( 符号)标志位;
与目标位置相比,无符号算术运算结果太大时,设置(进位)标志位。
解析见上文整理内容。
两个整数相减等于0,则标志位正确的是:(D)
A. ZF=0 , PF=0 , SF=0
B. ZF=1 , PF=0 , SF=1
C. ZF=0 , PF=1 , SF=0
D. ZF=1 , PF=1 , SF=0
- 零标志位 (
ZF
),算术或逻辑操作产生的结果为零时,设置该标志位。 - 符号标志位 (
SF
),算术或逻辑操作产生负结果时,设置该标志位。 - 奇偶校验标志位 (
PF
),结果的最低有效字节包含偶数个1时,设置该标志位,否则,清除该标志位。