Как я могу попросить Mac OS выделить память в определенном диапазоне адресов?

Я пишу "уровень совместимости Mac OS 9" для Mac OS X, потому что недавно меня поразила ностальгия, и поскольку все текущие решения требуют, чтобы вы запускали Classic внутри виртуальной машины, которая не поддерживает все, что нужно для запуска материал, который я хочу использовать.

Для достижения этой цели я реализовал исполняемый загрузчик PEF, интерпретатор PowerPC, который может подключиться к собственному коду и некоторые библиотеки Mac OS 9. Все дело в некотором роде: в интерпретаторе есть некоторые ошибки, но это ожидалось, и я над этим работаю.

Моя самая большая проблема до сих пор заключается в том, что программы PowerPC являются 32-битными, поэтому указатели должны быть 32-битными. Чтобы удовлетворить это ограничение, в настоящее время я компилирую только для i386. Однако, поскольку я пытаюсь построить вокруг этого ядра, он становится все более и более ограниченным (например, вы не можете использовать ARC с 32-разрядными приложениями Cocoa). Не говоря уже о том, что это не супербезопасно, чтобы позволить PowerPC-коду получить доступ ко всему, что может иметь хост-процесс.

Я разработал "платформу" с возможным переключением на 64-битные значения: интерпретатор ожидает, что базовый адрес и все указатели PowerPC будут смещены этим базовым адресом. (Наличие карты, которая преобразует адреса PowerPC на собственные адреса, не может быть и речи по причинам производительности и дизайна.)

Поскольку в 64-разрядном адресном пространстве достаточно места для размещения четырех миллиардов независимых 32-битных адресных пространств, это звучит как хороший способ пойти за мной.

Но у меня все еще есть проблема: мне нужно быть уверенным, что я смогу выделить память внутри этого диапазона адресов, потому что интерпретатору PPC было бы невозможно получить доступ к чему-либо вне его.

Есть два решения, о которых я сейчас думаю:

  • Узнайте, могу ли я попросить Mac OS выделить что-то внутри определенного диапазона адресов. Я знаю, что могу использовать mmap, но mmap будет запрашивать распределения в кратных страницах, что кажется мне очень расточительным, так как мне нужна полная страница для каждого размещения, независимо от того, насколько она мала (хотя это могло бы на самом деле будьте любезны, учитывая, что у Mac Mac классической эпохи было очень мало памяти по сравнению с современными компьютерами);
  • Используйте mmap для резервирования полного 0x100000000 байт с помощью PROT_NONE, а затем mprotect страниц по требованию для фактического выделения памяти, когда это необходимо, и верните их в PROT_NONE, когда они больше не будут полезны. Он хорошо выглядит на бумаге, но это означает, что я должен выполнить замену malloc.

Итак, что мне делать? Есть ли встроенный механизм, который позволит мне выделить память, malloc -стиль, внутри определенного диапазона адресов? В противном случае, есть ли хорошая, читаемая версия с открытым исходным кодом malloc, на которой я мог бы основываться?

Ответ 1

Я не знаю о встроенном способе сделать это, но это выполнимо с небольшой работой. Один из подходов - создать пользовательскую зону malloc, а затем использовать malloc_zone_ * версии обычных функций malloc при распределении любой памяти, которая должна быть видимой для вашего кода PPC. Для вашей пользовательской зоны потребуется реализация malloc, но вы можете выбрать любое количество открытых исходных текстов (например, tcmalloc). Также необходимо подключить его, чтобы использовать что-то вроде vm_allocate с подсказкой, чтобы гарантировать, что вы получите выделение в нужном вам диапазоне.

Ответ 2

Итак, я сам рассматривал эту проблему для очень похожего (неопубликованного) проекта, и попытка использовать этот 64-разрядный подход (или, действительно, любое пространство большой памяти на x86!) быстро запускается в несколько неприятных проблем.

  • Хотя вы можете указать собственные API-интерфейсы в эмулируемых структурах, вы не можете заставить их делать все свои собственные распределения на этой арене. Вы можете предоставить свои собственные реализации всех наиболее очевидных, таких как _NewPointer, но внутренние выделения другими функциями (например, _NewWindow с nil wStorage) в значительной степени выходят из-под вашего контроля.

  • Структуры системы (например, Rect, например), выделенные эмулированным кодом, будут большими, но ОС будет хотеть их мало-endian. Там нет простого способа обойти это, кроме того, может быть, байт-замена всего на пути в и из собственных функций, и это кажется чрезвычайно подверженным ошибкам. (Другой подход, который я рассматривал здесь, состоял в том, чтобы просто сделать эмулированное ядро ​​работать как мало-endian, но некоторые программы, к сожалению, чувствительны к этому изменению.)

Чтобы быть ясным, я обожаю черт из идеи переводчика API Classic-to-OS-X. Но я уверен, что это непрактично - учитывая, что Apple закончила использование VM для Classic на PPC, я подозреваю, что они решили, что переводный подход не будет работать.