Может ли программа, эмулированная на чужом процессоре, работать быстрее, чем на родном?

Обновлено: 20.11.2024

Эмуляция и виртуализация имеют много общего, но имеют определенные операционные различия. Если вы хотите получить доступ к старой операционной системе в новой архитектуре, эмуляция будет вашим предпочтительным путем. И наоборот, виртуализированные системы действуют независимо от базового оборудования. Мы попытаемся разделить эти термины, которые часто путают, и опишем, что каждый из них означает для ИТ-операций бизнеса.

В чем разница?

Короче говоря, эмуляция означает, что одна система имитирует другую. Например, если часть программного обеспечения работает в системе A, а не в системе B, мы заставляем систему B «эмулировать» работу системы A. Затем программное обеспечение работает в эмуляции системы A.

В этом же примере виртуализация предполагает разделение системы A на два сервера, B и C. Оба этих «виртуальных» сервера являются независимыми программными контейнерами, имеющими собственный доступ к программным ресурсам — ЦП, ОЗУ, хранилище и сеть — и может перезагружаться независимо. Они ведут себя точно так же, как настоящее оборудование, и приложение или другой компьютер не смогут отличить их.

У каждой из этих технологий есть свои особенности использования, преимущества и недостатки.

Эмуляция

В нашем примере с эмуляцией программное обеспечение заменяет оборудование, создавая среду, которая ведет себя подобно оборудованию. Это нагружает процессор, выделяя циклы процессу эмуляции — циклы, которые вместо этого использовались бы для выполнения вычислений. Таким образом, большая часть мощности процессора расходуется на создание этой среды.

Интересно, что вы можете запустить виртуальный сервер в эмулируемой среде. Итак, если эмуляция — пустая трата ресурсов, зачем об этом думать?

Эмуляцию можно эффективно использовать в следующих сценариях:

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

Эмуляция также полезна при разработке программного обеспечения для нескольких систем. Кодирование можно выполнять на одном компьютере, а приложение можно запускать в эмуляциях нескольких операционных систем, причем все они работают одновременно в своих собственных окнах.

Виртуализация

В нашем примере с виртуализацией можно с уверенностью сказать, что вычислительные ресурсы используются эффективно и функционально независимо от их физического расположения или расположения. Быстрая машина с достаточным объемом оперативной памяти и достаточным объемом памяти может быть разделена на несколько серверов, каждый из которых имеет пул ресурсов. На этой единственной машине, обычно развертываемой как отдельный сервер, можно разместить веб-сервер и сервер электронной почты компании. Вычислительные ресурсы, которые ранее использовались недостаточно, теперь могут быть использованы в полной мере. Это может помочь значительно сократить расходы.

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

  • Широкая совместимость с существующей архитектурой ЦП x86
  • Возможность отображаться как физические устройства для любого аппаратного и программного обеспечения.
  • Автономный в каждом экземпляре

Между эмуляцией и виртуализацией ваш бизнес может выполнять большинство функций виртуальных систем. Хотя оба сервиса звучат одинаково, все зависит от того, как вы используете программное обеспечение. Если вы хотите, чтобы программное обеспечение не мешало, виртуализация позволяет запускать гостевой код непосредственно на ЦП. И наоборот, эмуляторы сами запускают гостевой код, экономя ЦП для других задач.

СОВРЕМЕННЫЕ компьютеры — мастера маскировки. Они должны быть. Поскольку, хотя технический прогресс хорош в том, что делает компьютерное оборудование быстрее, меньше и дешевле, он часто оставляет позади программное обеспечение, которое в первую очередь сделало машины полезными. Поскольку многие люди недовольны необходимостью выбрасывать совершенно хорошие программы при покупке новейшего компьютера, за последние несколько лет было разработано множество уловок, чтобы программное обеспечение не стало ненужным. Идея состоит в том, чтобы заставить современные компьютеры олицетворять или «эмулировать» старые компьютеры, обеспечивая подходящую среду для запуска устаревшего программного обеспечения.

