Как работает libc? - PullRequest
2 голосов
/ 04 мая 2011

Я пишу эмулятор MIPS32 и хотел бы сделать возможным использование всей библиотеки Standard C (возможно, с расширениями GNU) при компиляции программ на C с помощью gcc.

Как я понимаю, на данный моментI / O обрабатывается системными вызовами в архитектуре MIPS32.Чтобы успешно запустить программу с использованием libc / glibc, как узнать, какие системные вызовы мне нужно эмулировать? (без проб и ошибок)

Редактировать: см. this для примера того, что я имею в виду под syscalls.

(Вы можете проверить проект здесь , если вам интересно, любые отзывы приветствуются. Имейте в виду, что он находится в очень ранняя стадия)

Ответы [ 4 ]

6 голосов
/ 04 мая 2011

Очень короткий ответ

Прочитайте гораздо более длинный ответ.

Короткий ответ

Если вы намереваетесь предоставить пользовательский libc, который использует некоторые функции вашего эмулятора, чтобы хост-ОС выполняла ваши системные вызовы, вы должны реализовать их все.

Намного более длинный ответ

Отойдите на минутку и посмотрите, как все обычно наслоено в реальной (не эмулированной) системе:

  1. Периферийные устройства имеют некоторый интерфейс ввода / вывода (например, пронумерованные порты или отображение памяти), который ЦП может щекотать, чтобы заставить их делать то, что они делают.
  2. CPU запускает программное обеспечение, которое понимает, как манипулировать оборудованием. Это может быть специализированная программа или операционная система, которая запускает другие программы. Поскольку на рисунке изображен libc, давайте предположим, что есть ОС, и это что-то Unix-y.
  3. Программы в пользовательском пространстве, запускаемые ОС, используют определенный интерфейс между собой и ОС, чтобы запрашивать выполнение определенных «системных» функций.

То, что вы пытаетесь выполнить, происходит между уровнями 3 и 2, где функция в libc или пользовательском коде делает то, что ОС определяет как запуск системного вызова. Это открывает многочисленные банки червей:

  • То, что ОС определяет как запуск системного вызова, отличается от ОС к ОС и (редко) между версиями одной и той же ОС. Эта проблема смягчается в «реальных» системах, предоставляя динамически подключаемый libc, который заботится о сокрытии этих деталей. Кроме того, если у вас есть двоичный файл MIPS32, который вы хотите запустить, использует ли он соглашение о системных вызовах, поддерживаемое вашим эмулятором?

  • Вам нужно будет предоставить пользовательский libc, который делает то, что ваш эмулятор может распознать как выполняющий определенный системный вызов, и выполнять его. Любая программа, которую вы хотите запустить, должна быть кросс-скомпилирована в MIPS32 и статически связана с ней, как и любые другие библиотеки, необходимые программе (на ум приходит libm). С другой стороны, ваш пакет эмулятора должен будет обеспечить имитацию динамического компоновщика плюс динамически связываемые копии всех необходимых библиотек, потому что открытие их на хосте не будет работать. Если у вас достаточно исходного кода для перекомпиляции программы с нуля, перенос может быть лучше, чем эмуляция.

  • Любой код, который делает предположения о путях к файлам в конкретной системе или другие предположения о том, что они найдут на определенных устройствах (которые сами являются файлами), не будет работать правильно.

  • Если вы предоставляете уровень 2, вы регистрируетесь, чтобы обеспечить полное и правильное моделирование поведения одной конкретной версии всей операционной системы. С некоторыми вызовами, такими как read() и write(), будет легко иметь дело; другие, такие как fork(), uselib() и ioctl(), будут намного сложнее Также не обязательно однозначное сопоставление вызовов и поведения, которое ваша программа использует с теми, которые предоставляет ваша хост-ОС. Все это предполагает, что хост Unix и целевая программа тоже. Если цель скомпилирована для какой-либо другой среды, все ставки выключены.

Этот последний момент заключается в том, что большинство эмуляторов предоставляют только процессор и аппаратное поведение некоторой целевой системы (т. Е. Все на уровне 1). Имея их, вы можете запускать загрузочный диск оригинальной системы, ОС и пользовательские программы без изменений. Существует ряд существующих эмуляторов MIPS32 , которые делают именно это и могут запускать неизмененные версии операционных систем, работающих на оборудовании, которое они эмулируют.

HTH и удачи в вашем проекте.

0 голосов
/ 04 мая 2011

Обычный подход заключается в эмуляции не только процессора, но и репрезентативного набора стандартных периферийных устройств. Затем вы запускаете операционную систему в вашем эмуляторе, которая поставляется с libc и аппаратными драйверами. Libc вызовет драйверы ОС, которые вызывают виртуальное оборудование в вашем эмуляторе. Для популярного примера, см. DosBox.

Другая интерпретация вашего вопроса заключается в том, что вы не хотите писать полный эмулятор, а слой двоичной совместимости, который позволяет вам запускать двоичные файлы mips32 в системе, отличной от mips32. Популярным примером этого является MacOsX (Intel), который также может выполнять приложения PowerPC.

В последнем сценарии вам нужно эмулировать либо ABI операционной системы (двоичный интерфейс приложения), либо, возможно, вы можете сойти с ABI в libc. В обоих случаях вам нужно реализовать код заглушки, работающий на эмуляторе, и код прокси, запущенный на хосте:

  • Заглушка сериализует аргументы вызова функции
  • ... и передает их из памяти эмулятора в память хоста, используя специальные виртуальные инструкции
  • Прокси-серверу необходимо исправить аргументы (порядковый номер, целочисленная длина, адресное пространство ...)
  • ... и выполняет вызов функции в хост-системе
  • Затем прокси-сервер кэширует и сериализует аргументы исходящей функции
  • ... и передает их обратно на заглушку
  • ... который возвращает данные вызывающей стороне

Большинство вызовов не смогут работать с универсальной заглушкой / прокси, но для этого нужны конкретные решения.

Удачи!

0 голосов
/ 04 мая 2011

Я не знаю точно, как работает MIPS, но на Win32 вызовы ОС должны быть явно импортированы в процесс через таблицу импорта DLL / EXE. В исполняемом формате, используемом системой MIPS, может быть что-то похожее.

0 голосов
/ 04 мая 2011

Большая часть стандартной библиотеки C по ISO может быть написана на прямом C. Доступ к функциональности ОС более низкого уровня требуется только нескольким частям.

Как минимум, вам нужно будет эмулировать базовый ввод-вывод на уровне блоков или символов для fopen, fread и fwrite. Вы можете использовать подход Unix и реализовать его поверх вызовов более низкого уровня open, read и write.

И вам придется управлять динамическим распределением памяти для malloc и free.

И setjmp и longjmp, которым требуется доступ к стеку выполнения.

Также time и функции signal.h.

...