【问题标题】:MOVDQU instruction + page boundaryMOVDQU 指令 + 页边界
【发布时间】:2014-03-10 00:07:06
【问题描述】:

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

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

但是,这大大降低了未对齐负载的有用性 一点点。另外 SSE4.2 指令(如 pcmpistri) 允许未对齐的内存引用似乎表现出这种行为 也是。

没关系——除了有很多 strcmp 的实现 使用我发现似乎无法解决此问题的 pcmpistri 完全没有——而且我已经能够设计出微不足道的测试用例 导致这些实现失败,而每次一个字节微不足道 strcmp 实现可以在相同的数据布局下正常工作。

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

无论如何,我的问题主要是 -- 我在哪里可以找到更多信息 关于这个问题?我输入了“movdqu 跨越页面边界”和 我能想到的谷歌的每一个变种,但还没有遇到 任何特别有用的东西。如果有人可以向我指出更多信息 对此将不胜感激。

【问题讨论】:

  • __strcmp_sse42 实现可能是为了避免跨越页面边界对性能造成的影响。英特尔处理器(不确定最新的处理器)在跨页面边界的未对齐访问方面有着令人震惊的性能历史。页面错误问题应该无关紧要。
  • 我很好奇这个问题的答案。英特尔优化手册(第 10.3.6 节)仅说“未对齐的 128 位 SIMD 内存访问可以跨页边界获取数据,因为系统软件以页粒度管理内存访问权限。”。也许尝试在其他操作系统上重现相同的错误?
  • 或者更确切地说,操作系统将响应页面错误并将其分页 - 对应用程序不可见(除了对性能造成巨大影响)。或者如果未分配应用程序则崩溃。在这种情况下,访问未分配内存是标准 UB。
  • 到底是什么问题? strcmp 也将生成 SIGSEG 如果您传递未终止的字符串并让它运行到非映射页面。这正是访问非映射页面所做的事情。
  • 作为对最后一条评论的回应。我仔细构建了一个测试,其中字符串位于 4K 页面的偏移量 4090 处,值为“test”和“\0”字节。以下内存页面未映射。当我将该字符串作为参数使用 strcmp 时,一切正常。当我尝试类似的 pcmpistri 指令时,会尝试加载整个 16 字节块——进入下一页,触发 SIGSEGV。这就是限制 pcmpistri 对我有用的原因,也是为什么我想知道我发现的一些使用它的 strcmp 实现。

标签: linux sse4


【解决方案1】:

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

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

不过……

AVX1 (Sandybridge) 添加了“屏蔽移动”功能,该功能比 movdqa 或 movdqu 慢,但不会(在架构上)访问未映射的页面,只要未为访问的部分启用掩码即可在那个页面中。这是为了解决这个问题。一般来说,向前看,加载/存储的屏蔽部分(参见 AVX512)似乎也不会导致 IA 上的访问冲突。

(PCMPxSTRx 的行为真是令人遗憾。也许您可以在“字符串”对象中添加 15 个字节的填充?)

【讨论】:

    【解决方案2】:

    我正在编写的一个库遇到了类似的问题,I got some information 来自一位非常有帮助的贡献者。

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

    由于我们从未读过字符串,因此我们不可能误入受保护的页面。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-12
      • 1970-01-01
      • 2021-07-29
      • 2013-03-05
      • 1970-01-01
      • 2016-01-01
      • 2011-04-15
      相关资源
      最近更新 更多