QEMU.js: saiki serius lan nganggo WASM

Biyen aku mutusake kanggo seneng-seneng mbuktekaken reversibility saka proses lan sinau carane nggawe JavaScript (luwih tepat, Asm.js) saka kode mesin. QEMU dipilih kanggo eksperimen, lan sawetara wektu mengko ana artikel ditulis ing Habr. Ing komentar, aku disaranake nggawe ulang proyek kasebut ing WebAssembly, lan malah mandheg meh rampung Aku piye wae ora pengin proyek kasebut ... Karya kasebut ditindakake, nanging alon-alon, lan saiki, bubar ing artikel kasebut muncul komentar ing topik "Dadi kepiye kabeh rampung?" Nanggepi jawaban rinci, aku krungu "Iki muni kaya artikel." Inggih, yen sampeyan bisa, bakal ana artikel. Mungkin wong bakal nemokake migunani. Saka iku, sing maca bakal sinau sawetara fakta babagan desain backend generasi kode QEMU, uga carane nulis kompiler Just-in-Time kanggo aplikasi web.

tugas

Amarga aku wis sinau babagan "piye wae" port QEMU menyang JavaScript, wektu iki diputusake kanggo nindakake kanthi wicaksana lan ora mbaleni kesalahan lawas.

Kesalahan nomer siji: cabang saka release titik

Kesalahanku sing sepisanan yaiku ngganti versiku saka versi hulu 2.4.1. Banjur aku dadi ide sing apik: yen ana release titik, mula bisa uga luwih stabil tinimbang 2.4 sing gampang, lan luwih akeh cabang. master. Lan wiwit aku ngrancang kanggo nambah jumlah cukup saka kewan omo dhewe, Aku ora perlu wong liya ing kabeh. Mesthine kaya ngono. Nanging iki: QEMU ora mandheg, lan ing sawetara wektu dheweke malah ngumumake optimasi kode sing digawe kanthi persen 10. "Ya, saiki aku bakal beku," pikirku lan rusak. Ing kene kita kudu nggawe digression: amarga sifat siji-Utas QEMU.js lan kasunyatan QEMU asli ora ateges ora ana multi-threading (yaiku, kemampuan kanggo ngoperasikake sawetara jalur kode sing ora ana hubungane, lan ora mung "nggunakake kabeh kernels") kritis iku, fungsi utama Utas aku kudu "nguripake" kanggo bisa nelpon saka njaba. Iki nggawe sawetara masalah alam sajrone penggabungan. Nanging, kasunyatan sing sawetara saka owah-owahan saka cabang master, karo kang aku nyoba kanggo nggabungake kode sandi, padha uga Cherry ngangkat ing release titik (lan mulane ing cabang) uga mbokmenawa ora nambah penak.

Umumé, aku mutusake manawa isih ana gunane kanggo mbuwang prototipe, mbongkar bagean kasebut lan mbangun versi anyar saka awal adhedhasar sing luwih seger lan saiki saka master.

Kesalahan nomer loro: metodologi TLP

Intine, iki dudu kesalahan, umume, mung minangka fitur nggawe proyek ing kahanan kesalahpahaman lengkap babagan "ing endi lan kepiye pindhah?" Lan umume "apa kita bakal teka?" Ing kahanan kasebut pemrograman kikuk ana pilihan sabdho, nanging, alamiah, aku ora pengin mbaleni iku ora perlu. Wektu iki aku pengin nindakake kanthi wicaksana: komitmen atom, owah-owahan kode sadar (lan ora "nggabungake karakter acak nganti kompilasi (karo bebaya)", kaya sing dikandhakake Linus Torvalds babagan sapa wae, miturut Wikiquote), lsp.

Kesalahan nomer telu: mlebu ing banyu tanpa ngerti ford

