if/else
先上一段简单的c代码以及它对应的汇编程序:
#include<stdio.h>
int main(){
int i = 12;
if (i > 0 && i < 3)
{
i = 2;
}
else if (i >= 3 && i < 6)
{
i = 4;
}
else{
i = 6;
}
return 0;
}
****************** 上述c程序对应的汇编代码 asm **************************
`movl $12, -4(%rbp)`: 将立即数12移动到寄存器 `%rbp` 偏移量为 -4 字节处的内存地址中。
`cmpl $0, -4(%rbp)`: 将立即数0与寄存器 `%rbp` 偏移量为 -4 字节处的内存地址中的值进行比较。
`jle .L2`: 如果比较结果为小于或等于,则跳转到标签 `.L2` 处执行代码。
`cmpl $2, -4(%rbp)`: 将立即数2与寄存器 `%rbp` 偏移量为 -4 字节处的内存地址中的值进行比较。
`jg .L2`: 如果比较结果为大于,则跳转到标签 `.L2` 处执行代码。
`movl $2, -4(%rbp)`: 将立即数2移动到寄存器 `%rbp` 偏移量为 -4 字节处的内存地址中。
`jmp .L3`: 无条件跳转到标签 `.L3` 处执行代码。
`.L2:`: 定义了本地标签 `.L2`。
`cmpl $2, -4(%rbp)`: 将立即数2与寄存器 `%rbp` 偏移量为 -4 字节处的内存地址中的值进行比较。
`jle .L4`: 如果比较结果为小于或等于,则跳转到标签 `.L4` 处执行代码。
`cmpl $5, -4(%rbp)`: 将立即数5与寄存器 `%rbp` 偏移量为 -4 字节处的内存地址中的值进行比较。
`jg .L4`: 如果比较结果为大于,则跳转到标签 `.L4` 处执行代码。
`movl $4, -4(%rbp)`: 将立即数4移动到寄存器 `%rbp` 偏移量为 -4 字节处的内存地址中。
`jmp .L3`: 无条件跳转到标签 `.L3` 处执行代码。
`.L4:`: 定义了本地标签 `.L4`。
`movl $6, -4(%rbp)`: 将立即数6移动到寄存器 `%rbp` 偏移量为 -4 字节处的内存地址中。
`.L3:`: 定义了本地标签 `.L3`。
`movl $0, %eax`: 将立即数0移动到寄存器 `%eax` 中。
`popq %rbp`: 从堆栈中弹出一个值并将其存储到寄存器 `%rbp` 中。
总结, 可以看出,汇编实现if (i > 0 && i < 3)时,并不是去判断i 大于0 且i < 3,而是进行判错跳转,即我先判断 i 是不是 <= 0或者 i 是不是大于5,如果是我就跳出去。如果这2个都不符合,那说明i确实在0-3之间,我就不跳转,就执行{ i = 2;}的赋值语句。
while
#include<stdio.h>
int main(){
int i = 12;
while (i > 0)
{
i--;
}
return 0;
}
***************** 上述c语言的汇编程序 *****************
movl $12, -4(%rbp)
jmp .L2 # 直接跳到L2处
.L3:
subl $1, -4(%rbp)
.L2:
cmpl $0, -4(%rbp) # 判断
jg .L3 # 第一个操作数若大于第二个操作数,就跳到L3
movl $0, %eax
popq %rbp
## 以下指的都是cmpl的第2个操作数比第1个操作数小、大或等于
# jg 大于就跳转【只判断cmp指令下的比较结果】
# js 结果为负则转移【算数、逻辑运算的运算结果都可判断】
# jle 结果小于或等于就转移【只判断cmp指令下的比较结果】
for
#include<stdio.h>
int main(){
for(int i = 0; i < 12; i++){
i = i - 2;
}
return 0;
}
************** 上述c代码的汇编程序 **************************
movl $0, -4(%rbp)
jmp .L2
.L3:
subl $2, -4(%rbp)
addl $1, -4(%rbp)
.L2:
cmpl $11, -4(%rbp)
jle .L3
movl $0, %eax
popq %rbp
# 和上面while一个样,同样的汇编结构,同样的汇编套路