QEMU.js: ҳоло ҷиддӣ ва бо WASM

Боре ман барои масхара қарор додам баргардонидани процессро исбот мекунанд ва омӯзед, ки чӣ тавр тавлид кардани JavaScript (дақиқтараш, Asm.js) аз рамзи мошин. QEMU барои таҷриба интихоб карда шуд ва пас аз чанде дар бораи Ҳабр мақола навишта шуд. Дар шарҳҳо ба ман маслиҳат доданд, ки лоиҳаро дар WebAssembly аз нав созам ва ҳатто худамро тарк кунам кариб ба охир расид Ман гӯё лоиҳаро намехостам... Кор идома дошт, вале хеле суст ва ҳоло, ба наздикӣ дар он мақола пайдо шуд Шарҳҳо дар мавзӯи «Пас, ҳамааш чӣ гуна анҷом ёфт?» Дар посух ба ҷавоби муфассали худ ман шунидам, ки "Ин ба мақолае монанд аст." Хуб, агар тавонед, мақолае мешавад. Шояд касе онро муфид пайдо кунад. Аз он хонанда баъзе далелҳоро дар бораи тарҳрезии пуштибонии тавлиди коди QEMU ва инчунин чӣ гуна навиштани компилятори Just-in-Time барои веб-барнома меомӯзад.

вазифаҳо

Азбаски ман аллакай фаҳмидем, ки чӣ гуна порти QEMU-ро ба JavaScript "ба гунае" омӯхтам, ин дафъа тасмим гирифта шуд, ки ин корро оқилона анҷом диҳам ва хатогиҳои кӯҳнаро такрор накунам.

Хатогии рақами як: филиал аз нуқтаи озод

Аввалин хатои ман ин буд, ки версияи худро аз версияи болоравии 2.4.1. Он гоҳ ба назари ман як идеяи хубе менамуд: агар релизи нуқта вуҷуд дошта бошад, пас он эҳтимолан аз 2.4 оддӣ устувортар аст ва ҳатто бештар аз он филиал. master. Ва азбаски ман нақша доштам, ки миқдори одилонаи хатогиҳои худамро илова кунам, ба ман умуман ба ягон каси дигар эҳтиёҷ надоштам. Шояд хамин тавр шуд. Аммо ин аст, ки QEMU дар ҷои худ намеистад ва дар баъзе лаҳзаҳо онҳо ҳатто 10 фоиз оптимизатсияи коди тавлидшударо эълон карданд: "Бале, ҳоло ман ях мекунам" ман фикр кардам ва шикастам. Дар ин ҷо мо бояд як риштаро анҷом диҳем: аз сабаби хусусияти як риштаи QEMU.js ва он, ки QEMU аслӣ мавҷуд набудани чанд риштаро дар назар надорад (яъне қобилияти дар як вақт кор кардани якчанд роҳҳои коди ба ҳам алоқаманд ва на танҳо "ҳамаи ядроҳоро истифода баред") барои он муҳим аст, вазифаҳои асосии риштаҳо ман бояд онро "берун" кунам, то аз берун занг занам. Ин ҳангоми якҷояшавӣ баъзе мушкилоти табииро ба вуҷуд овард. Аммо, дар он аст, ки баъзе тагьирот аз филиал master, ки бо он ман кӯшиш кардам, ки коди худро якҷоя кунам, инчунин гелос дар релизи нуқтаи интихобшуда (ва аз ин рӯ дар филиали ман) низ эҳтимолан бароҳатӣ илова намекард.

Умуман, ман тасмим гирифтам, ки партофтани прототип, ба қисмҳо ҷудо кардани он ва сохтани версияи нав аз сифр дар асоси чизи тару тоза ва ҳоло аз он маъно дорад. master.

Хатогии рақами дуюм: методологияи TLP

Аслан, ин хато нест, дар маҷмӯъ, ин танҳо як хусусияти эҷоди лоиҳа дар шароити нофаҳмии пурраи ҳам "ба куҷо ва чӣ гуна бояд ҳаракат кард?" ва умуман "мо ба он ҷо мерасем?" Дар ин шароит барномасозии бесамар як варианти асоснок буд, аммо, табиист, ки ман намехостам онро такрор кунам. Ин дафъа ман мехостам, ки онро оқилона иҷро кунам: иҷроиши атомӣ, тағир додани коди огоҳона (ва на "ҳамбаста кардани аломатҳои тасодуфӣ то тартиб додани он (бо огоҳиҳо)", тавре ки Линус Торвалдс боре дар бораи касе гуфта буд, тибқи Википедиа) ва ғайра.

