【问题标题】:How do I find the range(s) of MMAPable virtual addresses in a program?如何在程序中找到 MMAPable 虚拟地址的范围?
【发布时间】:2021-05-30 02:28:45
【问题描述】:

背景资料:

  1. 我在 x86 系统上使用 64 位 Arch。

  2. 我没有使用 libc 或任何依赖于 libc 的语言。我正在使用专有的研究语言。我正在通过内联汇编进行系统调用。

  3. 我正在为一个研究项目编写一个实验性的自定义分配器,所以一个可移植的解决方案是一个不错的选择,但不是必需的。

  4. 我的程序是静态链接的,我愿意并且能够重写我用来解决给定解决方案的库。

根据这个 SO 帖子:Where is the stack memory allocated from for a Linux process? 一个程序的虚拟地址空间是这样组织的:

------------------ <--- Top of the process address space
Stack (grows down)
v v v v v v v v v
------------------

(unmapped)

------------------ <--- Maximum stack size.


(unmapped)


-------------------
mmap
-------------------


(unmapped)


-------------------
^ ^ ^ ^ ^ ^ ^ ^ ^ ^
brk (grows up)
-------------------
BSS
-------------------
Data
-------------------
Text
-------------------

------------------- <--- Bottom or process address space.

假设这是正确的,我正在尝试查找 brk 和堆栈之间的 MMAPable 地址范围。

通过从sbrk(0) 获取一个ptr,页面向上对齐ptr,然后确保brksbrk 不再被调用,是否足以找到下限?

通过获取一个ptr到堆栈上的某个位置,从getrlimit获取堆栈的最大大小,从ptr中减去它,页面向下对齐ptr,然后确保setrlimit 不会改变堆栈的大小?

我在这里不需要一个确切的范围,但我确实需要一个大范围的连续地址,这些地址可以保证是安全的 MMAPable(当然,假设我自己没有破坏它们)。在我的研究中,我遇到了这个:https://www.ibm.com/docs/en/aix/7.2?topic=memory-understanding-mapping,上面写着:

对于 64 位进程,具有进程地址空间的两组地址范围可用于 mmap 或 shmat 映射。第一个由单个范围 0x07000000_00000000-0x07FFFFFF_FFFFFFFF 组成,可用于固定位置和可变位置映射。第二组地址范围仅可用于固定位置映射,包括范围 0x30000000-0xCFFFFFFF、0xE0000000-0xEFFFFFFF 和 0x10_00000000-0x06FFFFFF_FFFFFFFF。该集合的最后一个范围,由 0x10_00000000-0x06FFFFFF_FFFFFFFF 组成,也可供系统加载程序用于保存程序文本、数据和堆,因此只有该范围中未使用的部分可用于固定位置映射。

这正是我需要的信息,但它适用于错误的操作系统。如果有人可以帮助我找到有关 Linux 和 Arch 的相同信息,那将是一个很大的帮助。

【问题讨论】:

  • 只要调用mmap地址为NULL,内核就会选择一个合适的地址。
  • 这就是我的其他自定义分配器的工作方式。这需要对事情的发展有自己的看法。
  • 一种方法是在mmap 一个非常大的MAP_ANONYMOUS | MAP_NORESERVE 区域前面,传递地址NULL 让内核选择地址。然后您知道您可以在该地址区域内安全地创建 MAP_FIXED 映射。

标签: linux memory-management mmap allocation virtual-memory


【解决方案1】:

经过大量测试,我发现我在问题中提出的解决方案确实有效。我一直在使用cat /proc/&lt;pid&gt;/maps 来检查我的自定义分配器,它的行为符合我的预期。重申解决方案:

  1. 要找到下限使用sbrk(0),确保ptr 是页面对齐的,然后确保不再调用brksbrk

  2. 为了安全地逼近上限,使用 getrlimit 找到堆栈大小,将其从 ptr 中减去到堆栈中,对 ptr 进行页面对齐,然后永远不要使用 setrlimit 更改堆栈大小。

如果您可能需要触摸brksbrksetrlimit,那么您还可以在下限中添加一些内边距并从上限中减去一些内边距。您可以通过使用/proc/meminfo 查找系统有多少内存来动态计算安全的填充量,或者如果您不需要通用解决方案,您可以根据您的实际情况过度估计您需要多少做。

【讨论】:

    猜你喜欢
    • 2011-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-07-10
    • 2015-07-09
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 2018-09-21
    相关资源
    最近更新 更多