计算机系统导论——读书笔记——第三章 程序的机器级表示(持续更新)

第三章 程序的机器级表示

3.1 历史观点

3.2 程序编码

1.命令行

(1)编译

linux> gcc -Og -o p p1.c p2.c #编译p1.c和p2.c文件

(2)ATT格式汇编

linux> gcc -Og -S mytry.c #产生C语言汇编文件mytry.s,可直接查看

linux> gcc -Og -c mytry.c #产生二进制目标代码文件mytry.o,无法直接查看

linux> objdump -d mytry.o #输出mytry.o文件的机器代码和反汇编代码,在命令行中输出

linux> gcc -Og -o prog main.c mytry.c #生成可执行文件prog

linux> objdump -d prog #输出prog文件的机器代码和反汇编代码,在命令行中输出

(3)Intel格式汇编

linux> gcc -Og -S -masm=intel mytry.c #产生C语言汇编文件mytry.s,可直接查看

2. gcc命令的过程

C预处理器(扩展源代码,插入#include的文件并扩展#define定义的宏)

编译器(产生源文件的汇编代码.s)

汇编器(将汇编代码转换成二进制目标代码文件.o)

链接器(将目标代码文件与实现函数库的代码合并,并产生可执行文件.p)

 

3.2.1 机器级代码

1.两种抽象

(1)指令集架构/指令集体系结构(Instruction Set Architecture, ISA)

(2)虚拟地址

 

3.2.2 代码示例 

1.汇编vs反汇编

(1)指令长度:1-15字节

(2)反汇编器省略许多指令结尾的q,而给call和ret指令添加q后缀

2.反汇编.o vs 反汇编prog

(1)地址不同

(2)反汇编prog填上了callq等指令所需的地址

(3)反汇编prog在末尾插入nop,使函数代码变为16字节,便于储存下一个代码块

 

3.2.3 关于格式的注释

1."."开头的行:伪指令,指导汇编器和链接器工作

2.ATT格式汇编vsIntel格式汇编

(1)intel省略表示大小的后缀

(2)intel省略寄存器前%

(3)intel用不同的方式描述内存中的位置,如“QWORD PTR [rbx]”替代“(%rbx)”

(4)在带有多个操作数的指令情况下,列出的操作数顺序相反

 

3.3 数据格式

1.C语言数据类型在x86-64中的大小

注:

(1)b = byte = 8 bits, w = word = 16 bits, l = long word = 32 bits, q = quad word = 64 bits

(2)浮点数:s = short float(?我猜的) = 32 bits, l = long float(?) = 64 bits

(3)l既表示4字节整数又表示8字节浮点数,但并不会产生歧义,因为浮点数使用一组完全不同的寄存器

 

3.4 访问信息

1.16个整数寄存器(非常重要)

注:

(1)生成小于8字节结果的指令,剩下的字节会如何?

生成1或2字节的指令保持剩余字节不变,生成4字节的指令把高位4字节置0

(2)(i guess)栈指针 %rsp = register stack pointer

 

3.4.1 操作数指示符

1.操作数(operand)

(1)立即数(immediate):表示常数值,ATT汇编代码中表示为“$”+标准C表示法表示的整数,自动选择最紧凑的方法编码(?)

(2)寄存器(register):表示某个寄存器的内容,16个寄存器中的低位1、2、4、8字节中的一个作为操作数

(3)内存引用:根据有效地址访问内存位置

注:

(1)ra表示任意寄存器a,R[ra]表示它的值(这是将寄存器集合视为数组R,寄存器标识符作为索引)

(2)Mb[Addr]表示对存储在内存中地址Addr开始的b个字节值的饮用,可省去下标b

(3)Imm(rb, ri, s)是最常用的内存引用的寻址模式,包含:立即数偏移Imm(缺省为0)、基址寄存器rb(缺省为0)、变址寄存器ri(缺省为0)、比例因子s(s=1,2,4,8,缺省为1),有效地址为Imm+R[rb]+R[ri]*s

写在前面:书中把许多不同的指令划分为指令类,每一类执行相同的操作,只不过操作数的大小不同

3.4.2 数据传送指令

1.MOV类——简单的数据传送指令:把数据从源位置复制到目的位置

格式:MOV source源操作数, destination目的操作数

注:

(1)寄存器部分的大小必须与指令做后一个字符(b、w、l、q)指定的大小相匹配

(2)S、D均可以是内存地址或寄存器,但不能同时为内存地址;从内存传送数据到内存需要两条指令:内存->寄存器,寄存器->内存

(3)movq vs movabsq: movq只能表示以表示为32位补码数字的立即数作为源操作数,然后扩展符号得到64位,而movabsq能够以任意64位立即数作为源操作数,但只能以寄存器作为目的

 2.MOVZ和MOVS类:将较小的源值复制到较大的目的时使用

格式:

(1)零扩展(MOV zero)——高位补0: MOVZ+源大小+目的大小 source, register

(2)符号扩展(MOV sign)——高位扩展符号位:MOVS+源大小+目的大小 source, register

注:

(1)S可以是内存地址或寄存器,R只能是寄存器

(2)不存在movzlq指令,但可以用以32位寄存器为目的的movl指令实现,高位4字节置0

(3)cltq指令无操作数,效果与movslq %eax,%rax完全一致,但是编码更紧凑(我理解为:更省地方)

(4)一个有趣的小练习

答案:

猜你喜欢

转载自www.cnblogs.com/tanshiyin-20001111/p/11619024.html