Хатогии рақами се: бе надонистани гузаргоҳ ба об даромадан

Ман то ҳол аз ин пурра халос нашудаам, аммо ҳоло ман қарор додам, ки роҳи камтарин муқовиматро риоя накунам ва онро бо "роҳи калонсол" иҷро кунам, яъне пуштибонии TCG-и худро аз сифр нависед, то ин ки не. бояд баъдтар бигӯям: "Бале, ин албатта оҳиста аст, аммо ман ҳама чизро идора карда наметавонам - TCI ҳамин тавр навишта шудааст ..." Гузашта аз ин, ин дар аввал як роҳи ҳалли возеҳ менамуд, зеро Ман рамзи дуӣ тавлид мекунам. Чунон ки мегуянд, «Гент чамъ омаду, аммо на он": рамз, албатта, дуӣ аст, аммо назоратро ба он интиқол додан мумкин нест - он бояд ба таври возеҳ ба браузер барои тартиб додан тела дода шавад, ки дар натиҷа объекти муайян аз ҷаҳони JS, ки то ҳол бояд дар ҷое наҷот ёбад. Аммо, дар меъмории муқаррарии RISC, то ҷое ки ман мефаҳмам, вазъияти маъмулӣ зарурати ба таври возеҳ барқарор кардани кэши дастур барои рамзи барқароршуда мебошад - агар ин ба мо лозим набошад, пас, дар ҳар сурат, он наздик аст. Илова бар ин, аз кӯшиши охирини худ ман фаҳмидам, ки назорат ба мобайни блоки тарҷума интиқол дода намешавад, аз ин рӯ ба мо аслан лозим нест, ки байткоди тафсир аз ягон офсет тафсир карда шавад ва мо метавонем онро танҳо аз функсияи ТБ тавлид кунем. .

Онхо омада лагад заданд

Гарчанде ки ман дар моҳи июл ба дубора навиштани код шурӯъ кардам, як зарбаи ҷодугарӣ нодида гирифт: одатан номаҳо аз GitHub ҳамчун огоҳинома дар бораи посухҳо ба саволҳо ва дархостҳо меоянд, аммо дар ин ҷо, ногаҳон зикр дар ришта Binaryen ҳамчун пуштибони qemu дар контекст, "Ӯ чунин кард, шояд чизе бигӯяд." Мо дар бораи истифодаи китобхонаи марбути Emscripten сӯҳбат мекардем Бинарйен барои сохтани WASM JIT. Хуб, ман гуфтам, ки шумо дар он ҷо литсензияи Apache 2.0 доред ва QEMU дар маҷмӯъ таҳти GPLv2 тақсим карда мешавад ва онҳо чандон мувофиқ нестанд. Ногаҳон маълум шуд, ки иҷозатнома метавонад бошад онро бо ягон роҳ ислоҳ кунед (Ман намедонам: шояд онро тағир диҳам, шояд иҷозатномадиҳии дугона, шояд чизи дигар ...). Ин, албатта, маро шод кард, зеро то он вакт ман аллакай ба он бодиккат назар карда будам формати дуӣ WebAssembly, ва ман гӯё ғамгин ва нофаҳмо будам. Инчунин китобхонае мавҷуд буд, ки блокҳои асосиро бо графики гузариш мехӯрад, байткодро тавлид мекунад ва ҳатто агар лозим бошад, онро дар худи тарҷумон иҷро мекард.

Он гоҳ бештар буд нома дар рӯйхати почтаи QEMU, аммо ин бештар дар бораи саволи "Ба ҳар ҳол ба кӣ лозим аст?" Ва он аст ногаҳон, маълум шуд, ки зарур аст. Ҳадди ақал, шумо метавонед имконоти зерини истифодаро якҷоя кунед, агар он зудтар ё камтар кор кунад:

  • бе ягон насбкунӣ ягон чизи таълимӣ оғоз кунед
  • виртуализатсия дар iOS, ки тибқи овозаҳо, ягона барномае, ки ҳуқуқи тавлиди кодро дар парвоз дорад, муҳаррики JS мебошад (оё ин дуруст аст?)
  • намоиши мини-OS - як дискет, дарунсохт, ҳама намуди нармафзор ва ғайра...

Хусусиятҳои кори браузер

