针对不同缓冲区大小的不同内存对齐方式 [英] Different memory alignment for different buffer sizes

查看:72
本文介绍了针对不同缓冲区大小的不同内存对齐方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试教育自己有关堆栈溢出的问题,并使用这些 -fno-stack-protector 标志进行了一些尝试,并试图了解如何在进程中管理内存.

I'm trying to educate myself regarding stack overflows and played around a bit with these -fno-stack-protector flag and tried to understand how memory is managed in a process.

我编译了以下代码(使用Ubuntu 18.04.1 LTS(x86_64),gcc 7.3.0.,禁用了ASLR)

I compiled the following code (using Ubuntu 18.04.1 LTS (x86_64), gcc 7.3.0., ASLR disabled)

int main (int argc, char *argv[])
{
    char    buff[13];
    return 0;
}

如下: gcc -g -o main main.c -fno-stack-protector .然后我想到了 gdb main b 4 run ,从以下输出中可以看到

as follows: gcc -g -o main main.c -fno-stack-protector. I then evoked gdb main, b 4, run and as can be seen from the the following outputs

(gdb) print &buff
$2 = (char (*)[13]) 0x7fffffffd963

0x7fffffffd963: 0xff    0xff    0x7f    0x00    0x00    0x00    0x00    0x00
0x7fffffffd96b: 0x00    0x00    0x00    0x00    0x00    0x10    0x46    0x55
0x7fffffffd973: 0x55    0x55    0x55    0x00    0x00    0x97    0x5b    0xa0
0x7fffffffd97b: 0xf7    0xff    0x7f    0x00    0x00    0x01    0x00    0x00

(gdb) info frame 0
Stack frame at 0x7fffffffd980:
 [...]
 Saved registers:
 rbp at 0x7fffffffd970, rip at 0x7fffffffd978

为缓冲区分配的 13 个字节紧随已保存的基本指针 rbp 之后.

the 13 bytes allocated for the buffer follow directly after the saved base pointer rbp.

将缓冲区大小从 13 增加到 21 后,我得到了以下结果:

After increasing the buffer size from 13 to 21 I got the following results:

(gdb) print &buff   
$3 = (char (*)[21]) 0x7fffffffd950

(gdb) x/48bx buff
0x7fffffffd950: 0x10    0x46    0x55    0x55    0x55    0x55    0x00    0x00
0x7fffffffd958: 0xf0    0x44    0x55    0x55    0x55    0x55    0x00    0x00
0x7fffffffd960: 0x50    0xda    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffd968: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffd970: 0x10    0x46    0x55    0x55    0x55    0x55    0x00    0x00
0x7fffffffd978: 0x97    0x5b    0xa0    0xf7    0xff    0x7f    0x00    0x00

(gdb) info frame 0
Stack frame at 0x7fffffffd980:   
 [...]
 Saved registers:
  rbp at 0x7fffffffd970, rip at 0x7fffffffd978

现在,在 rbp 之后的缓冲区后面还有另外的 11 个字节.

Now there are additional 11 bytes after the rbp before the buffer follows.

  • 在第二种情况下,为什么还要增加11个字节?这是由于堆栈对齐,例如从 rbp 开始,缓冲区必须对齐16个字节(16的倍数)吗?
  • 为什么在第一种情况下内存布局不同,似乎没有对齐?
  • In the second case, why are there 11 additional bytes? Is this due to the alignment of the stack, e.g. does the buffer have to be 16 bytes aligned (a multiple of 16) starting from rbp?
  • Why is the memory layout different in the first case, there seems to be no alignment?

推荐答案

The x86-64 System V ABI requires 16-byte alignment for local or global arrays that are 16 bytes or larger, and for all C99 VLAs (which are always local).

数组使用与元素相同的对齐方式,只是局部数组或全局数组长度至少为16个字节的数组变量或C99可变长度的数组变量始终至少对齐16个字节. 4

4 对齐要求允许在对阵列进行操作时使用SSE指令.编译器通常无法计算可变长度数组(VLA)的大小,但可以预期大多数VLA至少需要16个字节,因此强制要求VLA具有以下要求是合乎逻辑的至少16字节的对齐方式.

4 The alignment requirement allows the use of SSE instructions when operating on the array. The compiler cannot in general calculate the size of a variable-length array (VLA), but it is expected that most VLAs will require at least 16 bytes, so it is logical to mandate that VLAs have at least a 16-byte alignment.

小于一个SIMD向量(16个字节)的固定大小的数组没有此要求,因此可以在堆栈布局中高效打包.

Fixed-size arrays smaller than one SIMD vector (16 bytes) don't have this requirement, so they can pack efficiently in the stack layout.

请注意,此 不适用于内部结构 中的数组,仅适用于局部变量和全局变量.

Note that this doesn't apply to arrays inside structs, only to locals and globals.

(对于动态存储, malloc 返回值的对齐方式必须足够对齐,以容纳不超过该大小的任何对象,并且由于x86-64 SysV具有 maxalign_t 对于16个字节, malloc 如果大小为16或更大,还必须返回16个字节的对齐指针.对于较小的分配,如果需要,对于8B分配,它只能返回8B对齐.)

(For dynamic storage, the alignment of a malloc return value must be aligned enough to hold any object up to that size, and since x86-64 SysV has maxalign_t of 16 bytes, malloc must also return 16-byte aligned pointers if the size is 16 or higher. For smaller allocations, it could return only 8B-aligned for an 8B allocation if it wanted to.)

对本地数组的要求使得可以安全地编写将其地址传递给需要16字节对齐的函数的代码,但这绝不是ABI本身真正需要指定的内容.

The requirement for local arrays makes it safe to write code that passes their address to a function that requires 16-byte alignment, but this is mostly not something the ABI itself really needs to specify.

不同的编译器不必同意将它们的代码链接在一起,结构布局或调用约定的方式(调用寄存器被调用,或用于arg传递...)都不需要达成共识.编译器基本上拥有其正在编译的函数的堆栈布局,而其他函数则不能假定或依赖于此.如果您将指针作为函数args传递或将指针存储到全局变量中,则它们只会获取指向本地var的指针.

It's not something that different compilers have to agree on to link their code together, the way struct layout or the calling convention is (which registers are call-clobbered, or used for arg-passing...). The compiler basically owns the stack layout for the function it's compiling, and other functions can't assume or depend on anything about it. They'd only get pointers to your local vars if you pass pointers as function args, or store pointers into globals.

为全局变量指定它很有用:尽管如此,即使对象文件中的 extern int [] ,即使编译器生成的自动矢量化代码都可以对全局数组进行对齐,这也是安全的由另一个编译器编译.

Specifying it for globals is useful, though: it makes it safe for compiler-generated auto-vectorized code to assume alignment for global arrays, even when it's an extern int[] in an object file compiled by another compiler.

这篇关于针对不同缓冲区大小的不同内存对齐方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