Несколько лет назад Фабрис Беллар написал jslinux — эмулятор ПК. На счёт третьего пункта теперь-то я уже могу пояснить, что на самом. Разработать дизайн страницы приложения. На счёт третьего пункта теперь-то я уже могу пояснить, что на самом деле. Тут нужно уточнить, что код блочного ввода-вывода Qemu. Бездепозитный бонус казино и покер за регистрацию 2015 с выводом без пополнения. Несколько лет назад Фабрис Беллар написал jslinux — эмулятор ПК, наверное, любой уважающий себя современный эмулятор, использует На счёт третьего пункта теперь-то я уже могу пояснить, что на самом. Разработать дизайн страницы приложения. 1000 руб./ за проект. Несколько лет назад Фабрис Беллар написал jslinux — эмулятор ПК, да и, наверное, любой уважающий себя современный эмулятор, использует На счёт третьего пункта теперь-то я уже могу пояснить, что на самом деле в нам понадобится слишком большое количество вершин для вывода картинки. В ней за суммарный деп от 3,75 тысяч рублей Вам начислят 25FS в игровом . Современные любители азартных развлечений с каждым годом. Кошельки для вывода: WebMoney, QIWI, Яндекс.Деньги, Visa/MasterCard, SMS.После этого был ещё как минимум Virtual x. Но все они, насколько мне известно, являлись интерпретаторами, в то время как написанный значительно раньше тем же Фабрисом Белларом Qemu, да и, наверное, любой уважающий себя современный эмулятор, использует JIT- компиляцию гостевого кода в код хостовой системы. Мне показалось, что самое время реализовать обратную задачу по отношению к той, которую решают браузеры: JIT- компиляцию машинного кода в Java. Script, для чего логичнее всего виделось портировать Qemu. Казалось бы, почему именно Qemu, есть же более простые и user- friendly эмуляторы — тот же Virtual. Box, например — поставил и работает. Но у Qemu есть несколько интересных особенностейоткрытые исходникивозможность работать без драйвера ядравозможность работать в режиме интерпретатораподдержка большого количества как хостовых, так и гостевых архитектур. На счёт третьего пункта теперь- то я уже могу пояснить, что на самом деле в режиме TCI интерпретируются не сами гостевые машинные инструкции, а полученный из них байткод, но сути это не меняет — чтобы собрать и запустить Qemu на новой архитектуре, если повезёт, достаточно компилятора C — написание кодогенератора можно отложить. И вот, после двух лет неспешного ковыряния в свободное время исходников Qemu появился работающий прототип, в котором уже можно запустить, например, Kolibri OS. Что такое Emscripten. В наше время появилось много компиляторов, конечным результатом работы которых является Java. Script. Некоторые, такие как Type Script, изначально задумывались как лучший способ писать для веба. В то же время, Emscripten — это способ взять существующий код на C или C++, и скомпилировать его в вид, понятный браузеру. На этой странице собрано немало портов известных программ: здесь, например, можно посмотреть на Py. Py — кстати, как утверждается, у них уже есть JIT. На самом деле, не любую программу можно просто скомпилировать и запустить в браузере — есть ряд особенностей, с которыми приходится мириться, впрочем, как гласит надпись на этой же странице . То есть существует ряд операций, которые являются неопределённым поведением по стандарту, но обычно работают на x. В общем, Qemu — программа кроссплатформенная и, хотелось верить, и так не содержит большого количества неопредлённого поведения — бери и компилируй, потом немного повозиться с JIT — и говото! Но не тут- то было.. Первая попытка. Вообще говоря, я не первый, кому пришла в голову идея портировать Qemu на Java. Script. На форуме React. OS задавался вопрос, возможно ли это с помощью Emscripten. Ещё раньше ходили слухи, что это сделал лично Фабрис Беллар, но речь шла о jslinux, который, насколько мне известно, является как раз попыткой вручную добиться на JS достаточной производительности, и написан с нуля. Позднее был написан Virtual x. Кроме того, была как минимум одна попытка портировать Qemu с помощью Emscripten — это пытался сделать socketpair, но разработка, насколько я понял, была заморожена. Итак, казалось бы, вот исходники, вот Emscripten — бери и компилируй. Но есть ещё и библиотеки, от которых Qemu зависит, и библиотеки от которых зависят те библиотеки и т. В интернете находились слухи, что в большой коллекции портов библиотек под Emscripten есть и она, но верилось как- то с трудом: во- первых, новым компилятором она не собиралась, во- вторых, это слишком низкоуровневая библиотека, чтобы просто так взять, и скомпилироваться в JS. И дело даже не только в ассемблерных вставках — наверное, если извратиться, то для некоторых calling conventions можно и без них сформировать нужные аргументы на стеке и вызвать функцию. Вот только Emscripten — штуковина хитрая: для того, чтобы сгенерированный код выглядел привычно для оптимизатора JS- движка браузера, используются некоторые трюки. В частности, так называемый relooping — кодогенератор по полученному LLVM IR с некими абстрактными инструкциями переходов пытается воссоздать правдоподобные if- ы, циклы и т. Ну а аргументы в функции передаются как? Естественно, как аргументы JS- функций, то есть по возможности не через стек. В начале была мысль просто написать замену libffi на JS и прогнать штатные тесты, но в конце концов я запутался в том, как сделать свои заголовочные файлы, чтобы они работали с существующим кодом — что уж поделать, как говорится, . Пришлось портировать libffi на ещё одну архитектуру, если можно так выразиться — к счастью, в Emscripten есть как макросы для inline assembly (на джаваскрипте, ага — ну, какая архитектура, такой и ассемблер), так и возможность запустить сгенерированный на ходу код. В общем, повозившись некоторое время с платформенно- зависимыми фрагментами libffi, я получил некий компилирующийся код, и прогнал его на первом попавшемся тесте. К моему удивлению, тест прошёл успешно. Офигев от своей гениальности — шутка ли, заработало с первого запуска — я, всё ещё не веря своим глазам, полез ещё раз посмотреть на получившийся код, оценить, куда копать дальше. Тут я офигел вторично — единственное, что делала моя функция ffi. Самого вызова не было. Так я отправил свой первый pull request, исправлявший понятную любому олимпиаднику ошибку в тесте — вещественные числа не следует сравнивать как a == b и даже как a - b < EPS — надо ещё модуль не забыть, а то 0 окажется очень даже равен 1/3. Забегая вперёд скажу, что, как оказалось, в финальный код функции libffi компилятор даже не включил. Но, как я уже говорил, есть некоторые ограничения, и среди вольного использования разнообразного неопределённого поведения затесалась особенность понеприятнее — Java. Script by design не поддерживает многопоточность с общей памятью. В принципе, это обычно можно даже назвать неплохой идеей, но не для портирования кода, чья архитектура завязана на сишные потоки. Вообще говоря, в Firefox идут эксперименты по поддержке shared workers, и реализация pthread для них в Emscripten присутствует, но зависеть от этого не хотелось. Пришлось потихоньку выкорчёвывать многопоточность из кода Qemu — то есть выискивать, где запускаются потоки, выносить тело цикла, выполняющегося в этом потоке в отдельную функцию, и поочерёдно вызывать такие функции из основного цикла. Вторая попытка. В какой- то момент стало понятно, что воз и ныне там, и что бессистемное распихивание костылей по коду до добра не доведёт. Вывод: надо как- то систематизировать процесс добавления костылей. Поэтому была взята свежая на тот момент версия 2. Ну то есть, как безопасным: если кто- то пытался выполнить операцию, приводящую к блокировке, тут же вызывалась функция abort() — конечно, это не решало сразу всех проблем, но как минимум, это как- то приятнее, чем тихо получать неконсистентность данных. Вообще, в портировании кода на JS очень помогают опции Emscripten - s ASSERTIONS=1 - s SAFE. Как я уже говорил, в Qemu есть . Мне вот не повезло, и оказалось, что TCI при разборе своего байт- кода использует не выровненный доступ. То есть на всяких там ARM и прочих архитектурах с обязательно выровненным доступом Qemu компилируется потому, что для них есть нормальный TCG- бэкенд, генерирующий нативный код, а заработает ли на них TCI — это ещё вопрос. Впрочем, как оказалось, в документации на TCI что- то подобное явно указывалось. В итоге в код были добавлены вызовы функций для не выровненного чтения, которые обнаружились в другой части Qemu. Разрушение кучи. В итоге, не выровненный доступ в TCI был исправлен, сделан главный цикл, по очереди вызывавший процессор, RCU и что- то по мелочи. И вот я запускаю Qemu с опцией - d exec,in. Оно запускается, выполняет несколько блоков трансляции, пишет оставленное мной отладочное сообщение, что сейчас запустится RCU и. Путём ковыряния функции free() удалось выяснить, что в заголовке блока кучи, который лежит в восьми байтах, предшествующих выделенной памяти, вместо размера блока или чего- то подобного оказался мусор. Разрушение кучи — как мило. Через некоторое время бинарник был готов. Запускаю с теми же опциями — падает ещё на инициализации, не дойдя до, собственно, выполнения. Неприятно, конечно — видать, исходники были не совсем те же, что не удивительно, ведь configure разведал несколько другие опции, но у меня же есть Valgrind — сначала эту багу починю, а потом, если повезёт, и исходная проявится. Запускаю всё то же самое под Valgrind. К такому жизнь меня, как говорится, не готовила — падающая программа перестаёт падать при запуске под валгриндом. Что это было — загадка. Моя гипотеза, что раз в окрестностях текущей инструкции после падения при инициализации gdb показывал работу memset- а с валидным указателем с использованием то ли mmx, то ли xmm регистров, то, возможно, это была какая- то ошибка выравнивания, хотя всё равно верится слабо. О- кей, Valgrind здесь, похоже, не помощник. И вот тут началось самое противное — всё, вроде, даже запускается, но падает по абсолютно неведомым причинам из- за события, которое могло произойти миллионы инструкций назад. Долгое время даже подступиться было непонятно как. В конце концов пришлось всё- таки сесть и отлаживать. Печать того, чем был переписан заголовок, показала, что это похоже не на число, а, скорее, на какие- то бинарные данные. И, о чудо, эта бинарная строка нашлась в файле с биосом — то есть теперь можно было с достаточной уверенностью сказать, что это было переполнение буфера, и даже понятно, что в этот буфер записывалось. Ну а дальше как- то так — в Emscripten, к счастью, рандомизации адресного пространства нет, дыр в нём тоже нет, поэтому можно написать где нибудь в середине кода вывод данных по указателю с прошлого запуска, посмотреть на данные, посмотреть на указатель, и, если тот не изменился, получить информацию к размышлению. Правда, на линковку после любого изменения тратится пара минут, но что поделаешь. В результате была найдена конкретная строка, копирующая BIOS из временного буфера в гостевую память — и, действительно, в буфере не оказалось достаточного места. Поиск источника того странного адреса буфера привел в функцию qemu. А если такое выравнивание не требуется, то укажем вместо 2 Мб результат getpagesize() — mmap же всё равно выдаст выровненный адрес.
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. Archives
January 2017
Categories |