对齐是为了让处理器更高效取指,更快速的执行。我们可以照搬上面的汇编代码放在我们自己的用户程序里,以直观的方式观察编译器是如何对齐代码的。
C 代码如下:
[Plain Text] 纯文本查看 复制代码 #include <stdio.h>
static void delay_loop(unsigned long loops)
{
int d0;
__asm__ __volatile__(
"\\tjmp 1f\\n"
".align 16\\n"
"1:\\tjmp 2f\\n"
".align 16\\n"
"2:\\tdecl %0\\n\\tjns 2b"
:"=&a" (d0)
:"0" (loops));
}
int main()
{
int loops = 10;
delay_loop(loops);
return (0);
}
delay_loop 函数的反汇编代码如下: 080483f0 <delay_loop>:
80483f0: 55 push %ebp
80483f1: 89 e5 mov %esp,%ebp
80483f3: 53 push %ebx
80483f4: 83 ec 10 sub $0x10,%esp
80483f7: 8b 45 08 mov 0x8(%ebp),%eax
80483fa: 89 c3 mov %eax,%ebx
80483fc: 89 d8 mov %ebx,%eax
80483fe: eb 00 jmp 8048400 <delay_loop+0x10>
8048400: eb 0e jmp 8048410 <delay_loop+0x20>
8048402: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
8048409: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
8048410: 48 dec %eax
8048411: 79 fd jns 8048410 <delay_loop+0x20>
8048413: 89 c3 mov %eax,%ebx
8048415: 89 5d f8 mov %ebx,-0x8(%ebp)
8048418: 83 c4 10 add $0x10,%esp
804841b: 5b pop %ebx
804841c: 5d pop %ebp
804841d: c3 ret 在上面的第一条 jmp 语句中,地址是 0x80483fe,它的指令码有 2 个字节。所以接下来的 jmp 指令的指令的地址是 0x80484000。原本从汇编指令中,第一条 jmp 指令过后是要对齐的,但 0x80484000 已经是个 16 字节对其的地址,所以就不需要安排对齐。
第 2 条 jmp 指令后,代码开始不对齐了。这时,编译器在中间安排进了两条 lea 指令,每条完整的指令码是 7 个字节,共 14 个字节,这样一来,我们真正需要执行的 dec %eax 的地址就落在 0x8048410 处,这个地址是个 16 字节对齐的地址。 |