gcc堆栈优化

发布于 2024-10-19 03:50:10 字数 434 浏览 1 评论 0原文

您好,我有一个关于 gcc(或 g++)可能的堆栈优化的问题。FreeBSD

下的示例代码(UNIX 差异在这里重要吗?):

void main() {
   char bing[100];
   ..
   string buffer = ....;
   ..
}

我在 gdb 中发现该程序的核心转储是地址 bing 的值实际上低于该缓冲区(即 &bing[0] < &buffer)。

我认为这与教科书上所说的完全相反。那里可以吗 是一些编译器优化,以这样的方式重新组织堆栈布局 方式?

这似乎是唯一可能的解释,但我不确定。

如果您感兴趣,核心转储是由于缓冲区溢出造成的 bing 到缓冲区(但这也证实了 &bing[0] < &buffer)。

谢谢!

Hi I have a question on possible stack optimization by gcc (or g++)..

Sample code under FreeBSD (does UNIX variance matter here?):

void main() {
   char bing[100];
   ..
   string buffer = ....;
   ..
}

What I found in gdb for a coredump of this program is that the address
of bing is actually lower than that buffer (namely, &bing[0] < &buffer).

I think this is totally the contrary of was told in textbook. Could there
be some compiler optimization that re-organize the stack layout in such a
way?

This seems to be only possible explanation but I'm not sure..

In case you're interested, the coredump is due to the buffer overflow by
bing to buffer (but that also confirms &bing[0] < &buffer).

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

牵强ㄟ 2024-10-26 03:50:10

编译器可以按照自己希望的方式自由组织堆栈帧(假设它们甚至使用堆栈)。

他们这样做可能是出于对齐原因,或者是出于性能原因,或者根本没有任何原因。假设任何特定的顺序是不明智的。

如果您没有通过溢出缓冲区来调用未定义的行为,您可能永远不会知道,而事情应该如此。

编译器不仅可以重新组织变量,如果可以确定变量未被使用,还可以优化它们以消除它们的存在。使用代码:

#include <stdio.h>
int main (void) {
   char bing[71];
   int x = 7;
   bing[0] = 11;
   return 0;
}

比较正常的汇编器输出:

main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $80, %esp
    movl    %gs:20, %eax
    movl    %eax, 76(%esp)
    xorl    %eax, %eax
    movl    $7, (%esp)
    movb    $11, 5(%esp)
    movl    $0, %eax
    movl    76(%esp), %edx
    xorl    %gs:20, %edx
    je      .L3
    call    __stack_chk_fail
.L3:
    leave
    ret

与疯狂优化的:

main:
    pushl   %ebp
    xorl    %eax, %eax
    movl    %esp, %ebp
    popl    %ebp
    ret

注意到后者缺少什么吗?是的,没有堆栈操作可以为 bingx 创建空间。它们不存在。事实上,整个代码序列可以归结为:

  • 将返回码设置为0。return

Compilers are free to organise stack frames (assuming they even use stacks) any way they wish.

They may do it for alignment reasons, or for performance reasons, or for no reason at all. You would be unwise to assume any specific order.

If you hadn't invoked undefined behavior by overflowing the buffer, you probably never would have known, and that's the way it should be.

A compiler can not only re-organise your variables, it can optimise them out of existence if it can establish they're not used. With the code:

#include <stdio.h>
int main (void) {
   char bing[71];
   int x = 7;
   bing[0] = 11;
   return 0;
}

Compare the normal assembler output:

main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $80, %esp
    movl    %gs:20, %eax
    movl    %eax, 76(%esp)
    xorl    %eax, %eax
    movl    $7, (%esp)
    movb    $11, 5(%esp)
    movl    $0, %eax
    movl    76(%esp), %edx
    xorl    %gs:20, %edx
    je      .L3
    call    __stack_chk_fail
.L3:
    leave
    ret

with the insanely optimised:

main:
    pushl   %ebp
    xorl    %eax, %eax
    movl    %esp, %ebp
    popl    %ebp
    ret

Notice anything missing from the latter? Yes, there are no stack manipulations to create space for either bing or x. They don't exist. In fact, the entire code sequence boils down to:

  • set return code to 0.
  • return.
情丝乱 2024-10-26 03:50:10

编译器可以自由地在堆栈上布局局部变量(或将它们保留在寄存器中或对它们执行其他操作),但它认为合适:C 和 C++ 语言标准没有说明这些实现细节,POSIX 或UNIX。我怀疑你的教科书是否另有说明,如果是的话,我会寻找一本新教科书。

A compiler is free to layout local variables on the stack (or keep them in register or do something else with them) however it sees fit: the C and C++ language standards don't say anything about these implementation details, and neither does POSIX or UNIX. I doubt that your textbook told you otherwise, and if it did, I would look for a new textbook.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文