微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何强制程序使用未alignment的地址?

我听说alignmentint的读写是primefaces和安全的,我想知道除了打包结构和转换/指针算术字节缓冲区之外,系统何时使非malloc的全局variables不alignment?

[X86-64 linux]在我所有的正常情况下,系统总是select不会被破坏的整数位置,例如,一个字是两个字节,另一个字是另外两个字节。 任何一个可以发布一个程序/ snip(C或程序集)强制全局variables为非alignment的地址,这样的整数被撕毁,系统必须使用两个读取加载一个整数值?

当我打印下面的程序时,这些地址彼此接近,使得多个variables在64位之内,但从不会看到字符撕裂(系统或编译器中的智能)?

#include <stdio.h> int a; char b; char c; int d; int e = 0; int isaligned(void *p,int N) { if (((int)p % N) == 0) return 1; else return 0; } int main() { printf("processor is %d byte mode n",sizeof(int *)); printf ( "a=%p/b=%p/c=%p/d=%p/f=%pn",&a,&b,&c,&d,&e ); printf ( " check for 64bit alignment of test result of 0x80 = %d n",isaligned( 0x80,64 )); printf ( " check for 64bit alignment of a result = %d n",isaligned( &a,64 )); printf ( " check for 64bit alignment of d result = %d n",isaligned( &e,64 )); return 0;}

输出

Windows 7上的Qt 5.2编译问题(32位)

是否有可能在OpenSUSE上降级glibc?

提高C ++应用程序启动速度的方法

C中的dynamic数组

好的C ++目录和文件库?

processor is 8 byte mode a=0x601038/b=0x60103c/c=0x60103d/d=0x601034/f=0x601030 check for 64bit alignment of test result of 0x80 = 1 check for 64bit alignment of a result = 0 check for 64bit alignment of d result = 0

在上述情况下如何读取字符? 它是否从8字节alignment的边界(在我的情况0x601030)读取,然后去0x60103c?

内存访问粒度总是字的大小不是吗?

谢谢。

C语言中函数的隐式声明

在32位Debian Squeeze下编译的AC程序在我的朋友的64位版本上导致段错误

如何强制两个进程在同一个cpu上运行?

当用_O_U8TEXT处理unicode时使用setmode时,C ++崩溃

GCC没有预期的警告

1)是的,不能保证未对齐的访问是原子的,因为[至少有时在某些类型的处理器上]数据可能被写成两个独立的写入 – 例如,如果你跨越一个内存页边界[我不是在谈论虚拟内存的4KB页面,我说的是DDR2 / 3/4页面,这是总内存大小的一小部分,通常是实际内存芯片宽度的16Kbits – 这将取决于记忆棒本身]。 同样,在x86以外的其他处理器上,读取未对齐内存的陷阱可能会导致程序中止,或者读取将在软件中被模拟为多个读取以“修复”未对齐的读取。

2)你总是可以通过如下方式创建一个未对齐的内存区域:

char *ptr = malloc(sizeof(long long) * number+1); long long *unaligned = (long long *)&ptr[2]; for(i = 0; i < number; i++) temp = unaligned[i];

顺便说一句,您的对齐检查检查地址是否对齐到64字节,而不是64位。 你必须除以8来检查它是否对齐到64位。

3)char是单字节读取,地址将在字节本身的实际地址上。 执行的实际内存读取可能是从目标地址开始的完整缓存行,然后循环,例如:

0x60103d是目标地址,所以处理器将读取一个32字节的高速缓存行,从我们想要的64位字开始:0x601038(并且一旦完成,处理器就进入下一条指令 – 同时下一个读被执行以填充缓存行),然后缓存行被填充0x601020,0x601028,0x601030。 但是我们应该关闭缓存[如果你想3GHz最新的x86处理器比66MHz 486慢一点,禁用缓存是一个很好的方法],处理器只需要读取0x60103d的一个字节。

4)不在x86处理器上,它们具有字节寻址 – 但是对于正常的存储器,如上所述,读取是在缓存行的基础上完成的。

还要注意,“不可能是原子的”与“不会是原子的”并不完全相同 – 所以你可能会很难用意志使它出错 – 你真的需要得到两个不同的所有时间线程恰到好处,跨越缓存线,跨越内存页边界等等,使之出错 – 如果你不希望它发生,会发生这种情况,但试图使它出错可能会很难相信[相信我,我去过那里,那样做]。

除了这些情况之外,这可能不是。

在装配中是微不足道的。 就像是:

.org 0x2 myglobal: .word SOME_NUMBER

但在英特尔,处理器可以安全地读取未对齐的内存。 它可能不是原子的,但从生成代码中可能不明显。

英特尔,对吧? 英特尔ISA具有单字节读/写操作码。 反汇编你的程序,看看它使用什么。

不一定 – 内存字大小和处理器字大小可能不匹配。

1)这个答案是平台特定的。 一般来说,编译器会对齐变量,除非你强迫它做。

2)在32位cpu上运行时,需要两次读取加载一个变量:

uint64_t huge_variable;

该变量比寄存器大,因此需要多个操作才能访问。 你也可以使用打包结构来做类似的事情:

struct unaligned __attribute__ ((packed)) { char buffer[2]; int unaligned; char buffer2[2]; } sample_struct;

3)这个答案是平台特定的。 有些平台的行为可能与您所描述的类似。 一些平台具有能够获取数据的半寄存器或四分之一寄存器的指令。 我建议检查编译器发出的程序集以获取更多细节(确保先关闭所有编译器优化)。

4)C语言允许您以字节大小的粒度访问内存。 这是如何实现的,你的cpu读取一个字节的数据量是平台特定的。 对于许多cpu而言,这与通用寄存器的大小相同。

C标准保证malloc(3)返回一个符合最严格对齐要求的内存区域,所以在这种情况下就不会发生这种情况。 如果存在未对齐的数据,则可能会按片段读取/写入(这取决于体系结构提供的确切保证)。

在某些体系结构中允许不对齐访问,而在其他体系上则是致命错误。 在允许的情况下,通常比对齐访问慢得多; 如果不允许,编译器必须把它们拼接在一起,而且速度更慢。

字符(真正的字节)通常允许有任何字节地址。 在这种情况下,使用字节的指令只是获取/存储单个字节。

不,内存访问是根据数据的宽度。 但是真正的内存访问是根据缓存行(在cpu缓存中为此进行读取)。

如果不调用未定义的行为,不匹配的对象将永远不会存在。 换句话说,没有任何一个动作序列,都有一个定义明确的行为,一个程序可以采取这种行为,这将导致一个不对齐的指针成立。 特别是,没有可移植的方式让编译器给你错位的对象。 最接近的是许多编译器所具有的“压缩结构”,但这只适用于结构成员,而不适用于独立对象。

此外,无法在便携式C中测试对齐性。您可以使用实现定义的指向整数的指针转换并检查低位,但是没有基本要求“对齐”指针在低位中具有零,或者转换为整数后的低位甚至对应于指针的“最低有效位”,无论这意味着什么。 换句话说,指针和整数之间的转换不需要通过算术运算。

如果你真的想做出一些错位的指针,最简单的方法是假设alignof(int)>1 ,就像这样:

char buf[2*sizeof(int)+1]; int *p1 = (int *)buf,*p2 = (int *)(buf+sizeof(int)+1);

如果alignof(int)大于1,则buf和buf+sizeof(int)+1都不可能同时对齐。因此,至少两个(int *)中的一个被应用于未对齐的指针,调用未定义的行为,典型的结果是一个错位的指针。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