【问题标题】:mmap64() works in Red Hat 6.6 but not in Red Hat 7.2mmap64() 在 Red Hat 6.6 中有效,但在 Red Hat 7.2 中无效
【发布时间】:2016-11-22 22:43:50
【问题描述】:

mmap64()的函数调用如下:

addr = (unsigned char*) mmap64(NULL, regionSize, PROT_READ|PROT_WRITE, MAP_SHARED, FileDesc, (unsigned long long)regionAddr);

参数通常具有如下值:

regionSize = 0x20000;
FileDesc   = 27;
regionAddr = 0x332C0000;

显然,这些值在代码中并没有像那样硬编码,但我只想向您展示它们的典型值。

问题:

mmap64() 调用在 Red Hat Linux 6.6 中完美运行,内核版本:2.6.32-504.16.2.el6.x86_64。在 Red Hat Linux 7.2 中失败,内核版本:3.10.0-327.13.1.el7.x86_64。

据我所知,代码没有区别。

返回的 errno 是“无效参数”或 errno #22 (EINVAL)。查看此参考资料http://linux.die.net/man/3/mmap64,我发现 EINVAL 错误有 3 种可能性:

  1. 我们不喜欢 addr、length 或 offset(例如,它们太大,或未在页面边界上对齐)。 -> 在我的情况下很可能是罪魁祸首。
  2. (从 Linux 2.6.12 开始)长度为 0。 -> 不可能,我在调试打印中检查了长度(regionSize)值,它是 0x20000。
  3. 标志既不包含 MAP_PRIVATE 也不包含 MAP_SHARED,或者同时包含这两个值。 -> 从我的函数调用中可以看出,不可能是这样,只有 MAP_SHARED 标志作为参数给出。

所以我现在被困住了。不知道如何调试这个。这个问题是 100% 可重现的。任何人都对这两个操作系统版本之间可能发生的变化有什么提示?

【问题讨论】:

  • 如果您正在构建 64 位可执行文件,为什么不直接使用不带后缀的 mmap()?这对你的问题有什么影响吗?您确定没有分配给您指定的区域吗?如果让mmap64() 选择放置内存的位置会怎样?
  • 最后一个参数在概要中称为offset (mmap64()),并且:offset 必须是sysconf(_SC_PAGE_SIZE) 返回的页面大小的倍数。 i> 你的值是页面大小的倍数吗?在我看来,十六进制中的尾随零太少(512 的倍数,而不是 4K 或更大)。

标签: c linux x86-64


【解决方案1】:

将 cmets 转换为答案(一些 cmets 被修剪为不相关)。

如果您正在构建 64 位可执行文件,为什么不直接使用不带后缀的 mmap()?这对您的问题有什么影响吗?

但是,我认为您的问题是您所说的regionAddrmmap64() 的最后一个参数在概要中称为 offset,并且:

偏移量必须是sysconf(_SC_PAGE_SIZE)返回的页面大小的倍数。

regionAddr 的值是页面大小的倍数吗?在我看来,十六进制的尾随零太少(它是 512 的倍数,但不是 4K 或更大的倍数)。


请注意,该问题最初显示的 regionAddr 值不同 — 另请参阅下面的 cmets。

regionAddr = 0x858521600;

addr = (unsigned char*) mmap64(NULL, regionSize, PROT_READ|PROT_WRITE, MAP_SHARED, FileDesc, (unsigned long long)regionAddr);

使用修改后的信息(regionAddr 中的值是0x332C0000 或十进制的 828521600),出了什么问题就不太明显了。

【讨论】:

  • 感谢您的提示。 sysconf(_SC_PAGE_SIZE) = 4096。第一次尝试偏移量为 789315584 (0x2F0C0000),第二次尝试偏移量为 853278720 (0x32DC0000)。它是页面大小的倍数(除非我的数学是错误的)。我正在深入研究偏移量,因为它看起来是这里唯一可能出错的地方。
  • 这不是问题所说的:regionAddr = 0x858521600;addr = (unsigned char*) mmap64(NULL, regionSize, PROT_READ|PROT_WRITE, MAP_SHARED, FileDesc, (unsigned long long)regionAddr);。您可能是正确的,您的真实代码应该没问题(0x2F0C00000x32DC0000 都在 256 KiB 边界上对齐),但如果您不向我们展示真实代码,我们将无法帮助您。
  • 是的,我在最初的问题中犯了一个错误。 regionAddr 应该是十进制 858521600 (0x332C0000)。关于真正的代码,它是复杂且专有的。我不知道如何将它组织成一个好问题。我将更深入地研究 offset 论点,因为我相信这是唯一可能出错的论点。除了“无效参数”之外,mmap() 有没有办法为调试提供更有用的错误?
  • 好的;错误会发生,但是当问题中的信息(意外)不可靠时,人们很难可靠地帮助您。最后一个参数的类型正式地是off_t——你确定它等同于unsigned long long吗?如果没有,它可能会导致麻烦。我还注意到手册页的标题中有mmap64(),而概要中则有mmap()。您是否尝试过将mmap64() 替换为mmap() - 是否有所作为。我想如果它有所作为我会感到惊讶,但我们也需要排除不太可能的情况。考虑一个 MCVE (minimal reproducible example)。
  • 有趣。您没有获得 EBADF,但问题与描述符及其引用的内容有关。显然,我应该询问哪个文件。如果您提到了该文件,其他人可能会更早发现问题。很高兴解决了问题所在。你有解决方法吗?
猜你喜欢
  • 2019-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多