gpt4 book ai didi

c - 新旧GCC生成的汇编代码for循环的区别

转载 作者:太空狗 更新时间:2023-10-29 16:01:50 24 4
gpt4 key购买 nike

我正在阅读有关汇编代码的一章,其中有一个示例。这是 C 程序:

int main()
{
int i;
for(i=0; i < 10; i++)
{
puts("Hello, world!\n");
}
return 0;
}

这里是书中提供的汇编代码:

0x08048384 <main+0>:    push ebp
0x08048385 <main+1>: mov ebp,esp
0x08048387 <main+3>: sub esp,0x8
0x0804838a <main+6>: and esp,0xfffffff0
0x0804838d <main+9>: mov eax,0x0
0x08048392 <main+14>: sub esp,eax
0x08048394 <main+16>: mov DWORD PTR [ebp-4],0x0
0x0804839b <main+23>: cmp DWORD PTR [ebp-4],0x9
0x0804839f <main+27>: jle 0x80483a3 <main+31>
0x080483a1 <main+29>: jmp 0x80483b6 <main+50>
0x080483a3 <main+31>: mov DWORD PTR [esp],0x80484d4
0x080483aa <main+38>: call 0x80482a8 <_init+56>
0x080483af <main+43>: lea eax,[ebp-4]
0x080483b2 <main+46>: inc DWORD PTR [eax]
0x080483b4 <main+48>: jmp 0x804839b <main+23>

这是我的部分版本:

   0x0000000000400538 <+8>: mov    DWORD PTR [rbp-0x4],0x0
=> 0x000000000040053f <+15>: jmp 0x40054f <main+31>
0x0000000000400541 <+17>: mov edi,0x4005f0
0x0000000000400546 <+22>: call 0x400410 <puts@plt>
0x000000000040054b <+27>: add DWORD PTR [rbp-0x4],0x1
0x000000000040054f <+31>: cmp DWORD PTR [rbp-0x4],0x9
0x0000000000400553 <+35>: jle 0x400541 <main+17>

我的问题是,为什么本书的版本将 0 分配给变量( mov DWORD PTR [ebp-4],0x0 )并在之后与 cmp 进行比较但在我的版本中,它分配然后它执行 jmp 0x40054f <main+31> cmp在哪里是?

在没有任何 jump 的情况下分配和比较似乎更合乎逻辑,因为它就像 for 循环中的那样。

最佳答案

为什么您的编译器做了一些与书中使用的不同编译器不同的事情?因为它是不同的编译器。没有两个编译器会编译出相同的所有代码,即使是非常微不足道的代码也可能被两个不同的编译器甚至是同一编译器的两个版本编译成截然不同的代码。很明显,两者都是在没有任何优化的情况下编译的,经过优化,结果会更加不同。

让我们来推理一下 for 循环的作用。

for (i = 0; i < 10; i++) {
code;
}

让我们把它写得更接近于第一个编译器生成的汇编程序。

        i = 0;
start: if (i > 9) goto out;
code;
i++;
goto start;
out:

现在“我的版本”也是一样:

        i = 0;
goto cmp;
start: code;
i++;
cmp: if (i < 10) goto start;

这里明显的区别是,在“我的版本”中,循环内只会执行一个跳转,而书本版本有两个。由于 CPU 对分支的敏感程度,这是在更现代的编译器中生成循环的一种非常常见的方法。即使没有任何优化,许多编译器也会生成这样的代码,因为它在大多数情况下性能更好。较早的编译器不会这样做,因为要么他们没有考虑到这一点,要么这个技巧是在优化阶段执行的,而在编译本书中的代码时并未启用该技巧。

请注意,启用了任何优化的编译器甚至不会首先执行 goto cmp,因为它知道这是不必要的。尝试在启用优化的情况下编译您的代码(您说您使用 gcc,给它 -O2 标志),看看它在之后会有多大不同。

关于c - 新旧GCC生成的汇编代码for循环的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21141154/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com