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>>分层驱动程序一章的时候,看到了关于紧耦合驱动连接方式,这种 ...
随机推荐
- 1 Maximum Product Subarray_Leetcode
Find the contiguous subarray within an array (containing at least one number) which has the largest ...
- WEB安全:XSS漏洞与SQL注入漏洞介绍及解决方案(转)
对web安全方面的知识非常薄弱,这篇文章把Xss跨站攻击和sql注入的相关知识整理了下,希望大家多多提意见. 对于防止sql注入发生,我只用过简单拼接字符串的注入及参数化查询,可以说没什么好经验,为避 ...
- SVN基本指令
Svn使用: Versions: Cornerstone: 如果命令行不出来,可以设置commonsline Tools 命令行:svn heip 获取服务器端数据 svn checkout 远端ur ...
- 关于Solr的使用总结的心得体会
摘要:在项目中使用Solr作为搜索引擎对大数据量创建索引,提供服务,本文是作者对Solr的使用总结的一点心得体会, 具体包括使用DataImportHandler从数据库中近实时同步数据.测试Solr ...
- Rdeis 详解 小白
Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用. Redis不仅仅支持简单的key-v ...
- TPC-H
http://blog.csdn.net/leixingbang1989/article/details/8766047
- Linux 利用lsof命令恢复删除的文件
lsof命令 lsof命令用于查看你进程开打的文件,打开文件的进程,进程打开的端口(TCP.UDP).找回/恢复删除的文件.是十分方便的系统监视工具,因为lsof命令需要访问核心内存和各种文件,所以需 ...
- .net 开发---windows服务
因为想把quartz.net自动run的程式挂到windows服务中去,遇到问题记录 1.创建windows服务后,利用C:\Windows\Microsoft.NET\Framework\v4.0. ...
- CF750E New Year and Old Subsequence
讲道理好久没有做过题了.. 题目大意 给出长度为$n$的只含数字的串,有$q$个询问,每次询问一段区间,问最少删去多少个数才能变成只含2017子序列而不含2016子序列 吉爸爸好强啊.. 定义$a_{ ...
- [BZOJ4197][Noi2015]寿司晚宴
4197: [Noi2015]寿司晚宴 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 412 Solved: 279[Submit][Status] ...