Windows+GCC下内存对齐的常见问题
结构/类对齐的声明方式
gcc和windows对于modifier/attribute的支持其实是差不多的。比如在gcc的例子中,内存对齐要写成:
class X
{
//...
} __attribute__((aligned()));
但是实际上你写成
class __attribute__((aligned())) X
{
/*...*/
};
gcc一样可以识别。这样MSVC和gcc就可以使用宏完成跨平台编译。
对齐类型的变量在堆与栈上的分配
对齐在以下场合都能提示编译器为它的变量分配对齐的地址:
void foo()
{
X v; // v是个栈上的16字节对齐的变量
X* p = new X; // p是堆上的16字节对齐的指针
X* a = new X[ARRAY_SIZE]; // 那么这个呢?
}
栈上的变量堆上分配出的变量,因为align这个hint的存在,都能满足16字节对齐的要求。但是数组呢?按照一般规律来分析,对齐后的sizeof(X),一定是对齐的整数倍。比如16字节对齐的话,那么X的大小只能是16的倍数。所以对于本例的数组而言,编译器应该也能知道a应该是16字节对齐的。
但是事实上挺奇怪。在MSVC上,p和a都很好的遵守了对齐的要求;在gcc上,p是对齐的,但是a却不是。其实这个问题在2004年便有人提出来,只是到目前为止一直都没有人动手过。当然,标准也没有规定X的数组就一定是要对齐的。要解决这个问题,要么重载class的operator new/delete,要么用memalign/aligned_malloc分配出对齐的内存,再placement new。出于易用性,我选择的是操作符重载。
clang对于对齐的支持更干脆:16B的对齐已经够用了。所以align完全被编译器忽视了。结果Intel出来了AVX,Clang就傻逼了。不知道这个问题3.4会不会修正。
编译器如何实现内存对齐
MSVC在x86下默认是支持的4B的内存对齐。也就是说在函数入口处,ESP和EBP只保证是4字节对齐的。这时,当前函数域栈上变量的地址都是ESP + 4 * x的形式。如果函数体内有对齐的变量,例如:
void foo()
{
int __declspec(align()) x;
// ...
}
那么编译器在代码生成时,会在函数的前部插入一段称为prolog的代码,这段代码会将堆栈修正为16B对齐,比如
PUSH EBP
MOV EBP, ESP
SUB ESP, XXX
AND ESP, 0xFFFFFFF0h
这样ESP就一定是16字节对齐的。这个时候给x分配的地址,就可以是ESP + 0x10 * n的形式,这样就满足了对齐的需要。
在GCC上,gcc认为所有的函数都有义务在调用其它函数的时候,ESP是16字节对齐的(当然,可以通过编译选项修改这一要求)。不光是调用方会这样保证,被调用方也是这样默认的。所以GCC为了调用效率更高一点,便根据调用方的假设,去掉了“堆栈修正”这个步骤。
原来的代码可能就变成了
PUSH EBP ; 假设这里的ESP是16B对齐的,Push了EBP,ESP就是16x-4了。
MOV EBP, ESP
SUB ESP, 0x0000023Ch ; 减完以后这里又是16字节对齐了
那么当被调用方遵守这个约定的时候,ESP当然就是16字节对齐的。但是有一种情况例外。在MinGW下,线程的入口函数是被API回调的。这个函数很可能是按照Windows的标准4个字节对齐的。这样,在没有堆栈修正的情况下,整个线程调用链16B对齐的默契就被打破了。如果这个时候出现了SSE代码试图存取“16字节对齐”的变量,那可能就会发生segment fault的异常,因为这些变量的地址并不是对齐的。
解决这个问题,有两种常见的办法:第一,写一个Wrapper函数,对齐ESP后转发调用;第二,使用编译选项-mstackrealign。这个选项会为所有函数增加堆栈修正的PROLOG代码,以保证函数栈帧一定是按照16字节或用户指定大小对齐。
Windows+GCC下内存对齐的常见问题的更多相关文章
- windows和Linux内存的对齐方式
一.内存对齐的初步解说 内存对齐能够用一句话来概括: "数据项仅仅能存储在地址是数据项大小的整数倍的内存位置上" 比如int类型占用4个字节,地址仅仅能在0,4,8等位置上. 例1 ...
- Windows平台下的内存泄漏检测
在C/C++中内存泄漏是一个不可避免的问题,很多新手甚至有许多老手也会犯这样的错误,下面说明一下在windows平台下如何检测内存泄漏. 在windows平台下内存泄漏检测的原理大致如下. 1. 在分 ...
- C/C++: C++位域和内存对齐问题
1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...
- C++位域和内存对齐问题
1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...
- C语言内存对齐
转:http://blog.csdn.net/embeddedman/article/details/7429976 首先由一个程序引入话题: 1 //环境:vc6 + windows sp2 2 ...
- 对C语言内存对齐的初步了解
在解释内存对齐的作用前,先来看下内存对齐的规则: 1. 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身 ...
- C++成员变量内存对齐问题,ndk下非对齐的内存访问导致BUS_ADRALN
同样的代码,在vs下运行正常,在android ndk下却崩溃: signal 7(SIGBUS),code 1 (BUS_ADRALN),fault addr 0xe6b82793 Func(sho ...
- struct内存对齐1:gcc与VC的差别
struct内存对齐:gcc与VC的差别 内存对齐是编译器为了便于CPU快速访问而采用的一项技术,对于不同的编译器有不同的处理方法. Win32平台下的微软VC编译器在默认情况下采用如下的对齐规则: ...
- [原创]使用GCC创建 Windows NT 下的内核DLL
原文链接:使用GCC创建 Windows NT 下的内核DLL 在温习<<Windows 2000 Driving>>分层驱动程序一章的时候,看到了关于紧耦合驱动连接方式,这种 ...
随机推荐
- Could not load file or assembly 'Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its de
页面加载时出现这个错误: Could not load file or assembly 'Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Cul ...
- HTML5 五子棋 - JS/Canvas 游戏
背景介绍 因为之前用c#的winform中的gdi+,java图形包做过五子棋,所以做这个逻辑思路也就驾轻就熟,然而最近想温故html5的canvas绘图功能(公司一般不用这些),所以做了个五子棋,当 ...
- OpenCv ROI操作
Mat img, dst; Rect imgroi(, , img.cols, img.rows);//小图像img需要复制到大图的像素区域rect Rect dstroi(, , img.cols, ...
- mysql索引总结----mysql 索引类型以及创建
文章归属:http://feiyan.info/16.html,我想自己去写了,但是发现此君总结的非常详细.直接搬过来了 关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基 ...
- datatable 加序号列
最近使用datatable时,发现没有像jqgrid那样生成序号列,在国外网站搜罗了一下还是很简单的,就要在aoColumns中添加一空列占位就行,然后再用fnRowCallback添加序号 示例如下 ...
- 创建WP8试用应用
参考资料: 创建 Windows Phone 的试用应用 如何在 Windows Phone 应用中实现试用体验 Windows Phone 7 开发 31 日谈——第23日:提供试用版应用程序 对资 ...
- CI框架代码运行最详细的流程
最近在学习CI(3.1.0-dev)框架源码,一边看源码,一边在github上面写中文注释,https://github.com/pandancode/CI-note,有兴趣的同学可以看看. inde ...
- mysql中生产表格多列统计问题
for Example: select date_format(date,'%Y-%m-%d') as day, count(case when xinghao='a' then 1 end) as ...
- git上传代码到osc@git
1.get an account 2.get a ssh-key 3.git setting git config --global user.name "...." git co ...
- Django动态渲染多层菜单
为后续给菜单设置权限管理方便,通过给页面模版菜单动态渲染,通过数据菜单表进行匹配需要渲染的菜单 #Django表结构 class Menus(models.Model): name = models. ...