QEMU.js: nunc gravis et cum WASM

Olim constitui amet probare reversibility processus et discas quomodo JavaScript (propressius, Asm.js) generare ex machina codice. QEMU ad experimentum electus est, et post aliquanto scriptum est articulus in Habr. In commentationibus monitus sum ut consilium in WebAssembly reformaret et etiam a me ipso discederem paene complevit Ego consilium nescio quo modo nolebam... Opus gerebatur, sed tardissime, et nunc nuper in illo articulo apparuit. comment in thema "Quomodo igitur totum finem?" Ad singula responsio mea, audivi "Hoc sonat articulus." Bene, si potes, articulus erit. Forsitan aliquis utilem inveniet. Ex eo lector aliquas conjecturas de consilio QEMU codice generationis backends discet, itemque quomodo scriberet Just-in-Tempus compilator pro interreti applicatione.

tasks

Cum iam didici quomodo portum QEMU JavaScript, hoc tempus sapienter facere placuit nec vetera errata repetere.

Error numerus unus: ramus a puncto emissio

Primus error fuit meam versionem furca ab adverso flumine 2.4.1. Tum utilem mihi visum est: si punctum emissio existit, verisimiliter stabilior est quam simplex 2.4, et ramus multo magis. master. Et quoniam cogitavit de meis cimicibus addere iustam quantitatem, nullo alio egeo. Probabile est quomodo evenit. Sed hic res est: QEMU non stat, et in aliquo loco generati codicem optimam etiam nuntiaverunt per 10 cento. "Yeah, nunc vado rigescere" cogitavi et destruxit. Hic digressionem facere oportet: ob unicam bracteatam naturam QEMU.js et hoc quod originale QEMU non implicat absentiam multi- staminum (id est, facultas simul operandi plures viae codicei finitimus, et non solum "omnibus nucleis uti") criticum est pro eo, quod principales functiones filorum quas ad "extremum convertunt", ab extra appellare possunt. Hoc in merger creavit problemata naturalia. Sed hoc quod aliquae mutationes a ramo master, cum quo codicem meum iungi conatus sum, cerasus etiam in emissione (et ideo in ramo meo lecta) etiam commodum probabiliter non addidisset.

In genere decrevi adhuc sensum ejicere prototypum, eum in partes distrahere ac novam versionem a integro innixam novo recenti ac nunc e construere. master.

Error numerus duo: TLP methodologia

Essentialiter, hoc non fallitur, generatim solum proprium est creandi consilium in condicionibus perfecte erroris utriusque "ubi et quomodo movendi?" et generatim "ibi ibimus?" His conditionibus informes programming optio iustificata erat, sed naturaliter eam indebite repetere nolui. Hoc tempore sapienter id facere volui: nuclei facit, codicem mutationum conscium (et non "constringens characteribus incertis in unum, donec componat (monendo)", ut Linus Torvalds olim de aliquo, teste Vicicio) etc.

Fallitur numerus ternarium: Aquam introeunt nescientes vadum

Hoc adhuc non penitus exutus sum, nunc tamen decrevi ne minimae resistentiae viam sequi, et facere "viam adultam", nempe scribe meum TCG tergum a scabere, ne. postea dicere "Ita, hoc est, lente quidem, sed omnia non possum regere - id est quomodo TCI scriptum est..." Hoc autem initio quasi evidens solutio videbatur, quoniam Ego codice generate binarii. Ut aiunt, "Gandem congregavit"уnon autem unus»: codicem quidem binarium, sed imperium simpliciter transferri non potest - oportet explicite impelli in navigatro pro compilatione, inde in re aliqua e mundo JS, quod etiamnum necesse est. salvus alicubi. Attamen in architecturae normali RISC, quantum intelligo, situ typico opus est ut catechesim de codice regenerato explicite retexere - si hoc non est quod opus est, utique est prope. Praeterea, ab ultimo conatu, intellexi potestatem non videri ad medium translationis impedimentum transferri, ideo bytecode interpretari non debemus ex aliqua offset, et simpliciter generare possumus ex functione in TB. .

Venerunt et recalcitravit

