文章目录
1. 数据格式
在汇编语言层面,Intel
用术语字word
表示16
位数据类型,双字double words
表示32
位数据类型,四字quad words
表示64
位数据类型。
这里字的概念和字长不一样,要注意区分。
下表给出了x86-64
环境(64
位机器+64
位编译)下C
语言的基本数据类型表示。
C 声明 |
Intel 数据类型 |
汇编代码后缀 | 字节大小 |
---|---|---|---|
char |
字节 | b |
1 |
short |
字 | w |
2 |
int |
双字 | l |
4 |
long |
四字 | q |
8 |
char * |
四字 | q |
8 |
float |
单精度 | s |
4 |
double |
双精度 | l |
8 |
此外还有不太常用的数据类型,如long long
、long double
。
大多数gcc
生成的汇编代码指令都有一个字符的后缀,表面操作数的大小。例如:传送字节movb
、传送字movw
、传送双字movl
、传送四字movq
。
用后缀l
表示双字,因为32
位数被看成是长字long word
。汇编代码也使用后缀l
表示8
字节双精度浮点数,这不会产生歧义,因为浮点数使用的是一组完全不同的指令和寄存器。
2. 访问信息
一个x86-64
的CPU
包含一组16
个存储64
位值的通用目的寄存器。这些寄存器用来存储整数数据和指针,它们的名字都以%r
开头。
最初的8086
中有8
个16
位寄存器,即%ax ~ %sp
。扩展到IA32
架构时,为了兼容旧架构,这些寄存器的标号扩展为%eax ~ %esp
。扩展到64
位时,原来的8
个寄存器标号为%rax ~ %rsp
,此外还增加了8
个新的寄存器%r8 ~ %r15
。
指令可以对这16
个寄存器的低位字节中存放的不同大小的数据进行操作。字节级操作可以访问最低的字节,16
位操作可以访问最低的2
个字节,32
位操作可以访问最低的4
个字节,64
位操作可以访问整个寄存器。
对于操作小于8
字节数据的指令,寄存器中剩下的字节会怎样,有以下规则:
- 仅操作最低的
1
字节或2
字节时,寄存器中其他的字节不变。 - 仅操作低
4
字节时,高4
字节会被置0
。
在常见的程序里,不同的寄存器扮演不同的角色。如%rsp
用来指明运行时栈的结束位置。
有一组标准的编程规范控制着如何使用寄存器来管理栈、传递函数参数、存储函数的返回值,存储局部和临时数据。
2.1. 操作数指示符
大多数指令有一个或多个操作数,指示执行一个操作要使用的源数据值、目的位置。源数据可以以常数形式给出,或从寄存器或内存中读出。目的位置可以是寄存器或内存。因此操作数的类型有三种:
- 立即数,用来表示常数值。在
ATT
格式的汇编代码中,立即数的书写方式是$
后面跟一个标准C
表示法表示的整数,如$-577
、$0xff
、$010
等。不同的指令允许的立即数值范围不同,汇编器会自动选择最紧凑的方式进行数值编码。 - 寄存器,表示某个寄存器的内容。使用
16
个寄存器的低1
、2
、4
或8
字节作为操作数。我们使用 r a r_a ra表示任意寄存器a
,使用 R [ r a ] R[r_a] R[ra]表示该寄存器的值。这里将寄存器集合看成数组R
,寄存器标号是数组下标。 - 内存引用,它会根据计算出来的地址访问某个内存位置。将内存看成一个很大的字节数组,我们用符号 M b [ A d d r ] M_b[Addr] Mb[Addr]表示对存储在内存中从地址
Addr
开始的b
的字节的访问。通常省略下标b
。
类型 | 格式 | 操作数值 |
---|---|---|
立即数 | $ I m m m Immm Immm | I m m m Immm Immm |
寄存器 | r a r_a ra | R [ r a ] R[r_a] R[ra] |
存储器 | I m m Imm Imm | M [ I m m ] M[Imm] M[Imm] |
存储器 | ( r a r_a ra) | M [ R [ r a ] ] M[R[r_a]] |