我有一个简单的测试程序,用于加载xmm寄存器
movdqu指令跨页边界访问数据(OS = Linux)。
如果映射了以下页面,这可以正常工作。如果不是
映射然后我得到一个SIGSEGV,这可能是预期的。
然而,这极大地减少了未对准载荷的有用性
一点点。另外还有SSE4.2指令(比如pcmpistri)
允许未对齐的内存引用似乎表现出这种行为
同样。
这一切都很好 - 除了很多strcmp的实现
使用pcmpistri,我发现似乎没有解决这个问题
在所有 - 我已经能够设计琐碎的测试用例
导致这些实现失败,而一次一个字节是微不足道的
使用相同的数据布局,strcmp实现可以正常工作。
还有一点需要注意 - 它似乎是GNU C库的实现
64位Linux有一个似乎使用的__strcmp_sse42变体
pcmpistri指令以更安全的方式。实施
这个strcmp相当复杂,但似乎是在仔细尝试
避免页面边界问题。我不确定这是否是由于
我在上面描述的问题,或者它是否只是尝试的副作用
通过对齐数据获得更好的性能。
无论如何,我的问题主要是 - 我在哪里可以找到更多
关于这个问题?我输入了“movdqu cross page boundary”和
我可以想到谷歌的每一个变种,但没有遇到过
什么特别有用。如果有人能指出我进一步的信息
对此我们将不胜感激。
首先,任何试图访问未映射地址的算法都会导致SegFault。如果非AVX代码流使用4字节加载来访问页面的最后一个字节,并且“下一页”的前3个字节恰好没有映射,那么它也会导致SegFault。没有?我认为,“问题”是AVX(1/2/3)寄存器比“典型”寄存器大得多,以至于如果它们被简单地扩展到更大的寄存器,那么不安全的算法(但是它们已经侥幸逃脱)会被捕获。
对齐负载(MOVDQA)永远不会出现这个问题,因为它们不会跨越自己大小或更大的任何边界。未对齐的负载可能会出现此问题(如您所述)和“经常”这样做。原因是指令是 定义 加载目标寄存器的完整大小。您需要非常仔细地查看指令定义中的操作数类型。无论你感兴趣的数据有多少都无关紧要。重要的是指令的定义。
然而...
AVX1(Sandybridge)添加了一个“屏蔽移动”功能,它比movdqa或movdqu慢,但不会(在架构上)访问未映射的页面,只要未在该页面中访问的部分启用掩码。这是为了解决这个问题。通常,向前移动,看起来加载/存储的屏蔽部分(参见AVX512)也不会导致IA上的访问冲突。
(这是关于PCMPxSTRx行为的一个笨蛋。也许你可以在你的“字符串”对象中添加15个字节的填充?)
面对我写的图书馆的类似问题, 我得到了一些信息 从一个非常有帮助的贡献者。
这个想法的核心是将16字节读取对齐到 结束 字符串,然后处理开头的剩余字节。这是有效的,因为字符串的结尾必须位于可访问的页面中,并且可以保证16字节截断的起始地址也必须位于可访问的页面中。
由于我们从未读过字符串,因此我们无法潜入受保护的页面。
为了处理初始字节集,我选择使用 PCMPxSTRM
函数,返回匹配字节的位掩码。然后,只需将结果移位以忽略在字符串的真正开始之前出现的任何掩码位。