Quamvis codicem rescribere coepi mense Iulio, calcitrare magicum obrepsit inobservatum: plerumque litterae a GitHub perveniunt ut notificationes de responsionibus ad quaestiones et petitiones excute, hic autem; subito mentionem in sequela Binaryen ut qemu backend in contextu "aliquid tale fecit, fortasse aliquid dicet." Loquebantur de usura bibliothecae Emscripten cognatae Binaryen WASM JIT creare. Bene dixi te licentiam ibi Apache 2.0 habere, et totum QEMU sub GPLv2 distributum, et non valde compatitur. Subito evenit ut licentia fieri possit reficere aliquo modo (Nescio: fortasse mutare, fortasse licentiae dualis, fortasse aliquid aliud....). Quod quidem me beatum fecit, quod iam tunc inspexi binarii forma WebAssembly, et eram quodammodo tristis et incomprehensibilis. Fuit etiam bibliotheca, quae cuneos fundamentales graphio transitus devoraret, bytecodem producere, ac etiam in ipso interprete, si opus esset, currere.

Tum plus litterae in QEMU list, sed hoc magis est de quaestione, "Quis usquam opus est?" Et est subitoevenit, oportuit. Ad minimum, corradere potes sequentes facultates utendi, si plus minusve cito operatur;

  • sine ulla institutionem omnino aliquid educational launching
  • virtualisatio in iOS, ubi, secundum rumores, sola applicatio quae ius habet in codice generationis in musca, machinam JS (est hoc verum?)
  • mini- OS demonstratio simplicis floppy, constructa in omni genere firmware, etc.

Pasco Runtime Features

Ut iam dixi, QEMU ad multiplicationem ligatur, sed navigatrum illud non habet. Bene, id est, non... Primum omnino non erat, tunc operarii opifices apparuerunt - sicut intellego, haec est multiplex lectio secundum nuntium transitum. sine participatur variables. Naturaliter problemata significativa gignit cum codicem portandi existens in communi memoriae exemplari fundatum est. Tum, sub pressura publica, sub nomine etiam effecta est SharedArrayBuffers. Paulatim introductum, in diversis navigatoribus launches celebraverunt, deinde Novum Annum celebraverunt, deinde Meltdown... Post quod tempus cibarium aut grossum mensurae temporis conclusum est, sed ope memoriae et communionis. filum incrementing calculo, actum est hoc erit elaborare satis verius. Ita multithreading cum communi memoria erret. Hoc videtur quod postea recesserunt, sed, sicut ex primo experimento patuit, vita sine ea est, et si ita est, id conabimur sine multitudine freti.

Secunda linea est impossibilitas humilium graduum machinationes cum acervo: simpliciter capere non potes, praeter praesentem contextum et ad novum acervum commutandum. Vocatio acervus a machina virtuali JS administratur. Videretur, quaenam est quaestio, cum adhuc institutum sit illud manually omnino manare? Ita res est, ut clausus I/O in QEMU per coroutines perficiatur, et hoc est ubi ACERVUS ACERVUS manipulationes manus manus veniunt. Fortunate, Emscipten iam continet machinas asynchronas operationes, etiam duas; Asyncify и Emterpreter. Prima opera per significantes bloat in JavaScript codice generatae et non diutius sustinetur. Secunda vena "via recta" est et per bytecode generationis ad interpretem vernaculum operatur. Lente laborat, sed non deleo signum. Verum, subsidium coroutines huius mechanismi independenter conferri debebant (iam coroutines pro Asyncify scriptae erant et exsecutio proxime eiusdem API ad Emterpretem, modo opus erat eas coniungere).

In momento, codicem in WASM exaratum in WASM scindendum nondum curavi et utendo Emterprete interpretatus sum, tam scandalum machinae nondum operantur (vide in altera serie, ut aiunt...). Hoc est, in finem aliquid simile accipias hoc ridiculum trilicum:

  • interpretata angustos I/O. Hem, verene expectas aemulatum NVMe indigenis gesti? 🙂
  • statically QEMU codicem principalem composuit (interpres, alii strophas aemulatus, etc.)
  • dynamically digestus hospes codice in WASM

Features of QEMU fontes

