内存分配优化:从堆到栈
Memory allocation optimization: from heap to stack
我正在对 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 --> 堆栈分配)对任何人来说都很熟悉吗?是否有意义?谁能提供一些关于这种优化的manual/specification?
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, which is used by Linux, and BSD implementations copied this API from 32V UNIX from AT&T (according to FreeBSD)也是如此。
您只查看了第 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);
}
我正在对 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 --> 堆栈分配)对任何人来说都很熟悉吗?是否有意义?谁能提供一些关于这种优化的manual/specification?
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, which is used by Linux, and BSD implementations copied this API from 32V UNIX from AT&T (according to FreeBSD)也是如此。
您只查看了第 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);
}