Aku isih durung nyingkirake iki, nanging saiki aku mutusake supaya ora ngetutake dalan sing paling ora tahan, lan nindakake "minangka wong diwasa," yaiku nulis backend TCG saka awal, supaya ora kudu ngomong mengko, "Ya, iki mesthi, alon-alon, nanging aku ora bisa ngontrol kabeh - kaya ngono TCI ditulis ..." Kajaba iku, iki pisanan katon kaya solusi sing jelas, amarga Aku nggawe kode binar. Kaya sing dikandhakake, "Ghent kumpulу, nanging ora sing siji ": kode iku, mesthi, binar, nanging kontrol ora bisa mung ditransfer menyang - iku kudu eksplisit di-push menyang browser kanggo kompilasi, asil ing obyek tartamtu saka donya JS, kang isih perlu kanggo disimpen nang endi wae. Nanging, ing arsitektur RISC normal, sawayah-wayah aku ngerti, kahanan sing khas yaiku kudu ngreset cache instruksi kanthi jelas kanggo kode regenerasi - yen iki dudu sing dibutuhake, mula, ing kasus apa wae, wis cedhak. Kajaba iku, saka upaya pungkasan, aku sinau manawa kontrol kayane ora ditransfer menyang tengah blok terjemahan, mula kita ora mbutuhake bytecode sing diinterpretasikake saka offset, lan kita mung bisa ngasilake saka fungsi ing TB. .

Padha teka lan kicked

Sanajan aku wiwit nulis maneh kode kasebut ing wulan Juli, ana tendhangan sihir sing ora dingerteni: biasane surat saka GitHub teka minangka kabar babagan tanggapan babagan Panjaluk Masalah lan Tarik, nanging ing kene, dumadakan sebutno ing thread Binaryen minangka backend qemu ing konteks, "Dheweke nindakake kaya ngono, mungkin dheweke bakal ujar." Kita ngomong babagan nggunakake perpustakaan sing gegandhengan karo Emscripten binaryan kanggo nggawe WASM JIT. Inggih, Aku ngandika sing duwe Apache 2.0 lisensi ana, lan QEMU minangka kabèh disebaraké ing GPLv2, lan padha ora banget kompatibel. Dumadakan ternyata lisensi bisa ndandani iku piye wae (Aku ora ngerti: bisa ngganti, bisa dual lisensi, bisa mergo ...). Iki, mesthi, nggawe aku seneng, amarga ing wektu iku aku wis katon cedhak format binar WebAssembly, lan aku piye wae sedih lan ora bisa dingerteni. Ana uga perpustakaan sing bakal mangan pamblokiran dhasar karo grafik transisi, gawé bytecode, lan malah mbukak ing interpreter dhewe, yen perlu.

Banjur ana liyane huruf ing milis QEMU, nanging iki luwih akeh babagan pitakonan, "Sapa wae sing butuh?" Lan iku dumadakan, pranyata iku perlu. Paling ora, sampeyan bisa ngeruk kemungkinan panggunaan ing ngisor iki, yen bisa dianggo luwih cepet utawa kurang:

  • miwiti soko pendidikan tanpa instalasi ing kabeh
  • virtualisasi ing iOS, ing ngendi, miturut gosip, siji-sijine aplikasi sing duwe hak nggawe kode kanthi cepet yaiku mesin JS (apa iki bener?)
  • demonstrasi mini-OS - single-floppy, built-in, kabeh jinis firmware, lsp...

Fitur Browser Runtime

Kaya sing wis dakkandhakake, QEMU diikat karo multithreading, nanging browser ora duwe. Ya, ora ... Wiwitane ora ana, banjur muncul WebWorkers - sing aku ngerti, iki multithreading adhedhasar pesen sing dikirim. tanpa variabel sing dienggo bareng. Alami, iki nggawe masalah sing signifikan nalika ngirim kode sing ana adhedhasar model memori sing dienggo bareng. Banjur, ing tekanan umum, uga ditindakake kanthi jeneng kasebut SharedArrayBuffers. Iki mboko sithik ngenalaken, padha ngrayakake sawijining Bukak ing browser beda, banjur padha ngrayakake Taun Anyar, lan banjur Meltdown ... Sawise padha teka menyang kesimpulan sing coarse utawa coarse pangukuran wektu, nanging karo bantuan saka memori sambungan lan a thread incrementing counter, iku kabeh padha bakal bisa metu cukup akurat. Dadi, kita mateni multithreading kanthi memori sing dienggo bareng. Iku misale jek sing mengko padha nguripake maneh, nanging, minangka wis cetha saka eksperimen pisanan, ana urip tanpa iku, lan yen mangkono, kita bakal nyoba kanggo nindakake tanpa gumantung ing multithreading.