Ut probabiliter iam coniecibam, codicem architecturae hospitum aemulandi et codicem machinae generandae instructiones in QEMU separantur. Nam vel paulo fallacior est:

  • sunt hospite architecturae
  • est acceleratorsnempe KVM pro hardware virtualisationi in Linux (pro hospitio et systematibus hospitii inter se compatientibus), TCG pro JIT codice generationis alicubi. Satus cum QEMU 2.9, subsidium HAXM hardware virtualizationis vexillum in Fenestra apparuit (details)
  • si TCG usus est et virtualisatio non ferramentorum, tunc habet subsidium generationis separati pro singulis architecturae hospitis, necnon pro interprete universali.
  • ... et circa haec omnia aemulantur peripherales, interfaces, migrationes, remonstrationes, etc.

Viam scisti; QEMU aemulari potest non solum totum computatorium, sed etiam processus pro separato usoris processu in nucleo hostiae, qui adhibetur, exempli gratia, per AFL fuzzer instrumenti binarii. Forsitan aliquis modum hunc operationis QEMU ad JS inuenire velit? 😉

Sicut in programmatibus maxime diuturni gratis, per vocationem QEMU aedificatur configure и make. Dicamus te aliquid addere volueris: a TCG backend, deductio filum, aliquid aliud. Noli ruere ut felix/horriantur (pro opportunitate underline) in spe communicandi cum Autoconf - re vera, configure QEMU's videtur per se scriptum et non ex aliquo generatur.

WebAssembly

Quid est ergo hoc quod dicitur WebAssembly (aka WASM)? Haec substitutio Asm.js est, simulata non amplius valere JavaScript codicem. E contra, est mere binarius et optimized, ac etiam simpliciter scribens integrum in eo non admodum simplex: nam in forma densitatis reponitur. LEB128.

Audire licet de algorithm pro Asm.js - restaurationem hanc "alti-gradi" fluere instructionum moderationis (id est, si-tunc-aliud, ansas, etc.), ad quas machinas JS designantur, e. low-gradus LLVM IR, propius ad machinam processus a codice exsecutus est. Nempe medium QEMU repraesentatio propius ad secundum. Videtur quod hic sit, bytecode, finis tormenti.

Et haec est alia ratio quare Binaryen utilis est: potest naturaliter accipere cuneos summus gradus iuxta quod in WASM conditum esset. Sed codicem etiam producere potest e graphe inter eos stipites et transitus. Bene, iam dixi eum celare formas repositionis WebAssembly post opportunitatem C/C++ API.

TCG (Tiny Code Generator)

GTC fuit primum Rescribere pro C compilator, deinde, ut videtur, certamen cum GCC sustinere non potuit, sed in fine locum suum invenit in QEMU ut codicem generationis mechanismum pro tribunali exercitui. Est etiam TCG backend, quae abstractum aliquod bytecode gignit, quod ab interprete statim exsequitur, sed hoc tempore vitare decrevi. Quod tamen in QEMU iam fieri potest ut transitus ad genitum TB per functionem tcg_qemu_tb_execvertit ad me valde utilem.

Ad novam TCG backend ad QEMU addere, debes creare subdirectorium tcg/<имя архитектуры> (in hoc casu, tcg/binaryen) et continet duo fasciculi: tcg-target.h и tcg-target.inc.c и praescribo suus 'circa omnes configure. Alias ​​tabulas ibi ponere potes, sed ex nominibus horum duorum, ut suspicari potes, alicubi includuntur: unum ut fasciculus capitis regularis (includitur in tcg/tcg.het ille iam in aliis fasciculis in directoriis tcg, accel et non solum), alterum - tantum ut in codice snippet in tcg/tcg.csed habet aditus ad statas functiones.

Decernens me nimium tempus consumere in investigationibus singularibus quomodo operatur, simpliciter "ossa" harum duarum fasciculorum ex alia exsecutione backendi exscripsi, honeste id in capite licentiae indicans.

