第三章的内容为p145~p252, 分3次.
摘要
这章主要学习汇编代码, 汇编中没有变量, 只有寄存器, 内存, 指令等.
寄存器分类如下:
- 程序计数器(通常称为"PC", x86-64中用%rip表示)给出将要执行的下一条指令在内存中的地址.
- 整数寄存器文件包含16个命名的位置, 每个位置存储64位的值. 一般用来保存函数的参数, 局部变量, 返回值.
- 条件码寄存器保存状态, 用来实现if和while等.
- 一组向量寄存器用来存放一个或多个整数或浮点数.
本篇随便主要讲的整数寄存器的使用.(p145~p170)
数据格式
Intel用word表示16位数据类型, double words(双字)表示32位数据类型, quad words(四字)表示64位
整数寄存器
一个x86-64的CPU包含一组16个存储64位值得的通用目的寄存器, 用来存储整数数据和指针. 64位的命名归纳如下:
%rax 返回值
%rbx,%rbp,%r12,%r13,%r14,%r15 被调用者保存
%rdi,%rsi,%rdx,%rcx,%r8,%r9 第1,2,3,4,5,6个参数
%rsp 栈指针
%r10,%r11 调用者保存
完整的见图
寻址方式
分为立即数寻址, 寄存器寻址, 绝对寻址, 间接寻址, 变址寻址. 具体参看下图
指令
上面讲的都是基础知识, 下面开始指令的介绍, 指令的使用基于以上的基础.
MOV
MOV指令的作用是把数据从一个地方复制到另一个地方. 基本格式为MOV S, D
, 效果就是将S复制到D.
MOV有很多不同格式的指令, 功能都一样, 只是传送数据的大小不同. 如movb, movw, movl, movq, movabsq, 分别表示byte, word, long, quad word, abs quad word.
x86-64有一个限制, 不能在一条指令内完成从一个内存mov到另一个内存.
当源和目的大小不一致时, 还有2大类mov指令, movz和movs指令, 分别用来实现零扩展(高位补0)和符号扩展(高位补符号位). movz是零扩展, movs是符号扩展. 如下图:
cltq是一条快捷指令, cltq = movslq %eax, %rax. 我在想这个指令有什么用途, 查了下, 还挺有意思的, 原来引用了未声明函数时, 从32位转换为64位的时候, 编译器会自动加上cltq进行转换, 而转换可能会出现问题. 参考链接
栈指令
栈操作的指令有2个pushq和popq, pushq %rbp => subq $8, %rsp;movq %rbp,(%rsp); popq %rax => movq (%rsp), %rax; addq $8, %rsp;
x86-64中, 程序栈保存在内存中的某个区域, 栈向下增长, 这样栈底的物理位置高于栈顶的物理位置, 出入栈都在栈顶上操作, 如下图:
算术和逻辑操作指令
常见的加减乘除, 与或非异或, 左移右移等操作. 见下图:
leaq指令比较特别, leaq S, D => D = &S
, 表面上是从内存读取数据到寄存器, 实际上是利用寻址进行简单的加减乘运算.
例如, %rdx中的值为x, 则leaq 7(%rdx, %rdx, 4) = 5*x+7.
移位操作指令分左移和右移, 左移2个指令SAL和SHL完全等价, 右移SAR算术右移(补符号位) SHR逻辑右移(补0)