Fitur kapindho yaiku mokal manipulasi tingkat rendah kanthi tumpukan: sampeyan ora bisa mung njupuk, nyimpen konteks saiki lan ngalih menyang sing anyar kanthi tumpukan anyar. Tumpukan telpon dikelola dening mesin virtual JS. Iku bakal katon, apa masalah, awit kita isih mutusaké kanggo ngatur mantan mili rampung kanthi manual? Kasunyatane yaiku pemblokiran I / O ing QEMU ditindakake liwat coroutines, lan ing kene manipulasi tumpukan tingkat rendah bakal migunani. Untunge, Emscipten wis ngemot mekanisme kanggo operasi asinkron, malah loro: Asyncify и Emterpreter. Sing pertama kerjane liwat kembung sing signifikan ing kode JavaScript sing digawe lan ora didhukung maneh. Kapindho yaiku "cara sing bener" saiki lan bisa digunakake liwat generasi bytecode kanggo interpreter asli. Kerjane, mesthi, alon, nanging ora bloat kode. Bener, dhukungan kanggo coroutine kanggo mekanisme iki kudu disumbang kanthi mandiri (wis ana coroutine sing ditulis kanggo Asyncify lan ana implementasine kira-kira API sing padha kanggo Emterpreter, sampeyan mung kudu nyambungake).

Saiki, aku durung bisa mbagi kode kasebut dadi siji sing disusun ing WASM lan diinterpretasikake nggunakake Emterpreter, supaya piranti pamblokiran durung bisa digunakake (ndeleng ing seri sabanjure, kaya sing diucapake ...). Yaiku, ing pungkasan sampeyan kudu entuk kaya lapisan sing lucu iki:

  • diinterpretasikake blok I/O. Ya, apa sampeyan ngarepake NVMe sing ditiru kanthi kinerja asli? 🙂
  • kode QEMU utama sing disusun kanthi statis (penerjemah, piranti tiru liyane, lsp.)
  • kode tamu disusun kanthi dinamis menyang WASM

Fitur sumber QEMU

Sing mbokmenawa wis guessed, kode kanggo emulating arsitektur tamu lan kode kanggo ngasilaken instruksi mesin inang dipisahake ing QEMU. Ing kasunyatan, iku malah sethitik trickier:

  • ana arsitektur tamu
  • ana akselerator, yaiku, KVM kanggo virtualisasi hardware ing Linux (kanggo sistem tamu lan inang sing kompatibel karo saben liyane), TCG kanggo JIT kode generasi ngendi wae. Miwiti karo QEMU 2.9, dhukungan kanggo standar virtualisasi hardware HAXM ing Windows katon (rincian)
  • yen TCG digunakake lan dudu virtualisasi hardware, banjur duwe dhukungan generasi kode sing kapisah kanggo saben arsitektur host, uga kanggo interpreter universal
  • ... lan kabeh iki - peripheral sing ditiru, antarmuka pangguna, migrasi, rekaman-muter maneh, lsp.

Miturut cara, sampeyan ngerti: QEMU bisa niru ora mung kabeh komputer, nanging uga prosesor kanggo proses pangguna sing kapisah ing kernel inang, sing digunakake, contone, dening fuzzer AFL kanggo instrumentasi binar. Mbok menawa ana sing pengin port mode operasi QEMU iki menyang JS? 😉

Kaya piranti lunak gratis sing wis suwe, QEMU dibangun liwat telpon configure и make. Ayo dadi ngomong sampeyan arep kanggo nambah soko: backend TCG, implementasine thread, mergo. Aja cepet-cepet seneng / medeni (garis ngisor yen cocog) nalika ngarepake komunikasi karo Autoconf - nyatane, configure QEMU ketoke ditulis dhewe lan ora digawe saka apa wae.

WebAss Assembly

Dadi apa sing diarani WebAssembly (aka WASM)? Iki minangka panggantos kanggo Asm.js, ora pura-pura dadi kode JavaScript sing sah. Kosok baline, iku murni binar lan dioptimalake, lan malah mung nulis integer menyang iku ora banget prasaja: kanggo compactness, disimpen ing format LEB128.

Sampeyan bisa uga wis krungu babagan algoritma relooping kanggo Asm.js - iki minangka pemugaran instruksi kontrol aliran "tingkat dhuwur" (yaiku, yen-banjur-liyane, puteran, lan sapiturute), sing mesin JS dirancang, saka tingkat kurang LLVM IR, nyedhaki kode mesin kaleksanan dening prosesor. Mesthine, perwakilan penengah QEMU luwih cedhak karo nomer loro. Iku bakal katon sing kene iku, bytecode, mburi siksa ... Lan banjur ana pamblokiran, yen-banjur-liyane lan puteran!..