Эмуляция, которая когда-то ограничивалась несколькими нишами компьютерной индустрии, теперь широко распространена. На самом деле, это происходит в фоновом режиме внутри многих компьютеров, устраняя разрыв между различными процессорами и операционными системами.Процессоры Intel Pentium Pro, Pentium II и новые процессоры Pentium III содержат специальное аппаратное обеспечение, обеспечивающее обратную совместимость со старыми процессорами и позволяющее повысить производительность. С 1994 года компьютеры Apple Macintosh содержали программное обеспечение, позволяющее им эмулировать более старые модели, в которых использовался другой микропроцессор. И, пожалуй, самым известным примером является кроссплатформенный язык Sun Java. Это позволяет программному обеспечению работать на любом устройстве, способном эмулировать вымышленный компьютер, называемый «виртуальной машиной Java», который даже физически не существует.

Простейший вид программного эмулятора, называемый интерпретатором, работает путем поиска каждой инструкции из сторонней программы, чтобы найти, как выполнить эквивалентную операцию на хост-компьютере. Этот медленный, но надежный метод позволяет, например, современным ПК эмулировать аркадные игровые автоматы 1980-х годов, микропроцессоры которых работали на долю скорости.

Более сложными являются JIT-компиляторы. После изучения каждой инструкции и перевода ее в родной формат системы, в которой она выполняется, JIT сохраняет переведенный код на случай, если он снова понадобится. А поскольку большая часть программного обеспечения повторяется (небольшие фрагменты кода обычно запускаются в программе много раз), вероятность того, что переведенный код действительно будет использоваться повторно, высока. Это обычно делает JIT быстрее, чем интерпретатор.

Однако мощность современных компьютеров означает, что сейчас разрабатываются еще более умные эмуляторы. Эмуляторы динамической перекомпиляции (DR) не ограничиваются переводом инструкций; они продолжают анализировать, как работает новый код, и заново переводят самые неуклюжие фрагменты, чтобы повысить эффективность.

Один из новейших эмуляторов, выпущенный в феврале, был разработан Connectix, компанией, базирующейся в Сан-Матео, Калифорния. Виртуальная игровая станция ( VGS ), как называют свое творение Connectix, эмулирует игровую консоль Sony PlayStation на персональном компьютере Macintosh.

Компания Sony, выпустившая на прошлой неделе новую PlayStation 2, возмущена этим. Это не потому, что VGS может повлиять на продажи консолей, которые продаются в убыток, чтобы побудить людей покупать игры. Фирма утверждает, что причина в том, что VGS может быть не в состоянии справиться со своей задачей, и, соответственно, у клиентов может сложиться плохое впечатление об играх Sony. Однако американские суды до сих пор выносили решения в пользу Connectix.

Connectix — ветеран эмуляторного бизнеса. Она также продает программу, позволяющую Macintosh выдавать себя за ПК. Но подражание также побуждает предпринимателей создавать новые компании. Это верный признак того, что происходит что-то важное и, возможно, прибыльное.

Два из этих стартапов — TeraGen и секретное подразделение Transmeta — идут (или, в случае с Transmeta, кажется) идут по пути аппаратного обеспечения. Они приняли вариант подхода, используемого Intel, чтобы сделать свои новые чипы быстрее, оставаясь при этом совместимыми с более ранними микропроцессорами. Это включает в себя преобразование сложных инструкций, которые предпочитали более ранние разработчики микросхем, в более простые рудиментарные инструкции, называемые микрооперациями, которые могут быть изменены процессором для повышения производительности. Подход TeraGen основан на этой идее, но обобщает ее так, что изготовленные на заказ микросхемы компании могут преобразовывать инструкции и, следовательно, эмулировать более одного типа процессора одновременно.

Хотя Transmeta не раскрывает своих планов, патент, выданный компании в ноябре 1998 г., свидетельствует о том, что она также работает над процессором, основанным на универсальных микрооперациях. Кроме того, технология Transmeta выглядит гибридной. Исходный код транслируется с помощью программного обеспечения, в то время как аппаратное обеспечение берет на себя хозяйственную работу, связанную с одновременной эмуляцией нескольких чипов — трюк, который может позволить компьютерам в будущем надевать множество новых маскировок.

Эта статья появилась в разделе "Наука и технологии" печатного издания под заголовком "Самая искренняя форма лести"

Microsoft заявляет, что новая Windows на компьютерах с процессором ARM дает вам «знакомый опыт работы с Windows». Что это значит, как это работает и что на самом деле может предложить Microsoft?

Мэри Бранскомб — технический журналист-фрилансер.

Видео: рост бизнеса благодаря цели Microsoft Windows 10

Windows 10

