.
开头的行都是指导汇编器和链接器工作的伪指令,通常可以忽略数据类型 | 汇编代码后缀 | 大小(字节) |
---|---|---|
字节 | b | 1 |
字 | w | 2 |
双字 | l | 4 |
四字 | q | 8 |
名字 | 用途 |
---|---|
%rax | 返回值 |
%rbx | 被调用者保存 |
%rcx | 第4个参数 |
%rdx | 第3个参数 |
%rsi | 第2个参数 |
%rdi | 第1个参数 |
%rbp | 被调用者保存 |
%rsp | 栈指针 |
%r8 | 第5个参数 |
%r9 | 第6个参数 |
%r10 | 调用者保存 |
%r11 | 调用者保存 |
%r12 | 被调用者保存 |
%r13 | 被调用者保存 |
%r14 | 被调用者保存 |
%r15 | 被调用者保存 |
类型 | 格式 | 操作数值 | 名称 |
---|---|---|---|
立即数 | $Imm | Imm | 立即数寻址:直接取常数的值 |
寄存器 | ra | Rra | 寄存器寻址:取寄存器存储的内容 |
存储器 | Imm | MImm | 绝对寻址:取内存中某有效地址处的内容 |
存储器 | (ra) | MRra | 间接寻址 |
存储器 | Imm(rb) | MImm+Rrb | (基址+偏移量)寻址 |
存储器 | Imm(rb,ri) | MImm+Rrb+Rri | 变址寻址 |
存储器 | Imm(rb,ri,s) | MImm+Rrb+Rri*s | 比例变址寻址 |
指令 | 效果 | 描述 |
---|---|---|
MOV S, D | S -> D | 传送 |
MOVZ S, R | 零扩展(S) -> R | 以零扩展进行传送 |
MOVS S, R | 符号扩展(S) ->R | 传送符号扩展的字节(把源操作数的最高位进行复制) |
cltq | 符号扩展(%eax) -> %rax | 把%eax符号扩展到%rax |
指令 | 效果 | 描述 |
---|---|---|
push S | R%rsp <- R%rsp - 8; MR%rsp <- S | 将四字压入栈 |
pops D | D <- MR%rsp; R%rsp <- R%rsp + 8 | 将四字弹出栈 |
指令 | 效果 | 描述 |
---|---|---|
leaq S, D | D <- &S | 加载有效地址,目的操作数为寄存器 |
INC D | D <- D + 1 | 加1 |
DEC D | D <- D - 1 | 减1 |
NEG D | D <- -D | 取负 |
NOT D | D <- ~D | 取补 |
ADD S, D | D <- D + S | 加 |
SUB S, D | D <- D - S | 减 |
IMUL S, D | D <- D * S | 乘 |
XOR S, D | D <- D ^ S | 异或 |
OR S, D | D <- D | S | 或 |
AND S, D | D <- D & S | 与 |
SAL k, D | D <- D << k | 左移 |
SHL k, D | D <- D << k | 左移(等同于SAL) |
SAR k, D | D <- D >> K | 算数右移 |
SHR k, D | D <- D >> k | 逻辑右移 |
条件码 | 标志 |
---|---|
CF | 进位标志:最近的操作使最高位产生了进位 |
ZF | 零标志:最近的操作得出的结果为0 |
SF | 符号标志:最近的操作得到的结果为负数 |
OF | 溢出标志:最近的操作导致一个补码溢出 |
指令 | 基于 | 描述 |
---|---|---|
CMP S1, S2 | S2 - S1(这里和操作数顺序相反) | 比较:行为同SUB,但是只设置条件码而不更新目的寄存器 |
TEST S1, S2 | S1 & S2 | 测试:行为同AND,但是只设置条件码而不更新目的寄存器 |
指令 | 跳转条件 | 描述 |
---|---|---|
jmp Label | 1 | 直接跳转 |
amp *Operand | 1 | 间接跳转 |
long absdiff_se(long x, long y)
x in %rdi, y in %rsi
1 absdiff_se:
2 cmpq %rsi, %rdi Compare x:y
3 jge .L2 If >= goto x_ge_y
4 addq $1, lt_cnt(%rip) lt_cnt++ (这里的%rip是什么意思?)
5 movq %rsi, %rax
6 subq %rdi, %rax result = y - x
7 ret Return
8 .L2:
9 addq $1, ge_cnt(%rip) ge_cnt++
10 movq %rdi, %rax
11 subq %rsi, %rax result = x - y
12 ret Return
分支预测逻辑
来猜测每条指令是否会执行long absdiff(long x, long y)
x in %rdi, y in %rsi
1 absdiff:
2 movq %rsi, %rax
3 subq %rdi, %rax rval = y - x
4 movq %rdi, %rdx
5 subq %rsi, %rdx eval = x - y
6 cmpq %rsi, %rdi Compare x:y
7 cmovge %rdx, %rax If >=, rval = eval
8 ret Return
指令 | 传送条件 | 描述 |
---|---|---|
cmove S, R | ZF | 相等/零 |
cmovge S, R | ~(SF ^ OF) | 大于或等于( 有符号>= ) |
i
是一个代码段的地址i
时程序应该采取的动作1 .section .rodata 只读数据代码段
2 .align 8 Align address to multiple of 8
3 .L4:
4 .quad .L3 Case 100: loc_A
5 .quad .L8 Case 101: loc_def
6 .quad .L5 Case 102: loc_B
...
栈和寄存器存放着传递控制和数据、分配内存所需要的信息
指令 | 描述 |
---|---|
call Label | 过程调用 |
call *Operand | 过程调用 |
ret | 从过程调用中返回 |
1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|
%rdi | %rsi | %rdx | %rcx | %r8 | %r9 |
有些时候,局部数据必须存放在内存中:
&
,因此必须能够为它产生一个地址long call_proc()
{
long x1 = 1; int x2 = 2;
short x3 = 3; char x4 = 4;
proc(x1, &x1, x2, &x2, x3, &x3, x4, &x4);
return (x1 + x2) * (x3 * x4);
}
函数call_proc
的栈帧,包含局部变量和两个要传递给函数proc
的参数
+------------------------------------------------+
| 返回地址 32|
+------------------------------------------------+
| x1 24|
+------------------------------------------------+
| x2 20| x3 18|x4 17| 16|
+------------------------------------------------+
| 参数8 = &x4 8|
+------------------------------------------------+
| | 4 0| <==参数7
+------------------------------------------------+
被调用者保存寄存器
调用者保存寄存器
,任何函数都可以修改它们struct {
int i;
int j;
int a[2];
int *p;
};
偏移 | 0 | 4 | 8 | 16 | |
---|---|---|---|---|---|
内容 | i | j | a0 | a1 | p |
对齐限制
简化了形成处理器和内存系统之间接口的硬件设计对齐原则
是任何K字节的基本对象的地址必须是K的倍数struct S1 *
类型的指针p都满足4字节对齐struct S1 {
int i;
char c;
int j;
};
偏移 | 0 | 4 | 5 | 8 |
---|---|---|---|---|
内容 | i | c | j |
malloc
、calloc
、realloc
等)生成的块的起始地址都必须是16的倍数原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。