Lan iki minangka alesan liyane kenapa Binaryen migunani: bisa kanthi alami nampa pamblokiran tingkat dhuwur sing cedhak karo sing bakal disimpen ing WASM. Nanging uga bisa ngasilake kode saka grafik blok dhasar lan transisi ing antarane. Inggih, Aku wis ngandika sing ndhelikake format panyimpenan WebAssembly konco C / C ++ API trep.

TCG (Tiny Code Generator)

GTC asline backend kanggo compiler C. Banjur, ketoke, iku ora bisa tahan kompetisi karo GCC, nanging ing pungkasan ketemu Panggonan ing QEMU minangka mekanisme generasi kode kanggo platform inang. Ana uga backend TCG sing ngasilake sawetara bytecode abstrak, sing langsung dieksekusi dening interpreter, nanging aku mutusake supaya ora nggunakake wektu iki. Nanging, kasunyatan sing ing QEMU wis bisa kanggo ngaktifake transisi menyang TB kui liwat fungsi tcg_qemu_tb_exec, ternyata migunani banget kanggo aku.

Kanggo nambah backend TCG anyar menyang QEMU, sampeyan kudu nggawe subdirektori tcg/<имя архитектуры> (ing kasus iki, tcg/binaryen), lan ngemot rong file: tcg-target.h и tcg-target.inc.c и menehi resep iku kabeh babagan configure. Sampeyan bisa nyelehake file liyane ing kana, nanging, kaya sing bisa ditebak saka jeneng loro kasebut, loro-lorone bakal kalebu ing endi wae: siji minangka file header biasa (kalebu ing tcg/tcg.h, lan sing siji wis ana ing file liyane ing direktori tcg, accel lan ora mung), liyane - mung minangka snippet kode ing tcg/tcg.c, nanging nduweni akses menyang fungsi statis.

Nemtokake yen aku bakal nglampahi wektu akeh kanggo investigasi rinci babagan cara kerjane, aku mung nyalin "kerangka" saka rong file kasebut saka implementasine backend liyane, kanthi jujur ​​​​nuduhake iki ing header lisensi.

berkas tcg-target.h ngandhut utamané setelan ing wangun #define-s:

  • pinten ndhaptar lan jembar apa sing ana ing arsitektur target (kita duwe akeh sing dikarepake, kaya sing dikarepake - pitakonan luwih akeh babagan apa sing bakal diasilake dadi kode sing luwih efisien dening browser ing arsitektur "target rampung" ...)
  • alignment instruksi inang: ing x86, lan malah ing TCI, instruksi ora didadekake siji ing kabeh, nanging aku bakal sijine ing buffer kode ora instruksi ing kabeh, nanging penunjuk kanggo struktur perpustakaan Binaryen, aku bakal ngomong: 4 bita
  • instruksi opsional apa sing bisa diasilake backend - kita nyakup kabeh sing ditemokake ing Binaryen, supaya akselerator ngeculake liyane dadi sing luwih gampang.
  • Apa ukuran kira-kira cache TLB sing dijaluk backend. Kasunyatane yaiku ing QEMU kabeh serius: sanajan ana fungsi helper sing nindakake beban / nyimpen kanthi njupuk MMU tamu (ngendi kita bakal tanpa saiki?), Dheweke nyimpen cache terjemahan ing wangun struktur, pangolahan sing trep kanggo nampilake langsung menyang blok siaran. Pitakonan iki, apa offset ing struktur iki paling irit diproses dening urutan cilik lan cepet saka printah?
  • kene sampeyan bisa ngapiki tujuan siji utawa loro ndhaptar reserved, mbisakake nelpon TB liwat fungsi lan opsional njlèntrèhaké saperangan cilik. inline-fungsi kaya flush_icache_range (nanging iki dudu kasus kita)

berkas tcg-target.inc.c, mesthi, ukurane luwih gedhe lan ngemot sawetara fungsi wajib:

  • initialization, kalebu watesan sing instruksi bisa operate ing operan. Blatantly disalin dening kula saka backend liyane
  • fungsi sing njupuk siji instruksi bytecode internal
  • Sampeyan uga bisa sijine fungsi tambahan kene, lan sampeyan uga bisa nggunakake fungsi statis saka tcg/tcg.c

