QEMU.js: matotra izao ary miaraka amin'ny WASM

Indray mandeha aho dia nanapa-kevitra ny hifalifaly manaporofo ny fiverenan'ny dingana ary ianaro ny fomba famoronana JavaScript (marika kokoa, Asm.js) avy amin'ny kaody milina. QEMU no voafidy ho amin'ny andrana, ary fotoana fohy taty aoriana dia nisy lahatsoratra nosoratana tao amin'ny Habr. Tao amin'ny fanehoan-kevitra dia nanoro hevitra aho hamerina ny tetikasa ao amin'ny WebAssembly, ary hiala amin'ny tenako mihitsy aza saika vita Tsy naniry ny tetikasa aho ... Nandeha ny asa, saingy niadana be, ary ankehitriny, vao haingana no niseho tao amin'io lahatsoratra io. fanehoan-kevitra momba ny lohahevitra hoe β€œDia ahoana no niafaran’izany rehetra izany?” Ho setrin'ny valinteniko amin'ny antsipiriany, dia nandre hoe "Toa lahatsoratra ity." Eny, raha azonao atao dia hisy lahatsoratra. Angamba hisy hahita izany mahasoa. Avy amin'izany ny mpamaky dia hianatra zava-misy sasany momba ny famolavolana ny QEMU code generation backends, ary koa ny fomba fanoratana Just-in-Time compiler ho an'ny fampiharana tranonkala.

asa

Satria efa nianatra ny fomba "hanao" port QEMU amin'ny JavaScript aho, tamin'ity indray mitoraka ity dia nanapa-kevitra ny hanao izany amim-pahendrena ary tsy hamerina ny fahadisoana taloha.

Hadisoana laharana voalohany: sampana avy amin'ny famoahana teboka

Ny fahadisoako voalohany dia ny nanala ny kinovako avy amin'ny dikan-teny ambony 2.4.1. Avy eo dia toa hevitra tsara tamiko izany: raha misy ny famoahana teboka, dia mety ho stable kokoa noho ny tsotra 2.4 izany, ary na dia ny sampana aza. master. Ary satria nikasa ny hanampy be dia be amin'ny bibikely aho, dia tsy mila an'olon-kafa mihitsy aho. Izany angamba no niseho. Saingy izao no zava-misy: tsy mijanona ny QEMU, ary amin'ny fotoana iray dia nanambara mihitsy aza izy ireo ny fanatsarana ny kaody vokarina amin'ny 10 isan-jato. Eto isika dia mila manao digression: noho ny toetra tokana amin'ny QEMU.js sy ny zava-misy fa ny QEMU tany am-boalohany dia tsy midika ny tsy fisian'ny multi-threading (izany hoe, ny fahafahana miasa miaraka amin'ny lalana code maro tsy mifandray, ary fa tsy hoe "ampiasao ny voany rehetra") no tena zava-dehibe amin'izany, ny tena fiasan'ny kofehy tsy maintsy "navoakako" mba hahafahana miantso avy any ivelany. Niteraka olana voajanahary izany nandritra ny fampivondronana. Na izany aza, ny zava-misy fa ny sasany amin'ireo fiovana avy amin'ny sampana master, izay nanandrana nanambatra ny kaodinao aho, dia nofantenana ihany koa ny serizy tamin'ny famoahana teboka (ary noho izany tao amin'ny sampanako) dia mety tsy ho nampiana fanamaivanana.

Amin'ny ankapobeny, nanapa-kevitra aho fa mbola misy dikany ny manary ny prototype, manafoana azy ho ampahany ary manangana dikan-teny vaovao avy amin'ny scratch mifototra amin'ny zavatra vaovao kokoa sy ankehitriny. master.

Fahadisoana laharana faharoa: fomba fiasa TLP