Windows на ARM не нова: от Windows Phone до Windows RT и Windows IoT у Microsoft было несколько систем, которые выводят Windows за рамки привычных процессоров Intel и AMD. В конце концов, старые версии Windows работали на PowerPC, Alpha, Itanium и MIPS, а в 2009 году в рамках неофициального внутреннего проекта Windows 7 работала на ARM.Продолжалась разработка 32-разрядных процессоров ARMv7 с плавающей запятой VFP, NEON (версия ARM инструкций Intel SSE для параллельной обработки данных) и набора инструкций Thumb-2.

Но когда он поставлялся как Windows RT, он запускал только приложения, которые были специально написаны и скомпилированы для ARM с использованием только WinRT API. Идея заключалась в том, чтобы превратить Windows в операционную систему, предназначенную для мобильных устройств, как и iOS, чтобы обеспечить лучшую безопасность и время автономной работы. Но отказ от запуска стандартных программ Windows — либо перекомпилированных, либо в эмуляции — был искусственным ограничением (хотя разработка устройств Windows RT только для приложений Магазина означала, что они использовали маломощные SOC Tegra, которые в любом случае не могли обеспечить хорошую производительность эмуляции).

Новые устройства Windows на ARM, которые скоро поступят в продажу, не используют тот же подход. Они используют 64-битные SOC Snapdragon 835 (которые Qualcomm называет «платформой для мобильных ПК») и могут запускать гораздо больше приложений. Хотя все первые системы, которые поступят в продажу, будут поставляться с Windows 10 S, которая запускает только приложения из Магазина, эти приложения Магазина могут включать стандартные настольные приложения x86, упакованные для распространения через Магазин. Существует также бесплатное обновление до Windows 10 Pro — не специальной или ограниченной версии Windows, а полной версии Windows 10 Pro, которую Microsoft скомпилировала для ARM.

Установите Windows 10 Pro, и вы сможете устанавливать стандартные приложения Windows, но с одним реальным ограничением: несмотря на то, что это 64-разрядная версия Windows, а Snapdragon 835 представляет собой 64-разрядный процессор Kryo, только 32-разрядные приложения x86 поддерживается -- не 64-битный код x64. Итак, как это работает и насколько хорошо это будет работать?

Windows на Windows на ARM

Сама Windows — как ядро ​​Windows, так и функции внутри Windows, такие как оболочка и Проводник, — работают как собственный код ARM 64. Так же как и системные службы NTDLL, которые позволяют приложениям взаимодействовать с ядром, и системные библиотеки DLL для хранения, графики, сети и других драйверов устройств, которые взаимодействуют с ядром, что означает, что они получают собственную аппаратную скорость. Приложения UWP из Магазина были скомпилированы в собственный код ARM, но код x86 работает в режиме эмуляции поверх уровня абстракции WOW (Windows на Windows).

Если это звучит знакомо, то это потому, что WOW уже давно существует в Windows. Первая версия представляла собой подсистему, которая преобразовывала 16-битные API в 32-битные эквиваленты (процесс, называемый «thunking») для запуска 16-битного кода в 32-битной Windows (где все 16-битные приложения работали на одной виртуальной машине). ). Windows 10 по-прежнему использует WOW для запуска 32-разрядных приложений в 64-разрядных версиях Windows — не только для перенаправления вызовов DLL, но и для отображения или зеркалирования ключей реестра из их 64-разрядных эквивалентов в 32-разрядные, регистрации соединений ODBC и предоставления 32-разрядных CMD.EXE для вызовов командной строки, чтобы создать полную 32-разрядную среду для запуска 32-разрядных приложений.

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

Asus NovaGo TP370QL (слева) и HP Envy x2 (справа): первые ноутбуки с Windows 10 S на базе ARM (Qualcomm Snapdragon 835) с функцией «всегда на связи», обеспечивающие длительное время автономной работы и встроенное подключение LTE.

Изображения: Asus, HP Inc.

Переводчик должен справляться с различиями, выходящими за рамки набора инструкций ARM, такими как порядок памяти и обработка исключений, которые различаются на процессорах RISC, таких как ARM, по сравнению с процессорами t0 Intel и AMD.

Более слабая согласованность памяти ARM означает, что многопроцессорные системы могут использовать гораздо более дешевое оборудование для кэширования, но они также должны создавать «барьеры» для сохранения порядка памяти, когда это важно — например, убедиться, что все потоки в многопоточной программе видеть правильное значение в переменной, когда она обновляется, а не некоторые из них получают старое значение, а некоторые — новое. Переводчик должен управлять этими барьерами и соблюдать баланс между добавлением такого большого количества барьеров, что эмуляция будет работать медленно, и добавлением такого небольшого количества барьеров, при котором один поток получает неверное значение переменной и код аварийно завершает работу.

