|
高级条件分支,在高级语言里最常见的是 if 语句。下面是一段简单的代码( ifthen.c ):
#include <stdio.h>
int main()
{
int a = 100;
int b = 25;
if (a > b) {
printf ("The higher value is %d\n", a);
} else {
printf ("The higher value is %d\n", b);
}
return 0;
} 看一下这段代码相应的汇编形式,使用 gcc -S ifthen.c 命令可以生成 ifthen.s 文件,内容如下:
$ cat ifthen.s
.file "ifthen.c"
.section .rodata
.LC0:
.string "The higher value is %d\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $100, 28(%esp)
movl $25, 24(%esp)
movl 28(%esp), %eax
cmpl 24(%esp), %eax
jle .L2
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
jmp .L3
.L2:
movl $.LC0, %eax
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
.L3:
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.1-4ubuntu8) 4.4.1"
.section .note.GNU-stack,"",@progbits 下面分析汇编代码的实现:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
上面一段,是在进入程序后,先对 EBP 寄存器入栈保护,然后使 EBP 指向当前堆栈的栈顶,这也是进入一个函数后的通常做法。第 3 行中,使 ESP 寄存器边界对齐,因为 -16 的十六进制为 0xfffffff0 ,这样就保证了堆栈指针从 "零" 开始,这么一来无论是对于 2 字节,还是 4 字节,都是容易对齐的。第 4 行,留出 8 个字节的堆栈空间,目的是放入程序中需要压栈的变量。
movl $100, 28(%esp)
movl $25, 24(%esp)
movl 28(%esp), %eax
cmpl 24(%esp), %eax
jle .L2
第1行,变量 a 入栈(a 的值为100)。
第2行,变量 b 入栈(b 的值为 25) 。
第3行,从堆栈中取出 a ,然后送到 EAX 中。
第4行,进行 a 与 b 的比较
第5行,如果 a 小于 b,则跳到 .L2 标签。
movl $.LC0, %eax
movl 28(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
jmp .L3
第 1 行,是 printf() 函数第一个字符串参数的起始地址,这里送入EAX 寄存器中。
第 2 行,从堆栈中取出 a 的值送入 EDX 寄存器中。
第 3 行,EDX 寄存器放入堆栈 ESP+4 处。
第 4 行,要打印的 a 值放在栈顶。
第 5 行,调用 printf 函数。( C 函数的参数入栈顺序是从右到左)
第 6 行,跳到 .L3,准备退出整个函数 (return 0;)
剩下的代码类似分析。 |
|