数组在堆栈上的内存分配 [英] Arrays memory allocation on stack
问题描述
我在C语言中有2个功能:
I have 2 functions in C:
void func1(unsigned char x)
{
unsigned char a[10][5];
a[0][0] = 1;
a[9][4] = 2;
}
void func2(unsigned char x)
{
unsigned char a[10][5];
a[0][0] = 1;
a[9][4] = 2;
unsigned char b[10];
b[0] = 4;
b[9] = 5;
}
编译方式:
gcc 7.3 x86-64
gcc 7.3 x86-64
-O0 -g
操作系统:
16.04.1-Ubuntu x86-64
16.04.1-Ubuntu x86-64
产生的intel汇编功能:
Produced intel assembly of functions:
func1(unsigned char):
pushq %rbp
movq %rsp, %rbp
movl %edi, %eax
movb %al, -68(%rbp)
movb $1, -64(%rbp)
movb $2, -15(%rbp)
nop
popq %rbp
ret
func2(unsigned char):
pushq %rbp
movq %rsp, %rbp
movl %edi, %eax
movb %al, -84(%rbp)
movb $1, -64(%rbp)
movb $2, -15(%rbp)
movb $4, -74(%rbp)
movb $5, -65(%rbp)
nop
popq %rbp
ret
我可以看到为50字节数组分配了64字节.似乎它在16字节边界上分配堆栈,因为对于10字节-已分配16字节.
I can see that for 50 bytes array 64 bytes were allocated. It seems that it's allocating stack on 16 bytes boundary, since for 10 bytes - 16 bytes were allocated.
我的问题:
1)在数组的16个字节边界上是否有一些堆栈对齐标准? 导致诸如int,long int等变量明显不在16字节边界上分配.
1) Is there some standard of stack alignment on 16 byte boundary for arrays? Cause variables like int, long int, etc. clearly aren't allocated on 16 byte boundary.
2)为什么以这种奇怪的方式分配数组?我们可以看到a
, 14个字节数组,它们是在 50个字节的有效载荷之后 c1>, 6个对齐字节被分配在 10个字节的有效载荷之前.我想念什么吗?
2) Why arrays allocated in such a weird way? We can see for array a
, 14 bytes that were added as alignment padding right after our payload of 50 bytes, but for array b
, 6 alignment bytes are allocated before our payload of 10 bytes. Am i missing something?
3)为什么将函数参数传入EDI
(unsigned char x
),并放在距数组内存开头4个字节的堆栈上(包括填充).那么字节变量(AL register
)也被填充了吗?为什么 4个字节?
3) Why function argument passed in EDI
(unsigned char x
), placed on stack 4 bytes away from our arrays memory beginning(including padding). So byte variables(AL register
) are also padded or something? Why 4 bytes?
推荐答案
x86_64 abi需要16字节的堆栈对齐方式(输入函数时,堆栈指针必须为16字节对齐方式).但是您看到的过度对齐是由-O0
引起的;如果-O1
或更高,则阵列的排列效率更高.例如
x86_64 abi requires a 16 byte stack alignment (stack pointer must be 16 byte aligned when entering a function). But the overalignment seen by you is caused by -O0
; with -O1
or higher, the arrays are aligned more efficiently. E.g.
void func2(unsigned char x)
{
unsigned char a[10][5];
a[0][0] = 1;
a[9][4] = 2;
unsigned char b[10];
b[0] = 4;
b[9] = 5;
__asm__ __volatile__("" :: "r"(a), "r"(b) : "memory");
}
原因:
gcc -O1 -g x.c -c
objdump -d x.o
0000000000000010 <func2>:
10: c6 44 24 c0 01 movb $0x1,-0x40(%rsp)
15: c6 44 24 f1 02 movb $0x2,-0xf(%rsp)
1a: c6 44 24 b6 04 movb $0x4,-0x4a(%rsp)
1f: c6 44 24 bf 05 movb $0x5,-0x41(%rsp)
24: 48 8d 44 24 c0 lea -0x40(%rsp),%rax
29: 48 8d 54 24 b6 lea -0x4a(%rsp),%rdx
2e: c3 retq
-Os
或-O3
创建其他布局.
这篇关于数组在堆栈上的内存分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!