Динамическая перекомпиляция работает с блоками кода, а не со всей программой, транслируя логические фрагменты кода, как их называет программа. Таким образом, он может остановиться на инструкции ветвления в коде, потому что это определит, какой код нужен дальше. Переведенный код может начать работать немедленно, вместо того, чтобы ждать, пока весь код будет готов; динамическая трансляция также дает переводчику больше информации о среде выполнения, чем статическая перекомпиляция заранее.

Как раз вовремя

Эта эмуляция перекодирования (иногда называемая Just In Time или JIT) намного быстрее, чем интерпретирующая эмуляция, при которой выполняется пошаговая обработка кода по одной инструкции за раз, по очереди моделируя каждую инструкцию процессора. Эмуляция инструкций в сотни или даже тысячи раз медленнее, чем нативный код.Своевременный перевод по-прежнему медленнее, чем запуск собственного кода — при первом запуске код может работать, возможно, в пятьдесят раз медленнее, но как только переведенный код кэшируется, он может работать со скоростью до 99 процентов от скорости. нативного кода.

Фактическая производительность будет зависеть от того, насколько приложение «привязано к вычислениям»: тратит ли оно большую часть своего времени на использование ЦП для вычислений или большую часть времени тратит на системный код и код ядра или загрузку файлов, используя сеть или рисовать графику? Первый медленнее из-за эмуляции, а все последние работают на собственной аппаратной скорости. Очевидно, что любые приложения, которые сами генерируют код, а затем запускают его, будут работать медленнее, потому что и приложение, и генерируемый им код должны быть переведены.

"Если приложение использует жесткий диск, графику или сеть, все это запускается в ядре и работает с исходной производительностью. Если приложение привязано к ЦП, оно занимает больше времени, чем исходное, потому что оно должно быть переведено. Это также зависит от приложения. В ходе нашего тестирования мы обнаружили, что большинство приложений, работающих в режиме эмуляции, соответствуют ожиданиям пользователя в отношении скорости отклика", — сообщила ZDNet генеральный менеджер Windows Эрин Чаппл.

Еще больше динамических библиотек

Один из способов, с помощью которого Windows в Windows повышает производительность 32-разрядных приложений в 64-разрядной версии Windows, — это несколько нелогичный запуск копий системных библиотек DLL, поставляемых с Windows, в виде 32-разрядного кода в режиме эмуляции.

У Microsoft есть исходный код, и она может легко перекомпилировать его в родную 64-разрядную версию заранее, но приложения, взаимодействующие с этими библиотеками DLL, используют 32-разрядные типы данных и 32-разрядные соглашения о вызовах.

Если бы библиотеки DLL были 64-разрядными, WOW пришлось бы «преобразовывать» каждый системный вызов к ним — переводить типы данных из 32-разрядных в 64-разрядные и обратно — и «упорядочивать» соглашение о вызовах в нужной памяти. представление. В системах x64 это на самом деле больше влияет на производительность, чем запуск библиотек DLL в режиме эмуляции, потому что, хотя можно автоматизировать способ маршаллинга вызовов с 32-битной на 64-битную, это сложно, а преобразование типов данных все еще проблема.

Однако в ARM запуск библиотек DLL в режиме эмуляции сопряжен с большими накладными расходами, поэтому Windows на ARM делает это преобразование несколько иначе. Собственные системные библиотеки DLL представляют собой файлы нового типа, называемые файлами CHPE (Compiled Hybrid Portable Executable). Они скомпилированы в код ARM 64 с использованием того же исходного кода, что и собственные 64-разрядные версии DLL, но хотя код соответствует ARM 64 (и система автоматизирует сортировку соглашений о вызовах), интерфейсы являются 32-разрядными x86. интерфейсы, поэтому библиотеки DLL работают с 32-разрядными типами данных, которые могут загружать процессы x86. Эта комбинация кода ARM и точек входа x86 намного эффективнее; «по большей части они работают на исходной скорости», — говорит Арун Кишан из команды ядра Windows.

Мы проверим это, когда появится доступное оборудование, но Кишан считает, что "при таком подходе вы можете получить почти или очень близкое к исходному быстродействие".