Тавре ки ман аллакай гуфтам, QEMU ба мултипликатсия алоқаманд аст, аммо браузер онро надорад. Хуб, яъне не... Дар аввал он тамоман вуҷуд надошт, баъд WebWorkers пайдо шуд - то ҷое ки ман мефаҳмам, ин бисёрсоҳавӣ дар асоси интиқоли паём аст. бе тағирёбандаҳои муштарак. Табиист, ки ин ҳангоми интиқоли коди мавҷуда дар асоси модели хотираи муштарак мушкилоти ҷиддиро ба вуҷуд меорад. Баъдан зери фишори мардум он ҳам бо ном амалӣ шуд SharedArrayBuffers. Он тадриҷан ҷорӣ карда шуд, онҳо дар браузерҳои гуногун ифтитоҳи онро ҷашн гирифтанд, баъд Соли навро ҷашн гирифтанд ва сипас Meltdown... Баъд аз ин онҳо ба хулосае омаданд, ки андозагирии вақт дағал ё дағал, вале бо ёрии хотираи муштарак ва як ришта афзояндаи ҳисобкунак, ҳамааш якхела аст он хеле дақиқ кор хоҳад кард. Ҳамин тавр, мо мултипликатсияро бо хотираи муштарак ғайрифаъол кардем. Чунин ба назар мерасад, ки онҳо баъдтар онро дубора ба кор андохтанд, аммо, тавре ки аз таҷрибаи аввал маълум шуд, ҳаёт бе он вуҷуд дорад ва агар ин тавр бошад, мо кӯшиш хоҳем кард, ки онро бидуни такя ба чанд ришта иҷро кунем.

Хусусияти дуюм имконнопазирии коркарди сатҳи паст бо стек мебошад: шумо наметавонед танҳо контексти ҷорӣро гиред, захира кунед ва бо стек нав ба контексти нав гузаред. Стеки зангҳо аз ҷониби мошини виртуалии JS идора карда мешавад. Чунин ба назар мерасад, ки мушкил дар чист, зеро мо то ҳол тасмим гирифтем, ки ҷараёнҳои қаблиро комилан дастӣ идора кунем? Далели он аст, ки блоки I/O дар QEMU тавассути корутинҳо амалӣ карда мешавад ва дар ин ҷо манипуляцияҳои стекҳои сатҳи паст муфид хоҳанд буд. Хушбахтона, Emscipten аллакай механизми амалиёти асинхронӣ дорад, ҳатто ду: Асинфикатсия и Тарҷумон. Якум тавассути варамкунии назаррас дар коди тавлидшудаи JavaScript кор мекунад ва дигар дастгирӣ намешавад. Дуюм "роҳи дуруст"-и ҷорӣ аст ва тавассути тавлиди байткод барои тарҷумони ватанӣ кор мекунад. Он, албатта, оҳиста кор мекунад, аммо он кодро варам намекунад. Дуруст аст, ки дастгирии корутинҳо барои ин механизм мебоист мустақилона саҳм гузошта мешуд (аллакай корутинҳо барои Asyncify навишта шуда буданд ва татбиқи тақрибан ҳамон API барои Emterpreter вуҷуд дошт, шумо танҳо лозим буд, ки онҳоро пайваст кунед).

Дар айни замон, ман то ҳол натавонистам, ки кодро ба коди дар WASM тартибдодашуда тақсим кунам ва бо истифода аз Emterpreter тафсир кунам, аз ин рӯ дастгоҳҳои блок ҳанӯз кор намекунанд (ба силсилаи навбатӣ нигаред, чунон ки мегӯянд...). Яъне, дар ниҳоят шумо бояд чизе ба монанди ин чизи қабати хандовар ба даст оред:

  • блоки I/O тафсиршуда. Хуб, оё шумо воқеан интизор будед, ки NVMe-и тақлидшуда бо иҷрои аслӣ? 🙂
  • рамзи асосии QEMU статикӣ тартиб додашуда (тарҷумон, дигар дастгоҳҳои эмулятсия ва ғайра)
  • рамзи меҳмонони динамикӣ ба WASM тартиб дода шудааст

Хусусиятҳои сарчашмаҳои QEMU