Kanggo aku, aku milih strategi ing ngisor iki: ing tembung pisanan saka blok terjemahan sabanjure, aku nulis papat pitunjuk: tandha wiwitan (nilai tartamtu ing sacedhake 0xFFFFFFFF, sing nemtokake kahanan saiki TB), konteks, modul sing digawe, lan nomer ajaib kanggo debugging. Ing kawitan tandha diselehake ing 0xFFFFFFFF - nngendi n - nomer positif cilik, lan saben-saben dieksekusi liwat interpreter tambah 1. Nalika tekan 0xFFFFFFFE, kompilasi dumadi, modul kasebut disimpen ing tabel fungsi, diimpor menyang "peluncur" cilik, ing ngendi eksekusi diwiwiti. tcg_qemu_tb_exec, lan modul dibusak saka memori QEMU.

Kanggo paraphrase klasik, "Crutch, carane akeh intertwined ing swara iki kanggo jantung proger ...". Nanging, memori kasebut bocor ing endi wae. Menapa malih, punika memori dikelola dening QEMU! Aku duwe kode sing, nalika nulis instruksi sabanjure (uga, yaiku, pointer), mbusak link sing ana ing panggonan iki sadurunge, nanging iki ora mbantu. Bener, ing kasus sing paling gampang, QEMU nyedhiyakake memori nalika wiwitan lan nulis kode sing digawe ing kana. Nalika buffer entek, kode dibuwang lan sing sabanjure wiwit ditulis ing panggonane.

Sawise sinau kode, Aku temen maujud sing trick karo nomer tenung ngidini kula ora gagal ing numpuk karusakan dening freeing soko salah ing buffer uninitialized ing pass pisanan. Nanging sing rewrites buffer kanggo lulus fungsi sandi mengko? Minangka pangembang Emscripten menehi saran, nalika aku nemoni masalah, aku ngirim kode sing diasilake bali menyang aplikasi asli, nyetel Mozilla Record-Replay ing ... Umumé, ing pungkasan aku nyadari bab sing prasaja: kanggo saben blok, a struct TranslationBlock kanthi katrangane. Tebak ngendi... Sing bener, sakdurunge pemblokiran tengen ing buffer. Sadhar iki, aku mutusaké kanggo mandhek nggunakake crutches (paling ora sawetara), lan mung uncalan metu nomer tenung, lan nransfer tembung isih kanggo struct TranslationBlock, nggawe dhaptar sing disambung siji-sijine sing bisa dilewati kanthi cepet nalika cache terjemahan direset, lan mbebasake memori.

Sawetara crutches tetep: contone, tandha tandha ing buffer kode - sawetara iku mung BinaryenExpressionRef, sing, padha katon ing ungkapan sing kudu linearly sijine menyang pemblokiran dhasar kui, part iku kondisi kanggo transisi antarane BBs, part ngendi kanggo pindhah. Ya, wis ana blok sing disiapake kanggo Relooper sing kudu disambungake miturut kahanan. Kanggo mbedakake, asumsi digunakake sing kabeh didadekake siji dening paling patang bait, supaya sampeyan bisa kanthi aman nggunakake rong bit paling pinunjul kanggo label, sampeyan mung kudu ngelingi mbusak yen perlu. Miturut cara, label kasebut wis digunakake ing QEMU kanggo nuduhake alasan kanggo metu saka loop TCG.

Nggunakake Binaryen

Modul ing WebAssembly ngemot fungsi, saben-saben ngemot awak, yaiku ekspresi. Ekspresi minangka operasi unary lan binar, blok sing kalebu dhaptar ekspresi liyane, aliran kontrol, lsp. Kaya sing wis dakkandhakake, aliran kontrol ing kene diatur kanthi tepat minangka cabang tingkat dhuwur, puteran, panggilan fungsi, lsp. Argumen kanggo fungsi ora diterusake ing tumpukan, nanging kanthi tegas, kaya ing JS. Ana uga variabel global, nanging aku wis ora digunakake, supaya aku ora bakal pitutur marang kowe bab mau.

Fungsi uga duwe variabel lokal, nomer saka nol, saka jinis: int32 / int64 / float / pindho. Ing kasus iki, variabel lokal pisanan yaiku argumen sing diterusake menyang fungsi kasebut. Wigati dimangerteni manawa kabeh ing kene ora kabeh tingkat rendah babagan aliran kontrol, integer isih ora nggawa atribut "tandatangani / ora ditandatangani": kepiye nomer kasebut gumantung ing kode operasi.