Amin'ny ankapobeny, tsy fahadisoana izany, amin'ny ankapobeny, singa iray amin'ny famoronana tetikasa amin'ny toe-javatra tsy fifankahazoan-kevitra tanteraka momba ny "aiza sy ny fomba hifindrana?" ary amin'ny ankapobeny "ho tonga any ve isika?" Amin'ireo fepetra ireo fandaharana kisendrasendra dia safidy ara-drariny, saingy, mazava ho azy, tsy te hamerina izany tsy amin'antony aho. Tamin'ity indray mitoraka ity aho dia te-hanao izany amim-pahendrena: ny atomika commits, ny fanovana fehezan-dalΓ na misaina (fa tsy ny β€œfamehezana ireo tarehin-tsoratra kisendrasendra mandra-pahatongany (miaraka amin'ny fampitandremana)”, araka ny nolazain'i Linus Torvalds momba ny olona iray, araka ny Wikiquote), sns.

Fahadisoana laharana fahatelo: miditra ao anaty rano nefa tsy mahafantatra ny ford

Mbola tsy nesoriko tanteraka izany, fa ankehitriny dia nanapa-kevitra ny tsy hanaraka ny lalan'ny fanoherana faran'izay kely indrindra aho, ary hanao izany "amin'ny maha-olon-dehibe", izany hoe, soraty ny backend TCG-ko hatramin'ny voalohany, mba tsy tsy maintsy miteny any aoriana hoe: "Eny, mazava ho azy, miadana, saingy tsy afaka mifehy ny zava-drehetra aho - izany no nanoratana ny TCI ..." Fanampin'izany, toa vahaolana mazava izany tamin'ny voalohany, satria Mamorona code binary aho. Araka ny filazan'izy ireo, "Nivory i GhentΡƒ, fa tsy ilay iray”: mazava ho azy fa mimari-droa ny kaody, saingy tsy azo afindra amin'izany fotsiny ny fanaraha-maso - tsy maintsy atsofoka mazava ao amin'ny navigateur izany mba hanangonana, ka miteraka zavatra iray avy amin'ny tontolon'ny JS, izay mbola mila hovonjena any ho any. Na izany aza, amin'ny maritrano RISC mahazatra, raha ny fahazoako azy, ny toe-javatra mahazatra dia ny ilΓ na ny famerenana mazava ny cache torolΓ lana ho an'ny kaody regenerated - raha tsy izany no ilaintsika, dia akaiky izany. Ho fanampin'izay, tamin'ny andrana farany nataoko, dia nianatra aho fa toa tsy afindra eo afovoan'ny sakana fandikan-teny ny fanaraha-maso, noho izany dia tsy mila bytecode adika amin'ny offset rehetra izahay, ary afaka mamorona azy fotsiny avy amin'ny fiasa amin'ny TB. .

Tonga izy ireo ary nandaka

Na dia nanomboka namerina nanoratra ny kaody aza aho tamin'ny volana jolay, dia nisy daka majika tsy voamarika: matetika ny taratasy avy amin'ny GitHub dia tonga ho fampandrenesana momba ny valin'ny olana sy ny fangatahana Pull, fa eto, tampoka miresaka amin'ny kofehy Binaryen ho toy ny backend qemu ao amin'ny teny manodidina, "Nanao zavatra toy izany izy, angamba hilaza zavatra." Niresaka momba ny fampiasana ny tranomboky mifandraika amin'i Emscripten izahay Binaryen mba hamoronana WASM JIT. Eny, nilaza aho fa manana lisansa Apache 2.0 ianao ao, ary ny QEMU amin'ny ankapobeny dia zaraina amin'ny GPLv2, ary tsy dia mifanentana loatra izy ireo. Tampoka teo dia hita fa azo atao ny fahazoan-dΓ lana amboary izany (Tsy haiko: mety hanova izany, mety ho fahazoan-dΓ lana roa, angamba zavatra hafa ...). Mazava ho azy fa nahafaly ahy izany, satria tamin'izay fotoana izay dia efa nijery akaiky aho endrika binary WebAssembly, ary somary nalahelo sy tsy takatry ny saina aho. Nisy ihany koa ny trano famakiam-boky iray izay handany ireo sakana fototra miaraka amin'ny grafika tetezamita, hamokatra ny bytecode, ary hampandeha azy amin'ny mpandika teny mihitsy aza, raha ilaina.

Dia nisy hafa koa taratasy ao amin'ny lisitry ny mailaka QEMU, fa ity kosa dia momba ny fanontaniana hoe "Iza no mila izany?" Ary izany dia tampoka, hita fa nilaina izany. Farafaharatsiny, azonao atao ny manambatra ireto fahafaha-manao manaraka ireto, raha miasa haingana kokoa na latsaka:

  • manomboka zavatra fanabeazana tsy misy fametrahana mihitsy
  • virtoaly amin'ny iOS, izay, araka ny tsaho, ny hany fampiharana manan-jo hamorona kaody amin'ny sidina dia motera JS (marina ve izany?)
  • fampisehoana ny mini-OS - single-floppy, naorina-in, isan-karazany ny firmware, sns...

Toetran'ny Browser Runtime

Araka ny efa nolazaiko, ny QEMU dia mifamatotra amin'ny multithreading, saingy tsy manana izany ny navigateur. Eny, izany hoe, tsia ... Tamin'ny voalohany dia tsy nisy mihitsy, dia niseho ny WebWorkers - raha ny fahazoako azy, ity dia multithreading mifototra amin'ny hafatra mandalo. tsy misy fari-piainana iombonana. Mazava ho azy, miteraka olana lehibe izany rehefa mandefa kaody efa misy mifototra amin'ny modely fahatsiarovana iombonana. Avy eo, noho ny faneren'ny vahoaka, dia nampiharina tamin'ny anarana ihany koa izany SharedArrayBuffers. Nampidirina tsikelikely izy ireo, nankalaza ny fandefasana azy tamin'ny navigateur samihafa izy ireo, avy eo nankalaza ny Taom-baovao, ary avy eo Meltdown ... Taorian'izay dia tonga tamin'ny fanatsoahan-kevitra izy ireo fa ny fandrefesana ny fotoana dia manjavozavo na manjavozavo, fa noho ny fanampian'ny fahatsiarovana iombonana sy ny kofehy mampitombo ny kaontera, mitovy daholo hahomby tsara izany. Noho izany dia nesorinay ny multithreading miaraka amin'ny fahatsiarovana iombonana. Toa naverin'izy ireo izany taty aoriana, saingy, araka ny nazava tamin'ny fanandramana voalohany, dia misy ny fiainana tsy misy azy, ary raha izany, dia hiezaka ny hanao izany isika fa tsy miantehitra amin'ny multithreading.

Ny endri-javatra faharoa dia ny tsy fahafahan'ny fanodinkodinana ambany amin'ny stack: tsy azonao atao ny maka tsotra izao, mitahiry ny contexte ankehitriny ary mifamadika vaovao miaraka amin'ny stack vaovao. Ny milina virtoaly JS dia mitantana ny antso an-tariby. Toa inona no olana, satria mbola nanapa-kevitra ny hitantana ny fikorianan'ny teo aloha amin'ny tanana izahay? Ny zava-misy dia ny fanakanana I/O ao amin'ny QEMU dia ampiharina amin'ny alΓ lan'ny coroutines, ary eto no mety hampiasana ny fanodikodinana stack ambany. Soa ihany fa ny Emscipten dia efa misy mekanika ho an'ny hetsika asynchronous, na dia roa aza: Asyncify ΠΈ Emterpreter. Ny voalohany dia miasa amin'ny alΓ lan'ny bloat lehibe amin'ny kaody JavaScript novokarina ary tsy tohana intsony. Ny faharoa dia ny "lalana marina" ankehitriny ary miasa amin'ny alΓ lan'ny famoronana bytecode ho an'ny mpandika teny. Miasa, mazava ho azy, miadana, fa tsy manenika ny kaody. Marina fa tsy maintsy nandray anjara tsy miankina ny fanohanana coroutines ho an'ity mekanika ity (efa nisy coroutine nosoratana ho an'ny Asyncify ary nisy ny fampiharana ny API mitovy amin'ny Emterpreter, mila mampifandray azy ireo fotsiny ianao).

Amin'izao fotoana izao, mbola tsy vitako ny nanasaraka ny code ho iray natambatra tao amin'ny WASM ary nadika tamin'ny fampiasana Emterpreter, ka tsy mbola mandeha ny fitaovana fanakanana (jereo amin'ny andiany manaraka, araka ny filazan'izy ireo ...). Izany hoe, amin'ny farany dia tokony hahazo zavatra toy ity zavatra mahatsikaiky sosona ity ianao:

  • interpreted block I/O. Eny, tena nanantena ve ianao NVMe nalaina tahaka tamin'ny fampisehoana teratany? πŸ™‚
  • kaody QEMU fototra natambatra amin'ny statika (mpandika teny, fitaovana hafa alaina, sns.)
  • kaody vahiny natambatra amin'ny WASM

Toetran'ny loharano QEMU

Araka ny efa noeritreretinao angamba dia misaraka ao amin'ny QEMU ny kaody ho an'ny fakan-tahaka ny maritrano vahiny sy ny kaody hamoronana toromarika milina mpampiantrano. Raha ny marina dia somary sarotra kokoa izany:

  • misy ny maritrano vahiny
  • dia accelerators, izany hoe, KVM ho an'ny virtoaly hardware amin'ny Linux (ho an'ny rafitra vahiny sy mpampiantrano mifanentana), TCG ho an'ny famokarana kaody JIT na aiza na aiza. Nanomboka tamin'ny QEMU 2.9, nipoitra ny fanohanana ny fenitra virtoaly virtoaly HAXM amin'ny Windows (ny antsipirihany)
  • raha TCG no ampiasaina fa tsy virtoaly virtoaly, dia manana fanohanana famoronana kaody misaraka ho an'ny maritrano mpampiantrano tsirairay, ary koa ho an'ny mpandika teny manerantany
  • ... ary manodidina izany rehetra izany - periferika nalaina tahaka, interface tsara, fifindra-monina, firaketana an-tsoratra, sns.

Raha ny marina, fantatrao ve: Ny QEMU dia tsy afaka maka tahaka ny solosaina manontolo ihany, fa koa ny processeur ho an'ny fizotry ny mpampiasa manokana ao amin'ny kernel mpampiantrano, izay ampiasain'ny AFL fuzzer ho an'ny fitaovana binary. Angamba misy olona te hampiditra ity fomba fiasan'ny QEMU ity amin'ny JS? πŸ˜‰

Tahaka ny ankamaroan'ny rindrambaiko maimaim-poana efa ela, QEMU dia natsangana tamin'ny antso configure ΠΈ make. Aoka hatao hoe manapa-kevitra ny hanampy zavatra ianao: backend TCG, fampiharana kofehy, zavatra hafa. Aza maika ho faly/ho raiki-tahotra (tsipiho raha mety) amin'ny fahatsinjovana ny fifandraisana amin'ny Autoconf - raha ny marina, configure Ny an'ny QEMU dia toa nosoratan'ny tena ary tsy noforonina na inona na inona.

WebAss Assembly

Inona Γ ry no atao hoe WebAssembly (aka WASM)? Ity dia fanoloana ny Asm.js, tsy miseho ho code JavaScript manan-kery intsony. Mifanohitra amin'izany, dia mimari-droa fotsiny izy io ary optimized, ary na dia ny fanoratana integer fotsiny aza dia tsy dia tsotra loatra: ho an'ny compactness, dia voatahiry ao amin'ny format. LEB128.

Mety efa naheno momba ny algorithm relooping ho an'ny Asm.js ianao - ity no famerenana amin'ny laoniny ny toromarika mifehy ny fikorianan'ny β€œavo” (izany hoe, raha tsy izany, tadivavarana, sns.), izay nanamboarana ny motera JS, avy amin'ny ny LLVM IR ambany, akaiky kokoa ny kaody masinina ataon'ny processeur. Mazava ho azy, ny solontenan'ny mpanelanelana an'ny QEMU dia manakaiky ny faharoa. Toa izao, bytecode, ny fiafaran'ny fampijaliana... Ary avy eo dia misy sakana, raha-dia-hafa ary tadivavarana!..

Ary antony iray hafa mahasoa an'i Binaryen izany: afaka manaiky ho azy ireo sakana avo lenta akaiky ny zavatra hotehirizina ao amin'ny WASM. Saingy afaka mamokatra kaody avy amin'ny kisarisary misy sakana fototra sy fifindrana eo anelanelan'izy ireo. Eny ary, efa nilaza aho fa manafina ny endrika fitahirizana WebAssembly ao ambadiky ny C/C ++ API.

TCG (Tiny Code Generator)

GTC tany am-boalohany backend ho an'ny compiler C. Avy eo, toa tsy nahatohitra ny fifaninanana tamin'ny GCC, fa tamin'ny farany dia nahita ny toerany tao amin'ny QEMU ho toy ny mekanika famoronana fehezan-dalΓ na ho an'ny sehatra mpampiantrano. Misy ihany koa ny backend TCG izay miteraka bytecode abstract, izay ataon'ny mpandika teny avy hatrany, saingy nanapa-kevitra ny tsy hampiasa izany aho amin'ity indray mitoraka ity. Na izany aza, ny zava-misy ao amin'ny QEMU dia efa azo atao ny mamela ny fifindrana mankany amin'ny TB vokarina amin'ny alΓ lan'ny fiasa tcg_qemu_tb_exec, hita fa tena nahasoa ahy.

Raha te hampiditra backend TCG vaovao amin'ny QEMU ianao dia mila mamorona subdirectory tcg/<имя Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹> (raha izany dia, tcg/binaryen), ary misy rakitra roa: tcg-target.h ΠΈ tcg-target.inc.c ΠΈ fanafody momba izany rehetra izany configure. Azonao atao ny mametraka rakitra hafa ao, fa, araka ny azonao vinavinaina amin'ny anaran'ireo roa ireo, dia samy ho tafiditra any amin'ny toerana iray izy ireo: ny iray ho toy ny fisie lohan-doha mahazatra (misy ao amin'ny tcg/tcg.h, ary efa ao anaty rakitra hafa ao amin'ny lahatahiry tcg, accel ary tsy ihany), ny iray hafa - ho toy ny sombin-kaody ao anatiny tcg/tcg.c, fa manana fahafahana miditra amin'ny fiasa static.

Nanapa-kevitra aho fa handany fotoana be loatra amin'ny fanadihadiana amin'ny antsipiriany momba ny fomba fiasan'izy io, dia nandika tsotra izao ny "skeleton" an'ireo rakitra roa ireo avy amin'ny fampiharana backend hafa aho, ary nanondro marina izany tao amin'ny lohatenin'ny fahazoan-dΓ lana.

rakitra tcg-target.h mirakitra indrindra indrindra amin'ny endrika #define-s:

  • firy ny rejisitra ary firy ny sakany ao amin'ny maritrano kendrena (manana betsaka araka izay irinay izahay, araka izay irinay - ny fanontaniana dia bebe kokoa momba ny zavatra ho ateraky ny kaody mahomby kokoa amin'ny navigateur amin'ny maritrano "kendrena tanteraka". ...)
  • fampifanarahana ny toromarika mpampiantrano: amin'ny x86, ary na dia ao amin'ny TCI aza, ny torolΓ lana dia tsy mifanaraka mihitsy, fa ny code buffer no hataoko fa tsy ny torolΓ lana mihitsy, fa manondro ny rafitra tranomboky Binaryen, ka hoy aho: 4 oktety
  • inona no torolalana azo atao ateraky ny backend - ampidirintsika ao amin'ny Binaryen daholo ny zavatra rehetra hitanay, avelao ny accelerator hamaky ny ambiny ho tsotra kokoa
  • Ohatrinona ny haben'ny cache TLB nangatahan'ny backend. Ny zava-misy dia ao amin'ny QEMU ny zava-drehetra dia matotra: na dia misy aza ny asa mpanampy izay manatanteraka ny entana / fivarotana amin'ny fiheverana ny MMU vahiny (aiza isika raha tsy misy izany ankehitriny?), Mitahiry ny cache fandikana azy ireo amin'ny endrika rafitra, ny ny fanodinana azy dia mety raha ampidirina mivantana amin'ny sakana fampielezam-peo. Ny fanontaniana dia hoe, inona ny offset amin'ity rafitra ity no tena karakaraina amin'ny alΓ lan'ny filaharana kely sy haingana?
  • eto dia azonao atao ny manitsy ny tanjon'ny rejisitra voatokana iray na roa, mamela ny fiantsoana ny TB amin'ny alΓ lan'ny fiasa iray ary azo atao ny mamaritra ny kely roa. inline- miasa toy ny flush_icache_range (fa tsy izany no raharahanay)

rakitra tcg-target.inc.c, mazava ho azy, matetika dia lehibe kokoa ny habeny ary misy asa tsy maintsy atao:

  • fanombohana, ao anatin'izany ny fameperana izay ahafahan'ny toromarika miasa amin'izay operand. Nadikako mibaribary avy any aoriana hafa
  • asa izay mitaky fampianarana bytecode anatiny
  • Azonao atao koa ny mametraka fiasa fanampiny eto, ary azonao atao koa ny mampiasa fiasa static avy amin'ny tcg/tcg.c

Ho an'ny tenako, dia nisafidy ity tetika manaraka ity aho: tamin'ny teny voalohany amin'ny andian-dahatsoratra manaraka dia nanoratra tondro efatra aho: marika fanombohana (sarobidy iray eo amin'ny manodidina. 0xFFFFFFFF, izay namaritra ny toetry ny TB amin'izao fotoana izao), ny contexte, ny maody novokarina, ary ny laharan'ny majika ho an'ny debugging. Tamin'ny voalohany dia napetraka ny marika 0xFFFFFFFF - nizay n - isa tsara kely, ary isaky ny novonoina tamin'ny alalan'ny mpandika teny dia nitombo 1. Rehefa tonga 0xFFFFFFFE, nitranga ny fanangonana, voatahiry ao amin'ny latabatra fiasa ny maody, nafarana tao anaty "launcher" kely, izay niaingan'ny famonoana. tcg_qemu_tb_exec, ary nesorina tao amin'ny fitadidiana QEMU ilay maody.

Mba hamaritana ny klasika, "Crutch, ohatrinona no mifamatotra amin'ity feo ity ho an'ny fon'ny proger ...". Na izany aza, nipoitra tany ho any ny fahatsiarovana. Ambonin'izany, fitadidiana nokarakarain'ny QEMU! Nanana kaody aho izay, rehefa nanoratra ny toromarika manaraka (eny, izany hoe pointer), dia nesoriko ilay iray izay nisy rohy tao amin'ity toerana ity teo aloha, saingy tsy nanampy izany. Raha ny marina, amin'ny tranga tsotra indrindra, ny QEMU dia manome fahatsiarovana amin'ny fanombohana ary manoratra ny code novokarina ao. Rehefa lany ny buffer dia ariana ny kaody ary manomboka soratana eo amin'ny toerany ny manaraka.

Rehefa avy nandinika ny kaody aho dia tsapako fa ny fika miaraka amin'ny isa majika dia namela ahy tsy hahomby amin'ny famotehana amboara amin'ny alΓ lan'ny famotsorana zavatra tsy mety amin'ny buffer tsy fantatra amin'ny lalana voalohany. Fa iza no mamerina manoratra ny buffer mba hialana amin'ny asako any aoriana? Araka ny torohevitry ny mpamorona Emscripten, rehefa sendra olana aho, dia namerina ny kaody vokarina tany amin'ny fampiharana teratany aho, nametraka Mozilla Record-Replay teo aminy... Amin'ny ankapobeny, tamin'ny farany dia nahatsapa zavatra tsotra aho: ho an'ny sakana tsirairay, ny struct TranslationBlock miaraka amin'ny famaritana azy. Eritrereto hoe aiza... Marina izany, eo anoloan'ny sakana eo amin'ny buffer. Tsapako izany dia nanapa-kevitra ny hiala amin'ny fampiasana tehina aho (farafaharatsiny sasany), ary nariako fotsiny ilay isa majika, ary nafindrako ny teny sisa tavela tamin'ny struct TranslationBlock, mamorona lisitra mifamatotra tokana izay azo tsidihana haingana rehefa averina ny cache fandikan-teny, ary manafaka ny fitadidiana.

Misy tehina sisa tavela: ohatra, tondro voamarika ao amin'ny buffer code - tsotra fotsiny ny sasany amin'izy ireo BinaryenExpressionRef, izany hoe mijery ireo fitenenana mila apetraka amin'ny tsipika fototra novokarina izy ireo, ny ampahany dia ny fepetran'ny tetezamita eo amin'ny BBs, ny ampahany dia ny toerana haleha. Eny ary, efa misy bloc voaomana ho an'ny Relooper izay mila mifandray amin'ny fepetra. Mba hanavahana azy ireo dia ampiasaina ny fiheverana fa mifanaraka amin'ny bytes efatra farafahakeliny izy rehetra, mba hahafahanao mampiasa ny bitika roa faran'izay manan-danja indrindra ho an'ny marika, mila tadidinao fotsiny ny manala azy raha ilaina. Raha ny marina, ny marika toy izany dia efa ampiasaina ao amin'ny QEMU mba hanondroana ny antony hialana amin'ny TCG loop.

Mampiasa Binaryen

Ny Modules ao amin'ny WebAssembly dia misy fiasa, izay samy misy vatana, izay fanehoana. Ny fanehoan-kevitra dia hetsika unary sy mimari-droa, sakana misy lisitry ny fanehoan-kevitra hafa, fanaraha-maso ny fandehanana, sns. Araka ny efa nolazaiko, ny fikorianan'ny fanaraha-maso eto dia voalamina tsara ho sampana avo lenta, tadivavarana, antso an-tariby, sns. Ny adihevitra momba ny asa dia tsy alefa amin'ny stack, fa mazava, toy ny ao amin'ny JS. Misy ihany koa ny fari-piainana manerantany, saingy tsy nampiasa azy ireo aho, noho izany dia tsy holazaiko aminao ny momba azy ireo.

Ny fiasa koa dia manana fari-pitsipika eo an-toerana, isaina manomboka amin'ny aotra, misy karazana: int32 / int64 / float / double. Amin'ity tranga ity, ny n variable eo an-toerana voalohany dia ny hevitra nampitaina tamin'ny asa. Mariho fa na dia tsy ambany loatra aza ny zava-drehetra eto amin'ny resaka fikorianan'ny fanaraha-maso, ny integer dia mbola tsy mitondra ny toetra "voasonia / tsy misy sonia": miankina amin'ny fehezan-dalΓ na momba ny asa ny fomba fitondran'ny isa.

Amin'ny ankapobeny, ny Binaryen dia manome tsotra C-API: mamorona module ianao, ao aminy mamorona fanehoan-kevitra - unary, binary, sakana avy amin'ny fanehoan-kevitra hafa, fanaraha-maso ny fandehanana, sns. Avy eo ianao dia mamorona fiasa misy fitenenana ho vatany. Raha toa ianao, toa ahy, manana grafika tetezamita ambany, dia hanampy anao ny singa relooper. Raha ny fahazoako azy dia azo atao ny mampiasa fanaraha-maso avo lenta amin'ny fikorianan'ny famonoana amin'ny sakana, raha mbola tsy mihoatra ny sisin'ny sakana - izany hoe azo atao ny manao lalana haingana / miadana anatiny lalana sampana ao anatin'ny kaody fanodinana cache TLB naorina, fa tsy hanelingelina ny fikorianan'ny fanaraha-maso "ivelany". Rehefa manafaka relooper ianao, dia afaka ny sakanany; rehefa manafaka mody iray ianao, dia hanjavona ny fomba fiteny, ny fiasa, sns. kianja.

Na izany aza, raha te-handika ny kaody amin'ny lalitra tsy misy famoronana tsy ilaina sy famafana ohatra mpandika teny ianao, dia mety misy dikany ny mametraka an'io lojika io ao anaty rakitra C ++, ary avy eo dia mitantana mivantana ny C ++ API ao amin'ny tranomboky, miala amin'ny vonona- natao fonosina.

Ka hamorona ny kaody ilainao

// Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ (ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΏΠΎΡ‚ΠΎΠΌ)
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);

... raha misy adinoko, miala tsiny, mba hanehoana ny mizana fotsiny ity, ary ao amin'ny antontan-taratasy ny antsipiriany.

Ary manomboka izao ny crack-fex-pex, toy izao:

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

Mba hampifandraisana ny tontolon'ny QEMU sy JS ary miaraka amin'izay koa ny fidirana haingana amin'ireo fiasa voaangona, dia nisy array iray noforonina (latabatra misy fiasa ho an'ny fanafarana ho any amin'ny mpandefa), ary napetraka ao ireo fiasa novokarina. Mba hanaovana kajy haingana ny fanondroana, dia nampiasaina tamin'ny voalohany ny index of the zero word translation block, fa avy eo ny index calculation mampiasa an'io formula io dia nanomboka nifanaraka fotsiny tamin'ny saha amin'ny struct TranslationBlock.

Raha eny, Demo (miaraka amin'ny fahazoan-dΓ lana manjavozavo amin'izao fotoana izao) ao amin'ny Firefox ihany no miasa tsara. Ny mpamorona Chrome dia toa tsy vonona amin'ny hoe misy olona maniry hamorona ohatra maherin'ny arivo amin'ny maodely WebAssembly, noho izany dia nomeny fotsiny ny habaka adiresy virtoaly gigabyte ho an'ny tsirairay...

Izay ihany aloha izao. Mbola hisy lahatsoratra hafa angamba raha misy liana. Izany hoe, mbola misy farafaharatsiny ihany ataovy miasa ny fitaovana block. Mety misy dikany ihany koa ny manao ny fanangonana ny mody WebAssembly ho asynchronous, toy ny mahazatra ao amin'ny tontolon'ny JS, satria mbola misy mpandika teny afaka manao izany rehetra izany mandra-pahavitan'ny mody teratany.

Farany ankamantatra: nanangona binary amin'ny maritrano 32-bit ianao, fa ny code, amin'ny alΓ lan'ny asa fitadidiana, dia miakatra avy any Binaryen, any amin'ny toerana iray eo amin'ny stack, na any amin'ny toerana hafa ao amin'ny 2 GB ambony amin'ny habaka adiresy 32-bit. Ny olana dia ny fomba fijerin'i Binaryen dia miditra amin'ny adiresy lehibe loatra. Ahoana ny fomba hialana amin'izany?

Amin'ny fomba admin

Tsy nanandrana izany aho, fa ny eritreritro voalohany dia "Ahoana raha nametraka Linux 32-bit aho?" Avy eo ny ampahany ambony amin'ny habaka adiresy dia hofehezin'ny kernel. Ny hany fanontaniana dia hoe ohatrinona no hobodoina: 1 na 2 Gb.

Amin'ny fomban'ny programmer (safidy ho an'ny mpitsabo)

Andao hitsoka bubble eo an-tampon'ny habaka adiresy. Ny tenako dia tsy azoko hoe nahoana izany no miasa - eo efa tsy maintsy misy stack. Saingy "mpanao fanao izahay: miasa ho anay ny zava-drehetra, saingy tsy misy mahalala ny antony..."

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

... marina fa tsy mifanaraka amin'ny Valgrind izany, saingy, soa ihany, ny Valgrind mihitsy no manosika ny olona rehetra hiala ao :)

Angamba hisy hanome fanazavana tsara kokoa momba ny fomba fiasan'ity code-ko ity ...

Source: www.habr.com

Add a comment