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>>分层驱动程序一章的时候,看到了关于紧耦合驱动连接方式,这种 ...
随机推荐
- 各大IT技术博客排行榜
cnblogs 积分排名前3000名 http://www.cnblogs.com/ 左侧有推荐博客排行 cppblog http://www.cppblog.com/AllBloggers.aspx ...
- [vue案例的知识点]todo-list
文章的原材料来自于vue的官方示例:https://cn.vuejs.org/v2/examples/todomvc.html,我们在学习过程中,试着对其中的一些知识点进行记录: 一.浏览器数据存储, ...
- BZOJ 1176 [Balkan2007]Mokia ——CDQ分治
[题目分析] 同BZOJ2683,只需要提前处理s对结果的影响即可. CDQ的思路还是很清晰的. 排序解决一维, 分治时间, 树状数组解决一维. 复杂度是两个log [代码] #include < ...
- pycharm快捷键、配置virtualenv环境,配置django调试,配置远程调试
pycharm安装和首次使用 http://blog.csdn.net/chenggong2dm/article/details/9365437 快捷键: 找文件.代码.引用相关 1.双击shift ...
- 1.2 控制器 view 的创建和加载
本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书” 加载优先顺序: 1.用系统的loadView方法创建控制器的视图 2.如果指定 ...
- Canvas 最佳实践(性能篇)
Canvas 想必前端同学们都不陌生,它是 HTML5 新增的「画布」元素,允许我们使用 JavaScript 来绘制图形.目前,所有的主流浏览器都支持 Canvas. Canvas 最常见的用途是渲 ...
- Check a dll is x64 or x86
Just read two good articles on this topic: http://stackoverflow.com/questions/480696/how-to-find-if- ...
- WPF上传文件到服务器
利用WebClient 上传文件到服务器 创建一个空网站,创建一个UploadFile.aspx项, 服务器报500错误:检查文件保存路径是否存在,检查文件大小限制 protected void Pa ...
- Linux Shell 脚本调试
方法如下所示:(1) 使用选项–x,启用shell脚本的跟踪调试功能: $ bash -x script.sh 运行带有-x标志的脚本可以打印出所执行的每一行命令以及当前状态.注意,你也可以使用sh ...
- centos 6.5 升级内核 linux 3.12.17 (笔记 实测)
环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G) 系统版本:Linux centos 2.6.32-431.el6.x86_64(Centos-6.5-x86_64-mi ...