【问题标题】:Memory allocation optimization: from heap to stack内存分配优化:从堆到栈
【发布时间】:2016-10-25 04:34:03
【问题描述】:

我正在对 32-bit x86 架构上的二进制文件执行一些逆向工程任务。

最近我发现了从C 源代码到汇编程序的一些有趣的优化。

比如原来的源码是这样的(这个源码来自openssl library):

powerbufFree = (unsigned char *)malloc(powerbufLen);

而编译后(gcc version 4.8.4 -O3),汇编代码是这样的:

807eaa0: cmp eax, 0xbff                         # eax holds the length of the buf.
807eaa5: mov dword ptr [ebp-0x68], eax          # store the length of powerbuf on the stack
807eaa8: jnle 0x807ec60                         # 0x807ec60 refers to the malloc
807eaae: mov edx, eax
807eab0: add eax, 0x5e
807eab3: and eax, 0xfffffff0
807eab6: sub esp, eax
807eab8: lea eax, ptr [esp+0x23]
807eabc: and eax, 0xffffffc0
807eabf: add eax, 0x40
807ead3: mov dword ptr [ebp-0x60], eax  # store the base addr of the buf on the stack.

令我惊讶的是,buf 确实是在堆栈上分配的!!!这对我来说似乎是对堆分配器的优化,但我不确定。

所以这是我的问题,上面的优化(malloc --> 堆栈分配)对任何人来说似乎都很熟悉吗?是否有意义?谁能提供一些关于这种优化的手册/规范?

【问题讨论】:

  • 这让我想起了新 JVM 中的逃逸分析。 en.wikipedia.org/wiki/Escape_analysis 如果内存永远不会存在于函数调用之外,它可以安全地从堆栈中分配。如果堆栈中有空间,这将是一对更快的分配/释放操作。
  • @user3629249 这与他的问题有什么关系?答:不是。
  • @user3629249。您好,谢谢您的指出。 1)我从 openssl 源代码部分复制/粘贴。 2) 在他们的原始代码中,他们有一个 (!=NULL) 的检查例程。
  • 我能找到的只有gcc.gnu.org/ml/gcc/2013-01/msg00084.html,它声称gcc 确实执行了这种优化。
  • 我用gcc-4.8.5 -O3 gcc-4.9.3 -O3 gcc-5.4 -O3 gcc-6 -O3 试过了:对malloc的调用还在。

标签: c optimization memory-management malloc heap-memory


【解决方案1】:

来自source of bn_exp.c:

0634 #ifdef alloca
0635     if (powerbufLen < 3072)
0636         powerbufFree = alloca(powerbufLen+MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH);
0637     else
0638 #endif
0639     if ((powerbufFree=(unsigned char*)OPENSSL_malloc(powerbufLen+MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH)) == NULL)
0640         goto err;

注意0xbff 等于 3071。在支持它的系统上,alloca 进行堆栈分配。 GNU version 也是如此,Linux 使用它,BSD implementations 从 AT&T (according to FreeBSD) 的 32V UNIX 复制了这个 API。

您只查看了第 639 行。但如果定义了 alloca,则 C 代码与您的程序集匹配。

如果分配相对较小,优化本身通常用于避免使用malloc 作为临时缓冲区的开销。对于 C.1999,可以改用 VLA(自 C.2011 起,VLA 是可选功能)。

有时,优化只是使用一些合理的小尺寸的固定大小的缓冲区。例如:

char tmp_buf[1024];
char *tmp = tmp_buf;

if (bytes_needed > 1024) {
    tmp = malloc(bytes_needed);
}
/* ... */
if (tmp != tmp_buf) {
    free(tmp);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-24
    • 2011-05-28
    • 2014-10-26
    • 2019-05-17
    • 2011-10-09
    • 2021-11-18
    • 2021-04-08
    相关资源
    最近更新 更多