gpt4 book ai didi

c - 为什么调用 printf 会导致 main 的不同函数序言?

转载 作者:太空狗 更新时间:2023-10-29 11:03:59 24 4
gpt4 key购买 nike

编译时

#include <stdio.h>
int
main () {
return 0;
}

对于 x86 汇编,结果很简单且符合预期:

$> cc -m32 -S main.c -o -|sed -r "/\s*\./d"
main:
pushl %ebp
movl %esp, %ebp
movl $0, %eax
popl %ebp
ret

但是在研究不同的反汇编二进制文件时,函数序言绝非如此简单。的确,把上面的C源改成

#include <stdio.h>
int
main () {
printf("Hi");
return 0;
}

结果是

$> cc -m32 -S main.c -o -|sed -r "/\s*\./d"
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
subl $12, %esp
call printf
addl $16, %esp
movl $0, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret

特别是,我不明白为什么这些说明

leal    4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)

是生成的——特别是为什么不直接将 %esp 存储到 %ecx 中,而不是存储到 %esp+4 中?

最佳答案

如果 main 不是叶函数,它需要对齐堆栈以使其调用的任何函数受益。未调用 main 的函数只是保持堆栈的对齐。

lea 4(%esp), %ecx   # ecx = esp+4
andl $-16, %esp
pushl -4(%ecx) # load from ecx-4 and push that

它压入了返回地址的副本,因此在对齐堆栈后它会在正确的位置。你是对的,不同的顺序会更明智:

mov    (%esp), %ecx   ; or maybe even  pop %ecx
andl $-16, %esp
push %ecx ; push (mem) is slower than push reg

正如 Youka 在评论中所说,不要指望 -O0 中的代码完全得到优化。使用 -Og 进行不影响可调试性的优化。 gcc 手册建议编译/调试/编辑周期。 -O0 输出比优化代码更难阅读/理解/学习。映射回源代码更容易,但这是糟糕的代码。

关于c - 为什么调用 printf 会导致 main 的不同函数序言?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32896305/

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