Архитектура Windows на ARM.

Изображение: Microsoft (из сборки 2017)

Вопрос о 64-битной версии

Это все, что касается 32-разрядных приложений x86, которые вы запускаете на ПК с Windows, но как насчет растущего числа 64-разрядных приложений для Windows, таких как Photoshop? Они не поддерживаются и не будут работать в Windows на ARM. Это компромисс между тем, сколько дополнительной работы потребуется для поддержки 64-разрядных приложений, и тем, насколько полезной будет эта поддержка.

"Чтобы эмулировать x64 в дополнение к x86, инженерная работа удваивается", — сказала ZDNet Эрин Чаппл. В отличие от 32-битной поддержки, это тоже будет новая работа. «Кроме того, Windows поддерживает уровень абстракции Windows в Windows (WOW) только для 32-разрядных приложений, но не для 64-разрядных приложений. Нам придется добавить поддержку 64-разрядного уровня Windows в Windows».

Кроме того, 64-разрядная эмуляция должна иметь дело с тем фактом, что процессоры x64 имеют 16 регистров общего назначения (небольшой объем быстрой памяти на процессоре, используемый для хранения текущей инструкции или данных, с которыми он работает) по сравнению с всего 8 для x86.

Хотя процессор Kryo 280 в Snapdragon 835 имеет 31 регистр общего назначения, к которым можно получить доступ как в 32-битном, так и в 64-битном режиме (64-битный код сложнее кодировать), некоторые из них зарезервированы. для конкретных вещей; сам эмулятор также должен использовать пару регистров. Обеспечение того, чтобы регистры, используемые эмулируемым кодом, оставались зафиксированными, является ключом к получению хорошей производительности эмуляции. Если эмулятор должен использовать системную память для хранения информации, которую он ожидает для загрузки в аппаратные регистры, а не иметь регистр, доступный для немедленного использования, производительность значительно упадет: инструкция, для выполнения которой требуется один цикл процессора, может выполняться десятью. , в двадцать или пятьдесят раз медленнее.

Сохранение достаточного количества регистров, выделенных для запуска эмулируемого кода, безусловно, проще для 8 регистров, используемых набором инструкций x86, чем для 16, необходимых для X64. И если сам эмулятор выполняет это распределение на языке высокого уровня, а не регистры, защищенные самой системной архитектурой, это усложняет эмуляцию, особенно когда 32-битный уровень эмуляции уже существует, а новый 64-битный уровень эмуляции уже существует. битовый слой придется писать с нуля.

Дополнительная работа и менее предсказуемая производительность могут быть бесполезны для многих людей, предположил Чаппл. «Технически это возможно, [но] это компромисс ресурсов между необходимой работой и выгодой для пользователя. Когда мы рассмотрели нашу телеметрию для наиболее часто используемых приложений в Windows, мы обнаружили, что большинство из них имеют версии x86. Многие приложения также имеют только версии x86. Большинство 64-разрядных приложений — это игры, которые не предназначены для целевого клиента для этого устройства. Наконец, те приложения, которые являются 64-разрядными, обычно хотят запускаться только для соображений производительности. В результате мы решили сосредоточить наши инженерные инвестиции на родном SDK ARM64, чтобы дать разработчикам возможность писать свои приложения для устройства нативно."

Если разработчики хотят, чтобы их код x64 сразу запускался в Windows на ARM, им нужно вместо этого скомпилировать его для x86, а если они используют Desktop Bridge для размещения этих приложений в Магазине, им необходимо отправить версию x86, чтобы иметь он работает на Windows на ARM. Это относится даже к установщикам, что может быть проблемой для некоторых приложений.

Microsoft никогда не прекращала создавать 32-разрядные версии Windows: в 2015 году тогдашний глава программы Windows Insider Гейб Аул заявил, что существуют «сотни миллионов 32-разрядных ПК», которые можно обновить до Windows 10.

Несмотря на это, некоторые разработчики перешли исключительно на x64 из соображений безопасности, увеличения памяти или производительности. И даже 32-разрядные приложения иногда имеют 64-разрядный установщик, поэтому вы можете установить 32- или 64-разрядный код по своему выбору. Например, программа установки Creative Cloud больше не устанавливает 32-разрядную версию Photoshop; вы скачали его отдельно, и он помечен как версия 2014 года.

