为什么“ lea..and..push”汇编代码经常出现在函数的开头?

问题描述 投票:0回答:1

我意识到,当我经常通过GDB查看某些文件时,在函数开始处有这三行代码

   0x08048548 <+0>:     lea    ecx,[esp+0x4]
   0x0804854c <+4>:     and    esp,0xfffffff0
   0x0804854f <+7>:     push   DWORD PTR [ecx-0x4]

我通常忽略它们,因为在创建这三行堆栈框架之后,通常是函数开始的方式。

谢谢。

linux x86 reverse-engineering 32-bit
1个回答
0
投票
这将堆栈指针对齐到16字节边界,因为有时(对于SSE)CPU需要16字节的数据对齐。

[一个好的编译器将检查调用图(找出调用什么),然后决定:

  • 该函数本身不需要堆栈对齐,也不会调用其他需要堆栈对齐的函数;因此不需要堆栈对齐]]

  • 该函数的所有调用者都使用对齐的堆栈,因此:

      该函数仅需进行固定调整即可重新建立预先存在的对齐方式,例如sub esp, 8(可以与为本地变量保留堆栈空间的任何代码合并)
  • 实际上需要16字节对齐的数据可以在不对齐堆栈本身的情况下获得16字节对齐
  • 以上任何一项都不能被证明是正确的,因此该函数必须采用“最坏情况”并自行执行对齐(例如,您在函数开始时看到的指令)

当然,对于一个好的编译器,最后一种情况(需要您显示的代码是非常罕见的。)>

但是;大多数编译器不能很好地执行,因为它们看不到整个程序(如果将程序拆分为单独编译的多个目标文件,则编译器一次只能看到一部分程序)。他们无法弄清楚太多/任何调用图,因此最后一种情况(需要显示的代码)非常普遍。为了解决这个问题,您需要“链接时间代码生成”,但是通常人们不会打扰。

注意:对于AVX2,您需要32字节对齐;对于AVX512,您需要64字节对齐;对于某些事情(为避免在高线程代码中进行错误共享),您可能需要“缓存行大小对齐”(通常也是64字节)对准)。这使得“检查调用图以确定实际需要的对齐方式”算法比我描述的要复杂一些。

© www.soinside.com 2019 - 2024. All rights reserved.