lima tcg-target.h maxime habet occasus in forma #define-s;

  • quot tabulae et quae latitudo ibi est in architectura scopo (tot habemus quot volumus, quotquot volumus - quaestio est de quo magis in codicem efficientem generabitur a navigatro in architectura "omnino scopo". ...)
  • alignment instructionum hospitii: in x86, et etiam in TCI, instructiones omnino non perpenduntur, sed ego in codice quiddam non instructiones omnino ponemus, sed indicium ad structuras bibliothecae Binaryen, sic dicam: 4 bytes
  • quae ad optionales backend instructiones generare possunt - includimus omnia quae in Binaryen invenimus, accelerator reliquas in se simpliciores frangat.
  • Quae est proxima magnitudo TLB cache rogatus a backend. Ita res est in QEMU omnia seria esse: quamquam munera adiuvantia sunt quae onus/copia attenta hospite MMU praestant (ubi nunc sine eo essemus?), translationem cella in forma structurae conservant, in processus cuius commodum est directe in cuneos iaci emed. Quaeritur, quidnam in hac structura efficacissime discursum sit parva et rapida series mandatorum?
  • hic indagare potes propositum unius vel duo registri reservati, da vocatione TB per functionem et optione duos parvos describere. inline-functions sicut flush_icache_range (sed haec non est nostra causa)

lima tcg-target.inc.csane plerumque multo maiora, pluraque munera facienda;

  • initialization, etiam restrictiones quibus instructiones operari possunt quibus operandi. Blatantly me exscriptus ab alio backend
  • munus quod interna bytecode disciplinam
  • Munera auxiliaria hic ponere potes et functionibus statice uti potes tcg/tcg.c

Ego ipse consilium hoc delegi: in primis verbis sequentis translationis clausus quattuor indicibus scripsi: signum initium (valorem quendam in vicinia. 0xFFFFFFFFquae statui hodierni TB determinavit), contextus, moduli genitus, et numerus magicus ad debugging. Primo nota posita est 0xFFFFFFFF - nquibus n - numerus positivus parvus, et quotiescumque per interpretem exsecutus est, augetur 1. Cum pervenit 0xFFFFFFFECompilatio facta est, modulus servatus est in tabula functionis, in parvam "launcher" importatam, in quam exsecutio profectus est. tcg_qemu_tb_execet modulus ab QEMU memoria remotus est.

Ad paraphrasin classica, "Cruthe, quantum huic sono inseritur cor procuratoris ...". Sed alicubi portasse memoria fuit. Porro memoria QEMU gesta! Codicem habui qui, cum disciplinam sequentem (bene, id est, regulam) scriberet, delevit illum cuius nexus antea in hoc loco erat, sed hoc nihil adiuvabat. Profecto, simplicissimo casu, QEMU memoriam in satus collocat et codicem genitum ibi scribit. Cum quiddam deficit, eicitur codice, deinde incipit in suo loco scribi.

Postquam codicem pervestigavi, intellexi dolum cum numero magico me non deesse in ruinam cumulo, ut aliquid mali liberaret in quiddam rudimentum in primo passu. Sed quis auctor est quiddam postea munus praeterire? Cum tincidunt Emscripten moneant, cum in problema decurro, codicem inde ad applicationem indigenae portavi, Mozilla Record-Replay in eo... In genere, in fine rem simplicem percepi: pro unoquoque scandalo, a struct TranslationBlock cum suis descriptionibus. Coniecto ubi ... Iustum est, paulo ante scandalum rectum in quiddam. Quod cum animadvertisset, decrevi utentes fusis (saltem aliquibus) et simpliciter eiectis numero magico, reliqua verba transtulisse ad. struct TranslationBlock, creans unum album coniunctum quod celeriter percurritur cum translatio cella retexere et memoriam liberare possunt.

Quaedam fusculae manent: exempli gratia indicia quaedam in codice notata - quaedam simpliciter sunt BinaryenExpressionRefhoc est, spectant locutiones quae lineariter ponendae sunt in scandalum genitum, pars est condicio transitus inter BBs, pars est ubi. Bene iam paratae sunt caudices pro Relooper quae secundum condiciones iungi necesse est. Ad distinctionem earum, suppositio adhibetur ut omnes saltem quattuor bytes perpendantur, ita tuto duobus minimis notis titulus uti potes, tantum meminisse debes, si opus est, removere. Obiter tales pittacii iam usi sunt in QEMU ad indicandam causam ansam TCG exeundi.

Using Binaryen