Тавре ки шумо аллакай тахмин кардаед, рамзи тақлид кардани меъмории меҳмонон ва рамзи тавлиди дастурҳои мошини мизбон дар QEMU ҷудо карда шудаанд. Дар асл, ин ҳатто каме душвортар аст:

  • меъмории мехмонон мавчуданд
  • аст суръатдиҳандагон, яъне KVM барои виртуализатсияи сахтафзор дар Linux (барои системаҳои меҳмонон ва мизбон бо ҳамдигар мувофиқ), TCG барои тавлиди коди JIT дар ҳама ҷо. Аз QEMU 2.9 сар карда, дастгирии стандарти виртуализатсияи сахтафзори HAXM дар Windows пайдо шуд (тафсилот)
  • агар TCG истифода шавад, на виртуализатсияи сахтафзор, он гоҳ он барои ҳар як меъмории мизбон ва инчунин барои тарҷумони универсалӣ дастгирии тавлиди коди алоҳида дорад.
  • ... ва дар атрофи ҳамаи ин - перифериҳои тақлидшуда, интерфейси корбар, муҳоҷират, сабти такрорӣ ва ғайра.

Воқеан, шумо медонистед: QEMU метавонад на танҳо ба тамоми компютер, балки ба протсессори як раванди корбари алоҳида дар ядрои ҳост, ки масалан аз ҷониби fuzzer AFL барои асбобҳои бинарӣ истифода мешавад, тақлид кунад. Шояд касе мехоҳад ин режими кори QEMU-ро ба JS интиқол диҳад? 😉

Мисли аксари нармафзори ройгони дарозмуддат, QEMU тавассути занг сохта мешавад configure и make. Фарз мекунем, ки шумо қарор додед, ки чизе илова кунед: пуштибонии TCG, татбиқи ришта, чизи дигар. Аз эҳтимоли муошират бо Autoconf ба шодӣ/даҳшатнок шудан шитоб накунед (ба қадри зарурӣ зерро хат кунед) - дар асл, configure QEMU аз афташ худаш навишта шудааст ва аз чизе тавлид нашудааст.

WebAssembly

Пас, ин чизест, ки WebAssembly (aka WASM) номида мешавад? Ин ивазкунандаи Asm.js аст, ки дигар рамзи JavaScript-ро дуруст вонамуд намекунад. Баръакс, он сирф дуӣ ва оптимизатсияшуда аст ва ҳатто ба он навиштани бутуни он чандон осон нест: барои паймонӣ он дар формат нигоҳ дошта мешавад. LEB128 нест.

Шояд шумо дар бораи алгоритми азнавсозӣ барои Asm.js шунидаед - ин барқарорсозии дастурҳои назорати ҷараёни "сатҳи баланд" аст (яъне агар-он гоҳ-дигар, ҳалқаҳо ва ғайра), ки барои онҳо муҳаррикҳои JS тарҳрезӣ шудаанд, аз сатҳи пасти LLVM IR, наздиктар ба рамзи мошин, ки протсессори иҷро мекунад. Табиист, ки намояндагии фосилавии QEMU ба дуюм наздиктар аст. Чунин ба назар мерасад, ки ин ҷост, байт код, охири азоб... Ва он гоҳ блокҳо, агар-он гоҳ-дигар ва ҳалқаҳо ҳастанд!..

Ва ин як сабаби дигари муфид аст, ки Binaryen муфид аст: он табиатан метавонад блокҳои сатҳи баландро, ки дар WASM нигоҳ дошта мешаванд, қабул кунад. Аммо он инчунин метавонад кодро аз графики блокҳои асосӣ ва гузариш байни онҳо тавлид кунад. Хуб, ман аллакай гуфта будам, ки он формати нигоҳдории WebAssemblyро дар паси API мувофиқи C/C++ пинҳон мекунад.

TCG (генератори коди ночиз)

GTC аслан буд пас, аз афташ, он ба рақобат бо GCC тоб оварда натавонист, аммо дар ниҳоят дар QEMU ҳамчун механизми тавлиди код барои платформаи ҳост ҷои худро пайдо кард. Инчунин як пуштибонии TCG мавҷуд аст, ки баъзе байткоди абстрактиро тавлид мекунад, ки онро тарҷумон фавран иҷро мекунад, аммо ман тасмим гирифтам, ки ин дафъа аз истифодаи он худдорӣ кунам. Бо вуҷуди ин, далели он, ки дар QEMU аллакай имконпазир аст, ки гузариш ба бемории сили тавлидшуда тавассути функсия имконпазир бошад tcg_qemu_tb_exec, барои ман хеле фоиданок шуд.