Umumé, Binaryen nyedhiyakake prasaja C-API: sampeyan nggawe modul, ing dheweke nggawe ekspresi - unary, binar, blok saka ekspresi liyane, aliran kontrol, lsp. Banjur sampeyan nggawe fungsi kanthi ekspresi minangka awak. Yen sampeyan, kaya aku, duwe grafik transisi tingkat rendah, komponen relooper bakal mbantu sampeyan. Sa adoh aku ngerti, iku bisa kanggo nggunakake kontrol tingkat dhuwur saka aliran eksekusi ing pemblokiran, anggere ora ngluwihi wates pamblokiran - sing, iku bisa kanggo nggawe internal path cepet / alon. path ngepang nang kode Processing cache TLB dibangun ing, nanging ora ngganggu aliran kontrol "njaba". Nalika sampeyan mbebasake relooper, pamblokiran bakal dibebasake; yen sampeyan mbebasake modul, ekspresi, fungsi, lan liya-liyane sing diparengake bakal ilang. arena.

Nanging, yen sampeyan pengin kokwaca kode ing fly tanpa nggawe rasah lan pambusakan saka Kayata interpreter, iku bisa nggawe pangertèn kanggo sijine logika iki menyang file C ++, lan saka ing kono langsung ngatur kabeh C ++ API perpustakaan, bypassing siap- digawe bungkus.

Dadi kanggo ngasilake kode sing sampeyan butuhake

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

... yen aku lali apa-apa, nuwun, iki mung kanggo makili skala, lan rincian ana ing dokumentasi.

Lan saiki crack-fex-pex diwiwiti, kaya iki:

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

Supaya bisa nyambungake jagad QEMU lan JS lan ing wektu sing padha ngakses fungsi sing dikompilasi kanthi cepet, array digawe (tabel fungsi kanggo ngimpor menyang peluncur), lan fungsi sing digawe diselehake ing kana. Kanggo ngetung indeks kanthi cepet, indeks blok terjemahan tembung nol wiwitane digunakake, nanging banjur indeks sing diitung nggunakake rumus iki wiwit pas karo lapangan ing struct TranslationBlock.

Miturut cara, demo (saiki nganggo lisensi murky) mung bisa digunakake ing Firefox. pangembang Chrome padha piye wae ora siap kanggo kasunyatan manawa ana wong sing pengin nggawe luwih saka sewu conto modul WebAssembly, mula mung menehi ruang alamat virtual gigabyte kanggo saben ...

Semono wae. Mbok menawi wonten artikel malih menawi wonten ingkang minat. Yaiku, isih ana paling ora mung nggawe piranti pamblokiran bisa. Sampeyan bisa uga nggawe pangertèn kanggo nggawe kompilasi modul WebAssembly ora sinkron, kaya biasane ing donya JS, amarga isih ana juru basa sing bisa nindakake kabeh iki nganti modul asli wis siyap.

Akhire teka-teki: sampeyan wis nyawiji binar ing arsitektur 32-dicokot, nanging kode, liwat operasi memori, climbs saka Binaryen, nang endi wae ing tumpukan, utawa nang endi wae ing ndhuwur 2 GB saka papan alamat 32-dicokot. Masalahe yaiku yen saka sudut pandang Binaryen iki ngakses alamat sing gedhe banget. Carane njaluk watara iki?

Kanthi cara admin

Aku ora mungkasi nyoba iki, nanging pikiranku pisanan yaiku "Apa yen aku nginstal Linux 32-bit?" Banjur bagean ndhuwur papan alamat bakal dikuwasani dening kernel. Pitakonan mung pira sing bakal dikuwasani: 1 utawa 2 Gb.

Kanthi cara programer (opsi kanggo praktisi)

Ayo nyebul gelembung ing ndhuwur papan alamat. Aku dhewe ora ngerti kenapa bisa - ana wis kudu ana tumpukan. Nanging "kita minangka praktisi: kabeh bisa digunakake kanggo kita, nanging ora ana sing ngerti sebabe ..."

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

... pancen ora kompatibel karo Valgrind, nanging, untunge, Valgrind dhewe kanthi efektif nyurung kabeh wong metu saka kono :)

Mbok menawa ana sing bakal menehi panjelasan sing luwih apik babagan cara kodeku iki ...

Source: www.habr.com

Add a comment