Чэппл подтвердила, что 64-разрядные установщики не будут работать в Windows на ARM, хотя и отметила, что "это не тот сценарий, с которым мы сталкивались при тестировании лучших приложений".

64 года

В долгосрочной перспективе появится способ перенести 64-разрядные приложения для ПК на Windows на ARM. Разработчики, которым нужны 64-разрядные функции, такие как доступ к большему объему памяти и 64-разрядным виртуальным адресам, смогут использовать Windows SDK для Windows 10 ARM 64 и компилировать свой код непосредственно в 64-разрядный код ARM, избегая даже незначительного снижения производительности эмуляция. Если вы пишете код на C++, вы можете поэкспериментировать с ним прямо сейчас, хотя шаблонов проектов нет и требуется определенная настройка. Вы пока не можете отправить эти приложения в Магазин, поэтому они будут работать только на Windows 10 Pro на ARM, а не на устройствах с Windows 10 S.

Будет ли SDK включать поддержку таких функций, как WinForms, для которых требуется настольная версия .NET? «Мы все еще работаем над нашими планами ARM64 SDK, включая то, какие версии .NET будут поддерживаться», — сказал Чаппл.

Microsoft также сделала несколько интересных решений для своих собственных приложений.

Браузер Edge — это 32-разрядное приложение ARM для Windows на ARM, которое изначально работает, хотя и переключается на ARM64 (это может означать, что поддержка всего, что ему нужно, теперь есть только в Windows ARM64 SDK). «Если вы присоединитесь к программе предварительной оценки Windows с устройством Windows на ARM, вы увидите, что MS Edge перешел на 64-разрядную версию», — сказал Чаппл.

Internet Explorer и Office, с другой стороны, являются приложениями x86: подключаемые модули и надстройки в подавляющем большинстве являются 32-разрядными, поэтому имеет смысл оставить приложения x86, тем более, что большая часть того, что делает Office, не зависит от процессора. интенсив.

Настольные приложения явно являются частью будущего Windows, что должно успокоить тех, кто думает, что Microsoft пытается перевести всех на UWP. Но пока они только 32-разрядные, это дает Windows на ARM очень четкую позицию, и она сильно отличается от того, как Apple рассматривает iPad Pro.

Несмотря на растущую производительность и возможности процессоров ARM, Windows на ARM предназначена для того, чтобы предоставить вам доступное и очень мобильное устройство с упором на время автономной работы и встроенный LTE для подключения, а не пытаться конкурировать с Intel в 64-разрядных версиях. Производительность ПК.

ПРЕДЫДУЩИЙ И СВЯЗАННЫЙ КОНТЕНТ

Microsoft, HP, Asus запускают большой эксперимент Windows на ARM и Qualcomm: вот ключевые вопросы

Цены на устройства с Windows 10 S, работающие на процессоре Qualcomm Snapdragon, вызывают несколько интересных вопросов. Вот краткий обзор неизвестного:

Microsoft представляет Windows 10 на устройствах ARM

Microsoft и Qualcomm демонстрируют первую Windows 10 на устройствах ARM, которые обеспечивают совместимость приложений Win32 посредством эмуляции. Однако большинство моделей не будет доступно до следующей весны.

В ноутбуках с Windows 10 будет использоваться аппаратное обеспечение, обычно используемое в мобильных телефонах, — чипсет Qualcomm Snapdragon 835 на базе ARM, чтобы обеспечить постоянное подключение и более длительное время автономной работы смартфонов на ноутбуках.

Что? вы можете сделать это в линуксе? Оказывается можно!

Во-первых, давайте посмотрим на это в действии. Здесь я извлекаю двоичный файл из моего Raspberry Pi, который является двоичным файлом ARM, и прозрачно запускаю его на моем компьютере x86_64.

Если вы попытаетесь сделать это... сразу это не сработает.

Сначала нам нужно настроить пару вещей. Мы будем использовать QEMU немного нетрадиционным способом в сочетании с функцией ядра под названием binfmt_misc.

Режим пользователя QEMU

Очевидно, что наш ЦП не может выполнять инструкции чужого машинного кода. Мы сказали, что будем использовать QEMU, но несколько нетрадиционным способом.

Мы все знаем QEMU как виртуальную машину, где мы загружаем виртуальный (поддельный) жесткий диск с операционной системой и настраиваем поддельное оборудование для взаимодействия с ним: поддельный процессор, поддельную клавиатуру, поддельный сетевой адаптер и т. д. Это выглядит так