Барои илова кардани пуштибонии нави TCG ба QEMU, шумо бояд зердиректория эҷод кунед tcg/<имя архитектуры> (дар ин маврид, tcg/binaryen), ва он ду файлро дар бар мегирад: tcg-target.h и tcg-target.inc.c и фармон додан хамааш дар бораи он аст configure. Шумо метавонед файлҳои дигарро дар он ҷо ҷойгир кунед, аммо тавре ки шумо аз номи ин ду нафар тахмин карда метавонед, ҳардуи онҳо дар ҷое дохил карда мешаванд: яке ҳамчун файли сарлавҳаи муқаррарӣ (он дар дохили он дохил карда шудааст) tcg/tcg.h, ва он аллакай дар дигар файлҳои директорияҳо мавҷуд аст tcg, accel ва на танҳо), дигаре - танҳо ҳамчун пораи код дар tcg/tcg.c, аммо он ба вазифаҳои статикии худ дастрасӣ дорад.

Қарор додам, ки ман барои таҳқиқи муфассали он, ки чӣ тавр кор мекунад, вақти зиёд сарф мекунам, ман танҳо "скелетҳо" -и ин ду файлро аз татбиқи дигари пуштибонӣ нусхабардорӣ кардам ва инро дар сарлавҳаи иҷозатнома ростқавлона нишон додам.

файл tcg-target.h асосан танзимотро дар шакл дар бар мегирад #define-s:

  • Дар меъмории мақсаднок чанд регистр ва кадом паҳно мавҷуд аст (мо ҳамон қадаре, ки мехоҳем, ҳамон қадар дорем - савол бештар дар бораи он аст, ки браузер дар меъмории "комилан ҳадаф" ба коди муассиртар чӣ тавлид хоҳад кард ...)
  • ҳамоҳангсозии дастурҳои мизбон: дар x86 ва ҳатто дар TCI, дастурҳо умуман мувофиқат намекунанд, аммо ман ба буфери код умуман дастурҳо намегузорам, балки ишораҳоро ба сохторҳои китобхонаи Binaryen мегузорам, бинобар ин ман мегӯям: 4 байт
  • Кадом дастурҳои ихтиёрӣ, ки пуштибон метавонад тавлид кунад - мо ҳама чизеро, ки дар Binaryen ёфтем, дохил мекунем, бигзор суръатдиҳанда боқимондаашро ба соддатар тақсим кунад
  • Андозаи тахминии кэши TLB, ки аз ҷониби пуштибон дархост шудааст, чанд аст. Гап дар он аст, ки дар QEMU ҳама чиз ҷиддӣ аст: гарчанде ки функсияҳои ёрирасон мавҷуданд, ки бо назардошти MMU-и меҳмон боргузорӣ/мағозаро иҷро мекунанд (мо ҳоло бе он дар куҷо мебудем?), онҳо кэши тарҷумаи худро дар шакли сохтор нигоҳ медоранд. ки коркарди он барои бевосита ба блокҳои пахши барнома ҷойгир кардан қулай аст. Савол ин аст, ки кадом ҷуброн дар ин сохтор бо пайдарпаии хурд ва зуди фармонҳо самараноктар коркард карда мешавад?
  • дар ин ҷо шумо метавонед ҳадафи як ё ду регистрҳои ҳифзшударо тағир диҳед, занги бемории силро тавассути функсия фаъол созед ва ихтиёрӣ якчанд регистрҳои хурдро тавсиф кунед. inline-вазифаҳое монанди flush_icache_range (аммо ин ҳолати мо нест)

файл tcg-target.inc.c, албатта, одатан хеле калонтар аст ва дорои якчанд вазифаҳои ҳатмӣ мебошад:

  • оғозкунӣ, аз ҷумла маҳдудиятҳое, ки дар кадом дастурҳо метавонанд дар кадом операндҳо кор кунанд. Ба таври ошкоро аз ҷониби ман аз паси дигар нусхабардорӣ карда шудааст
  • функсияе, ки як дастури байткоди дохилиро мегирад
  • Шумо инчунин метавонед функсияҳои ёрирасонро дар ин ҷо ҷойгир кунед ва шумо инчунин метавонед аз функсияҳои статикӣ истифода баред tcg/tcg.c

