注:以下所有内容均来自开源学习组织DataWhale
程序的机器级表示(四)
1 结构体
对于C代码中的一个结构体:
struct rec{
int i;
int j;
int a[2];
int *p;
}
其对应内存中的位置如下:
可以看出数组的元素是嵌入到结构体中的。
1.1 数据对齐
对于结构体:
struct S1{
int i;
char c;
int j;
}
其在内存中的占12个bytes,如下图示意:
i为int类型占4个bytes,c为char占1个byte,但编译器会在c的后面补上3个bytes,这是因为j为int类型,起始地址必须为4的倍数,因此需要在c后面补3个bytes。
对于不同的数据类型,地址对其的原则是任何K字节的基本对象的地址必须是K的倍数。例如short类型,起始地址必须是2的倍数。如下表所示:
K | Types |
---|---|
1 | char |
2 | short |
4 | int, float |
8 | long, double, char* |
当更改结构体内数据类型顺序时:
struct S1{
int i;
int j;
char c;
}
其在内存中的分配如下:
可以看出在char类型后面又补充了3个字节的填充,这是因为只有这样当结构体以数组形式存在时才能满足首地址是结构体的字节数的倍数。
2 联合体
与结构体不同,联合体中的所有字段共享统一存储区域,因此联合体的大小取决于它最大字段的大小。与结构体对比如下:
变量v和数组i大小都是8个bytes,所以这个联合体占8个bytes。
联合体的一种情况是:如果两个不同字段的使用是互斥的,那么就可以将这两个字段声明为一个联合体。
3 缓冲区溢出
当一个函数使用的栈的内存存储空间超过了实际给这个函数分配的内存存储空间时,会发生缓冲区溢出。缓冲区溢出会导致栈中的信息被破坏。
许多计算机病毒就是通过缓冲区溢出的方式来攻击计算机的,目前又三种机制来防止这种攻击:
- 栈随机化
- 栈破坏检测
- 限制可执行代码区域