Но есть и другой режим использования в QEMU, который называется эмуляция пользователя.

Когда мы пишем программу, мы взаимодействуем с системой через системные вызовы. Нам нужно сделать это, чтобы взаимодействовать с клавиатурой, терминалом, экраном, файловой системой и так далее. Это означает, что когда мы выполняем программу, код, который мы пишем, выполняется в пользовательском пространстве, а затем ядро ​​взаимодействует с системной частью за нас. Мы просто запрашиваем у ядра такие вещи, как запись в файл.

В QEMU эмуляция системы это выглядит так

В режиме пользователя QEMU эмулирует не все оборудование, а только ЦП. Он выполняет чужой код в эмулируемом ЦП, а затем перехватывает системные вызовы и перенаправляет их в ядро ​​хоста. Таким образом, мы взаимодействуем с собственным ядром так же, как и с любым родным программным обеспечением. Это выглядит так

Это имеет много преимуществ, потому что мы не эмулируем все оборудование, которое работает медленно, а также мы не эмулируем ядро, которое является приличной частью выполняемых вычислений. На самом деле нам даже не нужно ядро. Теперь мы можем понять, почему это работает намного быстрее, чем полная эмуляция системы.

В качестве примера давайте перекомпилируем статический двоичный файл ARM

нам нужно установить набор инструментов для кросс-компиляции из x86 в armhf, например

или в Arch Linux

Затем мы генерируем двоичный файл

Теперь мы можем запустить его с помощью qemu-arm. Нам нужно установить пакет qemu-user

, и теперь мы можем бежать

Это пока не очень полезно, поскольку большинство программ динамически связаны. У нас еще есть над чем поработать.

Прозрачный запуск исполняемых файлов ARM

Вспомните из последней публикации об исполняемых файлах Linux, что происходит, когда мы запускаем файл, и как мы можем использовать binfmt_misc для настройки наших собственных интерпретаторов. Теперь у нас есть все части, и мы хотим собрать их вместе. Нам нужно настроить binfmt_misc, чтобы использовать пользовательский режим QEMU в качестве интерпретатора нашего двоичного формата.

Мы можем сделать это сами вручную или установить пакет qemu-user-binfmt, который обычно устанавливается автоматически вместе с qemu-user. Мы получаем записи binfmt_misc

Теперь мы можем заменить

, потому что у нас есть активная запись в binfmt_misc

Ядро распознает магию ARM ELF и использует интерпретатор /usr/bin/qemu-arm-static , который является правильным двоичным кодом QEMU для данной архитектуры. 0x7F ‘ELF’ в шестнадцатеричном формате – это 7f 45 4c 46 , поэтому мы можем увидеть, как магия и маска работают вместе, учитывая структуру заголовка ELF

В конце концов, мы хотим, чтобы наш код сообщал ядру, что нужно напечатать hello world. Давайте сравним взаимодействие ядра с реальными

и эмулируемый код

Системный вызов execve() такой же, как и вызов write(), поэтому мы получаем такое же поведение. Мы также можем видеть, что чтение /proc/self/exe показывает, что исполняемый двоичный файл, запускаемый изначально, на самом деле является qemu-arm-static, интерпретатором.

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

Это еще не настолько полезно, потому что очень немногие программы связаны статически. Давайте создадим x86 и amrhf версии hello.c

.

Двоичные файлы ARM занимают гораздо больше места, поскольку архитектура RISC имеет меньший набор инструкций, поэтому для выполнения многих распространенных операций требуется больше машинного кода. Плотность кода можно повысить, используя набор инструкций THUMB.

Исполняемые файлы с динамической компоновкой предоставляют путь к компоновщику среды выполнения (также известному как интерпретатор ELF), жестко запрограммированному во время компиляции.

Поэтому код не работает, потому что не может найти компоновщик, который ему требуется /lib/ld-linux-armhf.so.3. Обычно это идет с кросс-инструментальной цепочкой.

У нас может возникнуть соблазн сделать что-то действительно грязное, например

Нам нужно будет сделать это не только для ld-linux-armhf.so, но и для libc.so и всего остального, что может понадобиться нашему двоичному файлу, и мы не хотите иметь в одном месте несколько библиотек разных архитектур, верно?

Мы можем указать QEMU, где искать компоновщик и библиотеки с помощью

но нам нужно прозрачное выполнение, поэтому мы можем добавить это в .bashrc или .zshrc