Барои худ ман стратегияи зеринро интихоб кардам: дар калимаҳои аввали блоки тарҷумаи навбатӣ, ман чор нишондодро навиштам: аломати оғоз (қимати муайян дар наздикӣ) 0xFFFFFFFF, ки ҳолати кунунии бемории силро муайян кардааст), контекст, модули тавлидшуда ва рақами ҷодугарӣ барои ислоҳи хатогиҳо. Дар аввал нишона гузошта шуд 0xFFFFFFFF - nки дар n - рақами мусбати хурд ва ҳар дафъае, ки он тавассути тарҷумон иҷро мешуд, он ба 1 зиёд мешавад. Вақте ки он расид 0xFFFFFFFE, ҷамъоварӣ сурат гирифт, модул дар ҷадвали функсионалӣ захира карда шуд, ба як "оғозкунандаи" хурд ворид карда шуд, ки иҷрои он аз tcg_qemu_tb_exec, ва модул аз хотираи QEMU хориҷ карда шуд.

Ба ибораи классикӣ, "Асабача, дар ин садо барои дили прогер чӣ қадар бо ҳам пайваст аст...". Бо вуҷуди ин, хотира дар ҷое мечакид. Гузашта аз ин, он хотира буд, ки аз ҷониби QEMU идора мешуд! Ман як код доштам, ки ҳангоми навиштани дастури навбатӣ (хуб, яъне ишоракунанда) онеро, ки қаблан пайвандаш дар ин ҷой буд, нест мекард, аммо ин ёрӣ надод. Дар асл, дар соддатарин ҳолат, QEMU хотираро ҳангоми оғозёбӣ ҷудо мекунад ва рамзи тавлидшударо дар он ҷо менависад. Вақте ки буфер тамом мешавад, код хориҷ карда мешавад ва рамзи навбатӣ ба ҷои он навишта мешавад.

Пас аз омӯхтани код, ман фаҳмидам, ки ҳила бо рақами ҷодугарӣ ба ман имкон дод, ки дар нобудшавии тӯда ноком нашавам ва дар гузариши аввал ягон чизи нодурустро дар буфери оғознашуда озод кунам. Аммо кӣ буферро аз нав менависад, то баъдтар аз функсияи ман гузашт кунад? Тавре таҳиягарони Emscripten маслиҳат медиҳанд, вақте ки ман ба мушкилот дучор шудам, ман коди ҳосилшударо ба замимаи аслӣ интиқол додам, дар он Mozilla Record-Replay насб кардам... Умуман, дар ниҳоят ман як чизи оддиро фаҳмидам: барои ҳар як блок, а struct TranslationBlock бо тавсифи худ. Тасаввур кунед, ки дар куҷо ... Ин дуруст аст, танҳо пеш аз блок дар буфер. Инро дарк намуда, ман қарор додам, ки аз асобағол даст кашам (ҳадди аққал баъзеҳо) ва танҳо рақами ҷодугарро партофта, калимаҳои боқимондаро ба он интиқол додам. struct TranslationBlock, эҷод кардани рӯйхати ягонаи алоқаманд, ки ҳангоми аз нав барқарор кардани кэши тарҷума зуд убур кардан мумкин аст ва хотираро холӣ кунед.

Баъзе асобағолҳо боқӣ мемонанд: масалан, нишондиҳандаҳои ишорашуда дар буфери код - баъзеи онҳо оддӣ ҳастанд BinaryenExpressionRef, яъне онҳо ба ибораҳое назар мекунанд, ки бояд ба блоки асосии тавлидшуда хаттӣ гузошта шаванд, қисм шарти гузариш байни ББ-ҳо, қисмат ба куҷо рафтан аст. Хуб, барои Relooper аллакай блокҳои омодашуда мавҷуданд, ки бояд мувофиқи шароит пайваст карда шаванд. Барои фарқ кардани онҳо, фарзия истифода мешавад, ки ҳамаи онҳо на камтар аз чор байт мувофиқат мекунанд, бинобар ин шумо метавонед ду битҳои камтаринро барои нишона бехатар истифода баред, ба шумо танҳо лозим аст, ки дар ҳолати зарурӣ хориҷ кардани онро фаромӯш накунед. Дар омади гап, чунин тамғакоғазҳо аллакай дар QEMU барои нишон додани сабаби баромадан аз ҳалқаи TCG истифода мешаванд.

Истифодаи Binaryen

