MOVDQU指令+页面边界

时间:2014-02-11 22:49:30

标签: linux sse4

我有一个简单的测试程序,用于加载xmm寄存器 movdqu指令跨页边界访问数据(OS = Linux)。

如果映射了以下页面,则可以正常工作。如果不是 映射然后我得到一个SIGSEGV,这可能是预期的。

然而,这会减少未对齐载荷的有用性 一点点。另外还有SSE4.2指令(比如pcmpistri) 允许未对齐的内存引用似乎表现出这种行为 同样。

这一切都很好 - 除了有许多strcmp的实现 使用pcmpistri,我发现似乎没有解决这个问题 在所有 - 我已经能够设计琐碎的测试用例 导致这些实现失败,而一次一个字节是无关紧要的 使用相同的数据布局,strcmp实现可以正常工作。

还有一点需要注意 - 它似乎是GNU C库的实现 64位Linux有一个似乎使用的__strcmp_sse42变体 pcmpistri指令以更安全的方式。实施 这个strcmp相当复杂,但它似乎在仔细尝试 避免页面边界问题。我不确定这是否是由于 我在上面描述的问题,或者它是否只是尝试的副作用 通过对齐数据获得更好的性能。

无论如何,我的问题主要是 - 我在哪里可以找到更多 关于这个问题?我输入了“movdqu crossing page boundary”和 我可以想到谷歌的每一个变种,但没有遇到过 什么特别有用。如果有人能指出我进一步的信息 非常感谢。

2 个答案:

答案 0 :(得分:8)

首先,任何尝试访问未映射地址的算法都会导致SegFault。如果非AVX代码流使用4字节加载来访问页面的最后一个字节,并且“下一页”的前3个字节恰好没有映射,那么它也会导致SegFault。没有?我认为“问题”是AVX(1/2/3)寄存器比“典型”寄存器大得多,以至于如果它们被简单地扩展到更大的寄存器,那么不安全的算法(但是它已经侥幸逃脱)会被捕获

对齐载荷(MOVDQA)永远不会出现这个问题,因为它们不会跨越自己大小或更大的任何边界。未对齐的负载可能会出现此问题(正如您所指出的那样)并且“经常”这样做。原因是指令已定义以加载目标寄存器的完整大小。您需要非常仔细地查看指令定义中的操作数类型。无论你感兴趣的数据有多少都无关紧要。重要的是指令的定义。

...然而

AVX1(Sandybridge)添加了一个“屏蔽移动”功能,它比movdqa或movdqu慢,但不会(在架构上)访问未映射的页面,只要没有为访问部分启用屏蔽就会掉线在那个页面。这是为了解决这个问题。通常,向前移动,看起来加载/存储的屏蔽部分(参见AVX512)也不会导致IA上的访问冲突。

(关于PCMPxSTRx的行为真是太糟糕了。也许你可以在你的“字符串”对象中添加15个字节的填充?)

答案 1 :(得分:2)

面对与我正在撰写的图书馆类似的问题,I got some information来自一位非常有帮助的撰稿人。

这个想法的核心是将16字节读取与字符串的 end 对齐,然后在开头处理剩余的字节。这是因为字符串的结尾必须存在于可访问的页面中,并且保证16字节截断的起始地址也必须存在于可访问的页面中。

由于我们从未读过字符串,因此我们无法潜入受保护的页面。

为了处理初始字节集,我选择使用PCMPxSTRM函数,它返回匹配字节的位掩码。然后,只需将结果移位以忽略在字符串真正开始之前出现的任何掩码位。