или настройте его для всей системы в /etc/qemu-binfmt.conf

.

Теперь это работает прозрачно!

Это все еще не настолько полезно. Причина в том, что теперь нам нужны копии всех библиотек ARM, необходимых для наших двоичных файлов ARM.

Наш пример работает, потому что все, что нужно hello.c, настолько простое, что поставляется с цепочкой инструментов.

Ситуация не так уж плоха в Debian, где вы можете, например, установить библиотеки из других архитектур

Эмуляция полных корневых файлов ARM

Чаще всего в реальных ситуациях нам нужно работать в конечной системе, в которой должен работать бинарник. Имеет больше смысла иметь всю среду ARM с ее библиотеками ARM и всем остальным. Войдите в chroot.

chroot, для change root — это системный вызов и соответствующая оболочка команды, которая изменяет местоположение корневого каталога процесса и его дочерних элементов. Имея каталог с другой корневой файловой системой, мы можем выполнить в нем что угодно, чтобы их представление файловой системы было перемещено в новый корневой каталог. По этой причине его часто называют тюрьмой chroot. Это предшественник пространств имен файловой системы, ключевой компонент, делающий возможным использование контейнеров.

В качестве примера давайте выполним echo в тюрьме x86. Я подготовил целую файловую систему Debian в новой_корневой_папке .

Это echo или любой другой исполняемый файл, который мы запускаем, ничего не видит за пределами тюрьмы. Например, невозможно удалить или прочитать файл за пределами новой корневой папки.

Мы можем получить существующую корневую файловую систему ARM для работы или создать ее. В Debian мы можем использовать debootstrap с ключом –arch для создания корневой файловой системы Stretch ARM.

Что мы хотим сделать сейчас, так это использовать chroot, чтобы двоичные файлы внутри тюрьмы отображали файловую систему так, как они этого ожидают. При использовании chroot у нас уже есть /etc, /bin и все обычные папки. Далее нам нужно добавить виртуальные файловые системы

Наконец, мы скопируем двоичный файл qemu-user-static в файловую систему ARM.

Этот маленький злоумышленник будет единственным двоичным файлом x86 в файловой системе ARM, он окружен!

У нас все на месте! Что произойдет, когда мы попытаемся запустить какой-нибудь исполняемый файл ARM из джейла?

  • Команда chroot вызовет execve() для двоичного файла ARM
  • Двоичный файл ARM будет обрабатываться бинарным обработчиком binfmt_misc в соответствии с его настроенной магией ARM ELF.
  • Запись в binfmt_misc указывает ядру использовать /usr/bin/qemu-arm-static в качестве интерпретатора, поэтому нам пришлось скопировать ее внутрь тюрьма. Помните, что благодаря магии chroot /usr/bin действительно находится внутри новой_корневой_папки.
  • qemu-arm-static интерпретирует двоичный файл ARM в пользовательском режиме. Мы используем статическую версию qemu-arm, потому что нам нужен автономный интерпретатор, так как это единственный двоичный файл x86 в тюрьме, и у него не будет доступа ни к каким библиотекам x86.
  • Любая библиотека ARM, ожидаемая программами внутри тюрьмы, будет там, как это предусмотрено корневой файловой системой ARM.

Давайте посмотрим на все это в действии, открыв оболочку bash в Raspbian rootfs

Мне пришлось настроить переменную PATH, чтобы она соответствовала той, которую ожидает Raspbian. Естественно, наша исходная среда от zsh будет унаследована chroot и arm-bash.Мы уже говорили о полносистемной эмуляции QEMU Raspbian раньше, и она работает намного быстрее.

Все будет работать до тех пор, пока двоичные файлы ARM будут видеть то, что они ожидают увидеть. Двоичные файлы могут execve() запускать другие исполняемые файлы, и в основном все будет работать отлично. Исключение составляют программы, использующие экзотические системные вызовы, которые еще не реализованы в пользовательском режиме QEMU, например, для использования псевдослучайного генератора. По мере того, как пользовательский режим QEMU становится более зрелым, становится все более странно видеть, как это происходит, и обычно в библиотеках в любом случае есть резервные варианты для таких ситуаций. В этих случаях вы увидите что-то вроде

Помните, что мы все еще используем наше ядро хоста, поэтому мы можем использовать сеть, устанавливать пакеты с помощью apt и все остальное. Это действительно полезно для таких вещей, как

Читайте также: