【问题标题】:How can I ask Mac OS to allocate memory in a specific address range?如何要求 Mac OS 在特定地址范围内分配内存?
【发布时间】:2012-11-11 03:05:27
【问题描述】:

我正在为 Mac OS X 编写一个 Mac OS 9“兼容层”,因为我最近被怀旧之情所震撼,并且因为所有当前的解决方案都要求您在不支持它应该运行的所有内容的虚拟机中运行 Classic我想用的东西。

为了实现这个目标,我实现了一个 PEF 可执行加载器、一个可以桥接到本机代码的 PowerPC 解释器以及一些 Mac OS 9 库。整个事情都在工作:解释器中有一些错误,但这是意料之中的,我正在努力解决这个问题。

到目前为止,我最大的问题是 PowerPC 程序是 32 位的,所以指针必须是 32 位的。为了满足这个限制,目前我只为 i386 编译。然而,当我试图围绕该核心进行构建时,它变得越来越受限制(例如,您不能将 ARC 与 32 位 Cocoa 应用程序一起使用)。更不用说让 PowerPC 代码访问宿主进程可以访问的所有内容并不是超级安全的。

我在设计“平台”时考虑到最终切换到 64 位:解释器需要一个基地址,并且所有 PowerPC 指针都被该基地址偏移。 (出于性能和设计原因,将 PowerPC 地址转换为本地地址的映射是毫无疑问的。)

由于 64 位地址空间有足够的空间容纳 40 亿个独立的 32 位地址空间,这对我来说听起来不错。

但我仍然有一个问题:我需要确保我能够在该地址范围内分配内存,因为 PPC 解释器不可能访问它之外的任何内容。

我现在正在考虑两种解决方案:

  • 了解我是否可以要求 Mac OS 在特定地址范围内分配某些内容。我知道我可以使用mmap,但是mmap 会要求以页面倍数进行分配,这对我来说似乎非常浪费,因为我需要为每个分配提供一个完整的页面,不管它有多小(尽管这实际上可以考虑到经典时代的 Mac 与现代计算机相比内存非常少,这没关系);
  • 使用mmap 保留完整的0x100000000 字节和PROT_NONE,然后使用mprotect 页面在需要时实际分配内存,并在它们不再有用时将它们放回PROT_NONE。它在纸面上看起来不错,但这意味着我必须实现 malloc 替换。

那么,我该怎么办?是否有内置机制可以让我尝试在特定地址范围内分配内存malloc-style?否则,是否有一个好的、可读的、开源的 malloc 实现我可以作为基础?

【问题讨论】:

  • 天哪。如果你有这个甚至部分工作,我很乐意看到它!你能把它扔到 Github 上吗?
  • @duskwuff,一定会的!我目前能够运行一个 hello world 程序。我的下一个目标是来自 MPW 工具的 Unmangle 可执行文件(这就是解释器变得丑陋的地方)。我正在开发一个图形调试器,当我有一些至少可以在 Cocoa 窗口中显示反汇编的东西时,我会将它推送到 github(可能是今天)。我的 github 句柄是zneak
  • (我只是不希望我的第一次推送太不完整。)
  • 有兴趣的朋友,我just published the project to GitHub
  • 是否可以通过包含定义的变量来创建空间?您是否希望从磁盘加载它,其中包含文本字典之类的内容(它会很大),然后只在该空间内分配?

标签: macos memory-management x86 emulation powerpc


【解决方案1】:

所以,我自己考虑过这个问题,用于一个非常相似(未发布)的项目,并尝试使用这种 64 位方法(或者,实际上是 x86 上的任何类型的大端内存空间!)很快就会遇到一些讨厌的问题。

  1. 虽然您可以将本机 API 指向模拟结构,但不能强制它们在该范围内进行所有自己的分配。您可以提供所有最明显的实现自己的实现,例如 _NewPointer,但其他函数的内部分配(例如,_NewWindow 与 nil wStorage)在很大程度上是您无法控制的。

  2. 由模拟代码分配的系统结构(例如 Rect)将是大端的,但操作系统会希望它们是小端的。除了可能在进出本机函数的过程中对所有内容进行字节交换之外,没有简单的方法可以解决这个问题,而且这似乎非常容易出错。 (我在这里考虑的另一种方法是让模拟的核心以小端方式运行,但不幸的是,有些程序对这种变化很敏感。)