Модулҳои WebAssembly дорои функсияҳое мебошанд, ки ҳар яки онҳо як танро дар бар мегиранд, ки ифода аст. Ифодаҳо амалҳои унарӣ ва дуӣ, блокҳое мебошанд, ки аз рӯйхати ифодаҳои дигар, ҷараёни идоракунӣ ва ғайра иборатанд. Тавре ки ман аллакай гуфтам, ҷараёни идоракунӣ дар ин ҷо маҳз ҳамчун шохаҳои сатҳи баланд, ҳалқаҳо, зангҳои функсионалӣ ва ғайра ташкил карда шудааст. Далелҳо ба функсияҳо на ба стек интиқол дода мешаванд, балки ба таври возеҳ ба мисли JS. Тағирёбандаҳои глобалӣ низ ҳастанд, аммо ман онҳоро истифода накардаам, бинобар ин ман дар бораи онҳо ба шумо намегӯям.

Функсияҳо инчунин тағирёбандаҳои маҳаллӣ доранд, ки аз сифр рақамгузорӣ карда шудаанд, навъи: int32 / int64 / float / double. Дар ин ҳолат, аввалин n тағирёбандаҳои маҳаллӣ далелҳое мебошанд, ки ба функсия интиқол дода мешаванд. Лутфан таваҷҷӯҳ намоед, ки гарчанде ки ҳама чиз дар ин ҷо аз нигоҳи ҷараёни назорат комилан паст нест, ададҳои бутун то ҳол атрибути “имзо/имзонашуда”-ро надоранд: чӣ гуна рафтори рақам аз коди амалиёт вобаста аст.

Умуман, Binaryen таъмин менамояд C-API оддӣ: шумо модул эҷод мекунед, дар вай ифодаҳо эҷод кунед - унарӣ, бинарӣ, блокҳо аз ибораҳои дигар, ҷараёни идоракунӣ ва ғайра. Пас шумо функсияеро бо ифода ҳамчун бадани он эҷод мекунед. Агар шумо, мисли ман, як графикаи гузариши сатҳи паст дошта бошед, ҷузъи relooper ба шумо кӯмак мекунад. То ҷое ки ман мефаҳмам, дар як блок назорати сатҳи баланди ҷараёни иҷроро истифода бурдан мумкин аст, ба шарте ки он аз ҳудуди блок берун наравад - яъне имкон дорад роҳи дохилии босуръат / сустро эҷод кард. шохабандии роҳ дар дохили рамзи коркарди кэши дарунсохташудаи TLB, аммо ба ҷараёни идоракунии "берунӣ" халал нарасонад. Ҳангоме ки шумо relooper-ро озод мекунед, блокҳои он озод мешаванд, вақте ки шумо модулро озод мекунед, ифодаҳо, функсияҳо ва ғайра, ки ба он ҷудо карда шудаанд, нопадид мешаванд. арена.

Аммо, агар шумо хоҳед, ки кодро бидуни эҷод ва нест кардани намунаи тарҷумон зуд тафсир кунед, ин мантиқро ба файли C++ гузоштан ва аз он ҷо мустақиман идора кардани тамоми API-и C++-и китобхона бо гузашти омодагӣ маъно дорад. парпечхо сохтанд.

Ҳамин тавр, барои тавлиди коде, ки ба шумо лозим аст

// настроить глобальные параметры (можно поменять потом)
BinaryenSetAPITracing(0);

BinaryenSetOptimizeLevel(3);
BinaryenSetShrinkLevel(2);

// создать модуль
BinaryenModuleRef MODULE = BinaryenModuleCreate();

// описать типы функций (как создаваемых, так и вызываемых)
helper_type  BinaryenAddFunctionType(MODULE, "helper-func", BinaryenTypeInt32(), int32_helper_args, ARRAY_SIZE(int32_helper_args));
// (int23_helper_args приоб^Wсоздаются отдельно)

// сконструировать супер-мега выражение
// ... ну тут уж вы как-нибудь сами :)

// потом создать функцию
BinaryenAddFunction(MODULE, "tb_fun", tb_func_type, func_locals, FUNC_LOCALS_COUNT, expr);
BinaryenAddFunctionExport(MODULE, "tb_fun", "tb_fun");
...
BinaryenSetMemory(MODULE, (1 << 15) - 1, -1, NULL, NULL, NULL, NULL, NULL, 0, 0);
BinaryenAddMemoryImport(MODULE, NULL, "env", "memory", 0);
BinaryenAddTableImport(MODULE, NULL, "env", "tb_funcs");

// запросить валидацию и оптимизацию при желании
assert (BinaryenModuleValidate(MODULE));
BinaryenModuleOptimize(MODULE);

