alloca() 的 GNU libc 实现如下:
# define alloca(size) __builtin_alloca (size)
它使用内置编译器,因此它完全取决于编译器如何实现它。更具体地说,它取决于堆栈的处理方式,这恰好是一个机器和依赖于 ABI 的数据结构。
让我们来看看一个具体的案例。在我的机器上,这是alloca(100000000000L) 的程序集:
0e9b: movabsq $-100000000016, %rax ; * Loads (size + 16) into rax.
0ea5: addq %rax, %rsp ; * Adds it to the top of the stack.
0ea8: movq %rsp, -48(%rbp) ; * Temporarily stores it.
0eac: movq -48(%rbp), %rax ; * These five instructions round the
0eb0: addq $15, %rax ; value stored to the next multiple
0eb4: shrq $4, %rax ; of 0x10 by doing:
0eb8: shlq $4, %rax ; rax = ((rax+15) >> 4) << 4
0ebc: movq %rax, -48(%rbp) ; and storing it again in the stack.
0ec0: movq -48(%rbp), %rax ; * Reads the rounded value and copies
0ec4: movq %rax, -24(%rbp) ; it on the previous stack position.
使用来自以下程序的gcc-4.2 -g test.c -o test 编译:
有了一些参考,现在可以回答您的问题:
在堆栈遇到堆段之前,它是否分配尽可能多的字节?
它只是按照请求的字节数盲目地增加堆栈。 根本没有进行边界检查,因此堆栈指针和返回值现在都可能位于非法位置。尝试从返回的值读取/写入(或压入堆栈)将导致 SIGSEGV。
它返回什么,一个指向 main 调用之前栈顶之后的第一个字节的指针?
它返回一个指向分配内存第一个字节的指针。
alloca() 返回之后的堆栈指针与调用alloca() 之前的堆栈指针不同吗?
是的,见上面的解释。另外,当调用alloca的函数返回时,栈会恢复到前一帧,可以再次使用。