明确地说,我非常喜欢 Classic-to-OS-X API 转换器的想法。但我很确定这是不切实际的——鉴于 Apple 最终在 PPC 上为 Classic 使用 VM,我怀疑他们认为翻译方法行不通。

【讨论】:

  • 我很确定 Apple 使用了 VM,因为他们的目标是 100% 相同的行为,而且他们几乎做到了(据我所知,它只是错过了虚拟内存)。我可以生活没有相同的行为。对于“外部”分配,只要它们包装不透明类型,这应该不是问题,因为我可以只返回一个指向库周围的瘦包装器将使用的实际指针的指针。也许这很容易出错,但我认为没有什么绝对不可能的。
  • 此外,我并不是真的在问这个项目会有什么困难。我认为困难的事情不会有任何意外。我在问如何在连续的 0x100000000 地址范围内分配东西。
  • 我考虑了指针包装方法——如果指针在经典 Mac OS 上总是被视为不透明的,它会起作用,但它们通常不是。直接读/写系统结构是一种非常普遍的做法。 :(
  • 如果您仍然对the whole thing 感到好奇,我得到了SillyBalls example program 今晚基本上工作。
【解决方案2】:

我不知道执行此操作的内置方法,但需要做一些工作。一种方法是创建一个自定义 malloc 区域,然后在分配需要对 PPC 代码可见的任何内存时使用常用 malloc 函数的 malloc_zone_* 版本。您的自定义区域需要一个 malloc 实现,但您可以从任意数量的开源区域(例如 tcmalloc)中进行选择。它还需要连接起来以使用带有提示地址的 vm_allocate 之类的东西,以确保您在所需的确切范围内获得分配。

【讨论】:

  • 我不知道 malloc_zone 函数系列,但这看起来很有希望。你认为你能想出一个使用它的例子吗?仅查看联机帮助页并不能说明如何实际使用这些功能。另外,它是否可以遵守所有分配都放在同一个虚拟地址范围内的要求?
  • 您首先要定义自己的 malloc 区域,malloc_zone_t(参见 /usr/include/malloc/malloc.h)。您可以通过调用malloc_zone_register 来注册它。你可以用指向你的自定义 malloc 实现的指针来填充它——你可以使用 Apple 使用的那个,它是 dyld 项目的一部分(例如,可从 opensource.apple.com 获得),或者第 3 方的一个(例如 tcmalloc )。无论哪种方式,您都必须调整自定义 malloc 实现以使用带有提示的 vm_allocate,正如我所指出的,而不是默认使用的任何内容(可能是 vm_allocate、mmap 或 brk)。
  • (我想举个例子太麻烦了,抱歉。我不知道互联网上有什么现成的例子)
  • 看起来这就像一个“正常”的 malloc,除了我必须自己提供实现。在这种情况下,它只为不同的分配器提供统一的接口;它不会使实现分配器更容易。这很酷,但不是我需要的。
  • 是的,这是一种非常复杂的 DIY 解决方案。正如我所说,我不知道更好的方法。不管怎样,您似乎都必须实现或找到一个自定义的 malloc 实现,因为这个功能绝对不是系统内置的。无论您是否将其插入 malloc 或任何由您决定。我认为这是明智的,因为 malloc API 提供了一些方便的抽象。如果方便您使用,您可能还想制作一个自定义 CFAllocator,并且可以为此重用 malloc 区域。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-14
  • 2021-07-17
  • 2012-10-24
  • 2018-01-10
  • 1970-01-01
相关资源
最近更新 更多