... агар ман чизеро фаромӯш карда бошам, бубахшед, ин танҳо барои ифода кардани миқёс аст ва тафсилот дар ҳуҷҷатҳо мавҷуданд.

Ва ҳоло crack-fex-pex оғоз мешавад, чизе монанди ин:

static char buf[1 << 20];
BinaryenModuleOptimize(MODULE);
BinaryenSetMemory(MODULE, 0, -1, NULL, NULL, NULL, NULL, NULL, 0, 0);
int sz = BinaryenModuleWrite(MODULE, buf, sizeof(buf));
BinaryenModuleDispose(MODULE);
EM_ASM({
  var module = new WebAssembly.Module(new Uint8Array(wasmMemory.buffer, $0, $1));
  var fptr = $2;
  var instance = new WebAssembly.Instance(module, {
      'env': {
          'memory': wasmMemory,
          // ...
      }
  );
  // и вот уже у вас есть instance!
}, buf, sz);

Барои он ки ҷаҳони QEMU ва JS ва ҳамзамон ба таври фаврӣ пайваст шаванд, массив (ҷадвали функсияҳо барои воридот ба launcher) сохта шуд ва функсияҳои тавлидшуда дар он ҷо ҷойгир карда шуданд. Барои зуд ҳисоб кардани индекс, дар аввал индекси блоки тарҷумаи калимаи сифрӣ ҳамчун он истифода мешуд, аммо баъдан индекси бо ин формула ҳисобшуда танҳо ба майдони дар struct TranslationBlock.

Бо роҳи, намоишӣ (дар айни замон бо иҷозатномаи норавшан) танҳо дар Firefox хуб кор мекунад. таҳиякунандагони Chrome буданд гӯё омода нест ба он далел, ки касе мехоҳад беш аз ҳазор намунаҳои модулҳои WebAssembly эҷод кунад, аз ин рӯ онҳо танҳо як гигабайт фазои суроғаи виртуалиро барои ҳар як…

Ҳамааш ҳамин аст. Шояд мақолаи дигаре бошад, агар касе таваҷҷӯҳ кунад. Яъне, ҳадди аққал боқӣ мемонад танҳо дастгоҳҳои блокро ба кор андохт. Инчунин мумкин аст, ки маҷмӯаи модулҳои WebAssembly асинхронӣ бошад, чуноне ки дар ҷаҳони JS маъмул аст, зеро то ҳол тарҷумоне мавҷуд аст, ки то омода шудани модули аслӣ ҳамаи инро иҷро карда метавонад.

Ниҳоят як муаммо: шумо бинариро дар меъмории 32-бит тартиб додед, аммо код тавассути амалиёти хотира, аз Binaryen, дар ҷое дар стек ё дар ҷои дигаре дар 2 ГБ болои фазои суроғаи 32-бит мебарояд. Мушкилот дар он аст, ки аз нуқтаи назари Binaryen ин дастрасӣ ба суроғаи аз ҳад калон аст. Инро чӣ гуна бояд гирифт?

Ба тарзи админ

Ман инро ба охир нарасондам, аммо аввалин фикрам ин буд: "Агар ман Linux-и 32-битро насб кунам, чӣ мешавад?" Он гоҳ қисми болоии фазои адресро ядро ​​ишғол мекунад. Ягона савол ин аст, ки чӣ қадар ишғол мешавад: 1 ё 2 Гб.

Бо роҳи барномасоз (интихоб барои таҷрибаомӯзон)

Биёед дар болои фазои суроға ҳубобчаро вазидаем. Ман худам намефаҳмам, ки чаро он кор мекунад - дар он ҷо аллакай бояд стек бошад. Аммо "мо таҷрибаомӯзем: ҳама чиз барои мо кор мекунад, аммо ҳеҷ кас намедонад, ки чаро..."

// 2gbubble.c
// Usage: LD_PRELOAD=2gbubble.so <program>

#include <sys/mman.h>
#include <assert.h>

void __attribute__((constructor)) constr(void)
{
  assert(MAP_FAILED != mmap(1u >> 31, (1u >> 31) - (1u >> 20), PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
}

... дуруст аст, ки он бо Valgrind мувофиқ нест, аммо, хушбахтона, худи Valgrind хеле муассир ҳамаро аз он ҷо тела медиҳад :)

Шояд касе шарҳи беҳтаре диҳад, ки ин рамзи ман чӣ гуна кор мекунад ...

Манбаъ: will.com

Илова Эзоҳ