Moduli in WebAssembly continent functiones, quarum singulae corpus continet, quod est expressio. Expressiones sunt operationes unariae et binariae, caudices constans in tabulis aliarum vocum, fluxus temperantiae, etc. Ut iam dixi, imperium hic fluere ordinatur praecise ut summus gradus rami, loramenta, munus vocat, etc. Argumenta ad functiones in acervo non transmittuntur, sed expresse, sicut in JS. Variae etiam globales sunt, sed eas usus non sum, ideo tibi de illis non dicam.

functiones etiam variabiles locales, a nulla re numeratae, generis habent: int32 / int64 / float / duplex. In hoc casu primae n locales variabiles rationes ad functionem latae sunt. Quaeso nota quod, licet omnia hic non sint omnino demissa secundum fluxum imperium, integri tamen attributum "signatum/unsignatum" non ferunt: quomodo numerus se gerit in codice operationis.

Generaliter Binaryen praebet simplex C-API: modulum creas; in eo expressiones creo - unara, binaria, caudices ab aliis elocutionibus, fluere imperium, etc. Munus ergo creas cum dictione ut corpus. Si tu, sicut me, graphi humili gradu transitum habebis, pars relooper te adiuvabit. Quantum intelligo, fieri potest ut summus gradus moderatio executionis in stipitem influat, dummodo non transcendat limites clausus - hoc est, fieri potest ut iter internum ieiunium / tardum faciat. iter ramosum intra in TLB cache processus codicis constructum, sed non impedire fluxum imperium "externi". Cum relooper liberas, caudices eius liberantur, cum moduli, expressiones, functiones, ei partita evanescant etc. arena.

Attamen, si voles codicem interpretari in musca sine superflua creatione et deletione interpretis, instantia potest facere sensum logicam hanc in fasciculum C++ ponere, et inde protinus totam C++ API bibliothecam administrare, praetermittens. derecta facta.

Itaque in codice opus ad generate

// настроить глобальные параметры (можно поменять потом)
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);

... si quid oblitus sum, moleste fero, hoc tantum librae repraesentare, ac singularia in documentis esse.

Jamque rima fex incipit, aliquid simile;

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);

Ut mundos QEMU et JS quodammodo coniungas et simul munera compilata celeriter accedere, ordinatio facta est (mensa functionum pro import in launcher), et munera generata ibi posita sunt. Ad indicem cito calculandum, index translationis dictionum nullarum in initio usus est, sed index calculi huius formulae utens in campum simpliciter incepit. struct TranslationBlock.

Per viam, demo ( Currently cum atris licentia) solum bene operatur in Firefox. Chrome developers erant nescio quomodo paratus eo quod aliquis plus quam mille exempla WebAssembly modulorum creare velit, ut gigabytum virtualis inscriptionis pro singulis... simpliciter sortiantur.

Quod ut 'quia iam omnia. Fortasse alius articulus erit si quis interroget. Scil, remanet saltem tantum adinventiones faciunt scandalum operari. Poterat etiam sensus efficere compilationem of WebAssembly modulorum asynchronam, sicut in mundo JS mori solet, cum adhuc sit interpres qui haec omnia facere potest usque ad moduli nativi paratus est.

Denique problema: Composuisti binarium in architectura 32-bit, sed codicem, per operationes memoriae, e Binaryen, alicubi in acervo, vel alibi in superiori 2 GB spatio 32-bit, conscendit. Problema est ex sententia Binaryen hoc nimis magnum accessum esse electronicum consequentem. Quam impetro circa hoc?

In admin 's modo

Hoc non temptavi, sed prima cogitatio "Quid si Linux 32 frenum institui?" Tum superior pars spatii a nucleo inscriptionis occupabitur. Sola quaestio est, quantum vacabit: 1 vel 2 Gb.

In via programmator (optionem medicorum)

Bullam in summo spatii inscriptionis ictu feriamus. Ego ipse non intellego cur operetur - ibi iam acervus erit. Sed nos medici sumus: omnia opera nostra sunt, sed nemo scit quare...

// 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));
}

... verum est quod cum Valgrind non compatitur, sed peropportune, ipsa Valgrind efficacissime omnes inde pellat.

Fortasse aliquis melius explicabit quomodo hoc codicem meorum operum...

Source: www.habr.com

Add a comment