QEMU.js: ayeuna serius sareng WASM

Sakali waktu kuring mutuskeun pikeun senang ngabuktikeun reversibility tina prosés sarta diajar kumaha carana ngahasilkeun JavaScript (leuwih tepatna, Asm.js) tina kode mesin. QEMU dipilih pikeun percobaan, sarta sababaraha waktu engké artikel ieu ditulis dina Habr. Dina koméntar kuring disarankan pikeun ngadamel deui proyék di WebAssembly, bahkan kaluar sorangan ampir réngsé Kuring kumaha bae teu hayang proyek ... Karya ieu jalan, tapi lambat pisan, sarta ayeuna, nembe dina artikel nu mucunghul. komentar dina topik "Jadi kumaha eta sadayana tungtungna?" Pikeun ngaréspon kana jawaban kuring anu lengkep, kuring nguping "Ieu sapertos tulisan." Muhun, upami anjeun tiasa, bakal aya artikel. Meureun batur bakal manggihan eta mangpaat. Ti dinya pamaca bakal diajar sababaraha fakta ngeunaan desain backends generasi kode QEMU, kitu ogé kumaha carana nulis Just-in-Time compiler pikeun aplikasi wéb.

pancén

Kusabab kuring parantos diajar kumaha "kumaha waé" port QEMU kana JavaScript, waktos ieu mutuskeun pikeun ngalakukeunana sacara bijaksana sareng henteu ngulang kasalahan anu lami.

Kasalahan nomer hiji: cabang tina pelepasan titik

Kasalahan munggaran kuring nyaéta pikeun ngarobih versi kuring tina versi hulu 2.4.1. Mangka kuring sigana mangrupakeun ide anu sae: upami aya pelepasan titik, maka sigana langkung stabil tibatan 2.4 saderhana, sareng langkung seueur cabangna. master. Sarta saprak kuring rencanana pikeun nambahkeun jumlah adil tina bug kuring sorangan, abdi teu kedah saha sejenna urang pisan. Éta meureun kumaha tétéla. Tapi di dieu Éta hal: QEMU teu nangtung kénéh, sarta di sawatara titik maranéhna malah ngumumkeun optimasi kode dihasilkeun ku persen 10. "Hehehehe, ayeuna Kaula bade freeze," Teu sangka sarta peupeus handap. Di dieu urang kudu nyieun digression a: alatan sipat single-threaded of QEMU.js jeung kanyataan yén QEMU aslina teu imply henteuna multi-threading (nyaéta, kamampuhan pikeun sakaligus beroperasi sababaraha jalur kode nu teu patali, jeung teu ngan "ngagunakeun sagala kernels") kritis pikeun eta, fungsi utama threads Kuring kungsi "ngahurungkeun kaluar" pikeun bisa nelepon ti luar. Ieu nyiptakeun sababaraha masalah alam nalika ngahiji. Sanajan kitu, kanyataan yén sababaraha parobahan ti cabang master, kalawan nu kuring diusahakeun ngagabungkeun kode kuring, ieu ogé céri ngangkat dina release titik (sahingga dina cabang kuring) ogé meureun moal geus ditambahkeun genah.

Sacara umum, kuring mutuskeun yén éta masih asup akal pikeun ngalungkeun prototipe, ngabongkar bagian-bagianna sareng ngawangun versi énggal ti mimiti dumasar kana anu langkung seger sareng ayeuna ti mimiti. master.

Kasalahan nomer dua: Métodologi TLP

Intina, ieu sanés kasalahan, sacara umum, éta ngan ukur fitur pikeun nyiptakeun proyék dina kaayaan salah paham lengkep boh "dimana sareng kumaha ngalih?" sareng sacara umum "naha urang bakal ka ditu?" Dina kaayaan ieu programming kagok éta pilihan diyakinkeun, tapi, sacara alami, kuring teu hayang ngulang deui unnecessarily. Kali ieu kuring hayang ngalakukeun eta bijaksana: commits atom, parobahan kode sadar (jeung teu "stringing karakter acak babarengan nepika compiles (kalawan warnings)", sakumaha Linus Torvalds sakali ngomong ngeunaan batur, nurutkeun Wikiquote), jsb.

Kasalahan nomer tilu: asup ka cai tanpa terang ford

Kuring masih teu acan lengkep ngaleungitkeun ieu, tapi ayeuna kuring parantos mutuskeun pikeun henteu nuturkeun jalan anu paling saeutik résistansi, sareng ngalakukeunana "sakumaha déwasa," nyaéta, nyerat backend TCG kuring ti mimiti, supados henteu mun kudu ngomong engké, "Leres, ieu tangtu, lalaunan, tapi kuring teu bisa ngadalikeun sagalana - éta kumaha TCI ditulis ..." Leuwih ti éta, ieu mimitina seemed kawas hiji solusi atra, saprak Kuring ngahasilkeun kode binér. Sakumaha aranjeunna nyarios, "Ghent ngumpulу, tapi teu nu hiji ": kode teh, tangtosna, binér, tapi kontrol teu bisa ngan saukur dialihkeun ka dinya - eta kudu eksplisit kadorong kana browser pikeun kompilasi, hasilna obyék tangtu ti dunya JS, nu masih perlu disimpen wae. Nanging, dina arsitéktur RISC normal, sajauh anu kuring ngartos, kaayaan anu khas nyaéta kabutuhan sacara eksplisit ngareset cache instruksi pikeun kode anu diregenerasi - upami ieu sanés anu urang peryogikeun, teras, dina sagala hal, éta caket. Salaku tambahan, tina usaha terakhir kuring, kuring diajar yén kontrol sigana henteu ditransfer ka tengah blok tarjamahan, janten urang henteu peryogi bytecode diinterpretasi tina offset mana waé, sareng urang ngan saukur tiasa ngahasilkeun tina fungsina dina TB. .

Aranjeunna sumping sareng najong

Sanajan kuring mimiti nulis balik kode deui dina bulan Juli, hiji tajongan magic crept up unnoticed: biasana hurup ti GitHub anjog salaku bewara ngeunaan réspon kana Isu jeung Narik requests, tapi di dieu, ngadadak sebutkeun dina thread Binaryen salaku backend qemu dina konteks, "Anjeunna ngalakukeun hal kawas éta, meureun anjeunna bakal nyebutkeun hiji hal." Urang ngobrol ngeunaan ngagunakeun perpustakaan patali Emscripten urang Binaryén pikeun nyieun WASM JIT. sumur, ceuk kuring nu boga Apache 2.0 lisénsi aya, sarta QEMU sakabéhna disebarkeun dina GPLv2, sarta aranjeunna henteu pisan cocog. Ujug-ujug tétéla yén lisénsi bisa ngalereskeun eta kumaha bae (Kuring henteu weruh: meureun ngarobahna, meureun dual lisénsi, meureun hal sejenna ...). Ieu, tangtosna, ngajantenkeun kuring bagja, sabab dina waktos éta kuring parantos ningali caket format binér WebAssembly, sareng kuring kumaha waé sedih sareng teu kaharti. Aya ogé perpustakaan anu bakal devour blok dasar kalayan grafik transisi, ngahasilkeun bytecode, komo ngajalankeun eta dina juru sorangan, lamun perlu.

Lajeng aya deui suratna dina milis QEMU, tapi ieu langkung seueur ngeunaan patarosan, "Saha waé anu peryogi?" Sareng éta ngadadak, tétéla éta perlu. Sahenteuna, anjeun tiasa ngahijikeun kamungkinan pamakean di handap ieu, upami tiasa dianggo langkung atanapi kirang gancang:

  • launching hal atikan tanpa instalasi nanaon pisan
  • virtualisasi dina ios, dimana, numutkeun rumor, hiji-hijina aplikasi anu ngagaduhan hak pikeun ngahasilkeun kode dina laleur nyaéta mesin JS (leres ieu?)
  • demonstrasi mini OS - single-floppy, diwangun-di, sagala jinis firmware, jsb ...

Fitur Runtime Browser

Sakumaha anu kuring parantos nyarios, QEMU dihijikeun kana multithreading, tapi browser henteu gaduh éta. Nya, éta, henteu ... Awalna éta henteu aya, teras muncul WebWorkers - sajauh anu kuring ngartos, ieu mangrupikeun multithreading dumasar kana pesen anu dikirimkeun. tanpa variabel dibagikeun. Alami, ieu nyiptakeun masalah signifikan nalika porting kode aya dumasar kana model memori dibagikeun. Teras, dina tekenan umum, éta ogé dilaksanakeun dina nami SharedArrayBuffers. Ieu laun diwanohkeun, aranjeunna sohor peluncuran na dina panyungsi béda, teras maranéhna sohor Taun Anyar, lajeng Meltdown ... Sanggeus éta maranéhna datang ka kacindekan yén kasar atawa kasar ukuran waktu, tapi kalayan bantuan memori dibagikeun jeung a thread incrementing counter, éta sadayana sami eta bakal dianggo kaluar geulis akurat. Jadi urang ditumpurkeun multithreading kalawan memori dibagikeun. Sigana yén aranjeunna engké dihurungkeun deui, tapi, sakumaha geus jelas ti percobaan munggaran, aya hirup tanpa eta, sarta lamun kitu, urang bakal coba ngalakukeun hal eta tanpa ngandelkeun multithreading.

Fitur kadua nyaéta impossibility manipulasi-tingkat low kalawan tumpukan: Anjeun teu bisa saukur nyandak, simpen konteks ayeuna sarta pindah ka nu anyar kalawan tumpukan anyar. Tumpukan panggero diurus ku mesin virtual JS. Ieu bakal sigana, naon masalahna, saprak urang masih mutuskeun pikeun ngatur urut ngalir lengkep sacara manual? Kanyataan yén blok I / O di QEMU dilaksanakeun ngaliwatan coroutines, sareng ieu dimana manipulasi tumpukan tingkat rendah bakal mangpaat. Untungna, Emscipten geus ngandung mékanisme pikeun operasi Asynchronous, sanajan dua: Asyncify и Emterpreter. Anu pangheulana jalan ngaliwatan bloat signifikan dina kode JavaScript dihasilkeun sarta henteu deui didukung. Anu kadua nyaéta "jalan anu leres" ayeuna sareng dianggo ngaliwatan generasi bytecode pikeun juru asli. Gawéna, tangtosna, lalaunan, tapi teu bloat kode. Leres, dukungan pikeun coroutines pikeun mékanisme ieu kedah disumbangkeun sacara mandiri (geus aya coroutines anu ditulis pikeun Asyncify sareng aya palaksanaan kira-kira API anu sami pikeun Emterpreter, anjeun ngan ukur kedah nyambungkeunana).

Di momen, kuring teu acan junun dibeulah kode kana hiji disusun dina WASM sarta diinterpretasi maké Emterpreter, jadi alat block teu dianggo acan (tingali dina séri salajengna, sabab nyebutkeun ...). Nyaéta, dina tungtungna anjeun kedah nampi hal-hal sapertos lapisan lucu ieu:

  • diinterpretasi blok I / O. Nya, naha anjeun leres-leres ngarepkeun NVMe anu ditiru sareng kinerja asli? 🙂
  • Kodeu QEMU utama anu disusun sacara statis (panerjemah, alat anu ditiru, jsb.)
  • dinamis disusun kodeu tamu kana WASM

Fitur tina sumber QEMU

Anjeun meureun geus ditebak, kode pikeun emulating arsitéktur tamu jeung kode pikeun generating parentah mesin host dipisahkeun dina QEMU. Kanyataanna, éta malah rada trickier:

  • aya arsitéktur tamu
  • nyaeta akselerator, nyaéta, KVM pikeun virtualization hardware dina Linux Ubuntu (pikeun tamu jeung host sistem cocog saling), TCG pikeun JIT kode generasi mana. Dimimitian ku QEMU 2.9, dukungan pikeun standar virtualisasi hardware HAXM dina Windows muncul (sacara rinci)
  • upami TCG dianggo sareng sanés virtualisasi hardware, maka éta gaduh dukungan generasi kode anu misah pikeun unggal arsitéktur host, ogé pikeun juru universal.
  • ... jeung sabudeureun sadayana ieu - emulated périferal, panganteur pamaké, migrasi, catetan-replay, jsb.

Ku jalan kitu, anjeun terang: QEMU bisa emulate teu ukur sakabéh komputer, tapi ogé prosésor pikeun prosés pamaké misah dina kernel host, nu dipaké, contona, ku fuzzer AFL pikeun instrumentation binér. Sugan aya anu hoyong port mode operasi QEMU ieu ka JS? 😉

Sapertos seueur parangkat lunak gratis anu lami, QEMU diwangun ngalangkungan telepon configure и make. Hayu urang mutuskeun pikeun nambahkeun hiji hal: backend TCG, palaksanaan thread, hal sejenna. Entong buru-buru gumbira / pikasieuneun (gariskeun garis anu pas) dina prospek komunikasi sareng Autoconf - kanyataanna, configure QEMU urang tétéla ditulis sorangan sarta teu dihasilkeun tina nanaon.

WebAss Assembly

Janten naon anu disebut WebAssembly (aka WASM)? Ieu mangrupikeun gaganti pikeun Asm.js, henteu deui pura-pura janten kode JavaScript anu sah. Sabalikna, éta murni binér sareng dioptimalkeun, bahkan ngan saukur nyerat integer kana éta henteu saderhana pisan: pikeun kompak, éta disimpen dina format. LEB128.

Anjeun panginten parantos nguping ngeunaan algoritma relooping pikeun Asm.js - ieu mangrupikeun pamulihan paréntah kontrol aliran "tingkat tinggi" (nyaéta, upami-lajeng-lain, puteran, jsb.), anu mesin JS dirancang, ti tingkat low LLVM IR, ngadeukeutan ka kode mesin dieksekusi ku processor. Alami, perwakilan panengah QEMU langkung caket kana anu kadua. Ieu bakal sigana nu di dieu éta, bytecode, tungtung siksaan ... Lajeng aya blok, lamun-lajeng-lain na loop!..

Sareng ieu mangrupikeun alesan sanés naha Binaryen mangpaat: sacara alami tiasa nampi blok tingkat luhur anu caket sareng anu bakal disimpen di WASM. Tapi ogé tiasa ngahasilkeun kode tina grafik blok dasar sareng transisi antara aranjeunna. Nya, kuring parantos nyarios yén éta nyumput format panyimpenan WebAssembly di tukangeun C / C ++ API anu merenah.

TCG (Tiny Code Generator)

GTC asalna backend pikeun kompiler C. Lajeng, katingalina, teu bisa tahan kompetisi kalawan GCC, tapi tungtungna kapanggih tempatna di QEMU salaku mékanisme generasi kode pikeun platform host. Aya ogé backend TCG nu dibangkitkeun sababaraha bytecode abstrak, nu langsung dieksekusi ku juru, tapi kuring mutuskeun pikeun nyingkahan pamakéan waktos ieu. Sanajan kitu, kanyataan yén dina QEMU geus mungkin pikeun ngaktipkeun transisi ka TB dihasilkeun ngaliwatan fungsi tcg_qemu_tb_exec, tétéla mangpaat pisan pikeun kuring.

Pikeun nambahkeun backend TCG anyar pikeun QEMU, anjeun kudu nyieun subdirectory a tcg/<имя архитектуры> (dina hal ieu, tcg/binaryen), sareng ngandung dua file: tcg-target.h и tcg-target.inc.c и resep éta sadayana ngeunaan configure. Anjeun tiasa nempatkeun file anu sanés di dinya, tapi, sakumaha anu anjeun tiasa nebak tina nami dua ieu, aranjeunna bakal duanana kalebet dimana waé: hiji salaku file header biasa (kaasup kana tcg/tcg.h, sareng anu hiji parantos aya dina file sanés dina diréktori tcg, accel teu ngan), nu séjén - ngan salaku snippet kode dina tcg/tcg.c, tapi boga aksés ka fungsi statik na.

Mutuskeun yén kuring bakal méakkeun teuing waktos on investigations detil rupa kumaha gawéna, Kuring saukur nyalin "skeletons" dua file ieu ti palaksanaan backend sejen, jujur ​​nunjukkeun ieu dina lulugu lisénsi.

file tcg-target.h ngandung utamana setelan dina formulir #define-s:

  • Sabaraha registers sareng lebar naon anu aya dina arsitéktur udagan (urang gaduh saloba anu dipikahoyong, saloba anu dipikahoyong - patarosan langkung seueur ngeunaan naon anu bakal dibangkitkeun kana kode anu langkung efisien ku browser dina arsitéktur "target lengkep" ...)
  • alignment parentah host: on x86, komo di TCI, parentah teu Blok pisan, tapi Kaula bade nempatkeun dina panyangga kode teu parentah pisan, tapi pointers kana struktur perpustakaan Binaryen, jadi kuring gé ngomong: 4 bait
  • naon parentah pilihan backend bisa ngahasilkeun - urang kaasup sagalana urang manggihan di Binaryen, hayu akselerator megatkeun sésana jadi leuwih basajan sorangan
  • Naon ukuran perkiraan tina cache TLB dipénta ku backend nu. Kanyataanna nyaéta dina QEMU sadayana serius: sanaos aya fungsi pembantu anu ngalaksanakeun beban / toko kalayan nganggap tamu MMU (dimana urang tanpa ayeuna?), aranjeunna nyimpen cache tarjamahan dina bentuk struktur, pamrosésan anu merenah pikeun diselapkeun langsung kana blok siaran. Patarosan na, naon offset dina struktur ieu paling éfisién diolah ku runtuyan leutik tur gancang paréntah?
  • Di dieu anjeun tiasa ngarobih tujuan hiji atanapi dua pendaptaran anu dicadangkeun, aktipkeun nelepon TB ngaliwatan hiji fungsi sareng sacara opsional ngajelaskeun sababaraha hal leutik. inline-fungsi kawas flush_icache_range (tapi ieu sanés kasus urang)

file tcg-target.inc.c, tangtosna, biasana ukuranana langkung ageung sareng ngandung sababaraha fungsi wajib:

  • initialization, kaasup larangan dina parentah nu bisa beroperasi dina operan mana. Blatantly disalin ku kuring ti backend sejen
  • fungsi nu nyokot hiji instruksi bytecode internal
  • Anjeun oge bisa nempatkeun fungsi bantu dieu, jeung anjeun ogé tiasa make fungsi statik ti tcg/tcg.c

Pikeun kuring sorangan, kuring milih strategi ieu: dina kecap mimiti blok tarjamahan salajengna, kuring nyerat opat petunjuk: tanda awal (nilai anu tangtu di sakurilingna. 0xFFFFFFFF, nu nangtukeun kaayaan kiwari TB nu), konteks, dihasilkeun modul, jeung nomer magic pikeun debugging. Awalna tanda ieu disimpen dina 0xFFFFFFFF - ndimana n - sajumlah leutik positif, sarta unggal waktos eta ieu dieksekusi ngaliwatan juru eta ngaronjat ku 1. Nalika eta ngahontal 0xFFFFFFFE, kompilasi lumangsung, modul ieu disimpen dina tabel fungsi, diimpor kana "launcher" leutik, dimana palaksanaan indit ti tcg_qemu_tb_exec, sarta modul ieu dikaluarkeun tina memori QEMU.

Pikeun paraphrase klasik, "Crutch, sabaraha intertwined dina sora ieu pikeun jantung proger urang ...". Sanajan kitu, memori ieu bocor wae. Leuwih ti éta, éta memori dikelola ku QEMU! Kuring kungsi kode nu, nalika nulis parentah salajengna (sumur, nyaeta, pointer a), ngahapus hiji link anu aya di tempat ieu saméméhna, tapi ieu teu mantuan. Sabenerna, dina kasus pangbasajanna, QEMU allocates memori dina ngamimitian jeung nulis kode dihasilkeun aya. Nalika panyangga béak, kodeu dialungkeun sareng anu salajengna mimiti ditulis dina tempatna.

Sanggeus diajar kode, Kuring sadar yén trik jeung angka magic diwenangkeun kuring teu gagal dina karuksakan numpuk ku freeing lepat dina panyangga uninitialized dina pass munggaran. Tapi anu rewrites panyangga pikeun bypass fungsi kuring engké? Salaku pamekar Emscripten mamatahan, nalika kuring lumpat kana masalah, Kuring porting kode anu dihasilkeun deui ka aplikasi asli, Nyetél Mozilla Rékam-Replay dinya ... Sacara umum, dina tungtungna kuring sadar hiji hal basajan: pikeun tiap blok, a struct TranslationBlock kalawan pedaranana. Tebak dimana... Leres, sateuacan blok katuhu dina panyangga. Nyadar ieu, kuring mutuskeun pikeun kaluar ngagunakeun crutches (sahenteuna sababaraha), sarta saukur threw kaluar angka magic, sarta mindahkeun kecap sésana ka struct TranslationBlock, nyieun daptar numbu tunggal nu bisa gancang traversed lamun cache tarjamahan reset, sarta ngosongkeun memori.

Sababaraha crutches tetep: contona, ditandaan pointers dina panyangga kode - sababaraha di antarana ngan saukur BinaryenExpressionRef, nyaeta, aranjeunna kasampak di ungkapan anu kudu linear nempatkeun kana blok dasar dihasilkeun, bagian mangrupa kaayaan transisi antara BBs, bagian nyaeta dimana buka. Nya, tos aya blok anu disiapkeun pikeun Relooper anu kedah dihubungkeun dumasar kana kaayaan. Pikeun ngabedakeun aranjeunna, anggapan dipaké yén maranéhanana kabéh Blok ku sahanteuna opat bait, sangkan anjeun aman tiasa nganggo sahenteuna signifikan dua bit pikeun labél nu, anjeun ngan kudu apal kana nyoplokkeun deui lamun perlu. Ku jalan kitu, labél sapertos kitu parantos dianggo dina QEMU pikeun nunjukkeun alesan kaluar tina loop TCG.

Ngagunakeun Binaryen

Modul dina WebAssembly ngandung fungsi, anu masing-masing ngandung awak, anu mangrupikeun ekspresi. Ekspresi nyaéta operasi unary sareng binér, blok anu diwangun ku daptar ekspresi sanés, aliran kontrol, jsb. Sakumaha anu kuring parantos nyarios, aliran kontrol di dieu diatur persis salaku cabang tingkat luhur, puteran, sauran fungsi, jsb. Argumen pikeun fungsi henteu diliwatan dina tumpukan, tapi sacara eksplisit, sapertos dina JS. Aya ogé variabel global, tapi kuring henteu acan dianggo, janten kuring moal nyarioskeun ka anjeun ngeunaan éta.

Fungsi ogé mibanda variabel lokal, wilanganana ti enol, tina tipe: int32 / int64 / float / ganda. Dina hal ieu, n variabel lokal munggaran nyaéta argumen anu disalurkeun kana fungsi éta. Perhatikeun yén sanajan sagalana di dieu teu sagemblengna low-tingkat dina watesan aliran kontrol, integers masih teu mawa atribut "ditandatanganan / unsigned": kumaha jumlah behaves gumantung kana kode operasi.

Umumna disebutkeun, Binaryen nyadiakeun basajan C-API: anjeun nyieun modul, di anjeunna jieun ekspresi - unary, binér, blok tina éksprési séjén, aliran kontrol, jsb. Satuluyna anjeun nyieun fungsi kalawan ekspresi salaku awakna. Upami anjeun, sapertos kuring, gaduh grafik transisi tingkat rendah, komponén relooper bakal ngabantosan anjeun. Sajauh kuring ngartos, kasebut nyaéta dimungkinkeun pikeun ngagunakeun kontrol tingkat tinggi tina aliran palaksanaan di blok a, salami teu balik saluareun wates blok - nyaeta, kasebut nyaéta dimungkinkeun pikeun nyieun jalur gancang internal / slow. jalur branching jero diwangun-di TLB kode processing cache, tapi teu ngaganggu aliran kontrol "éksternal". Nalika anjeun ngosongkeun relooper, blokna dibébaskeun; nalika anjeun ngosongkeun modul, éksprési, fungsi, jsb anu dialokasikeun pikeun éta ngaleungit. arena.

Sanajan kitu, lamun rék napsirkeun kode on laleur tanpa kreasi perlu tur ngahapus hiji conto juru, eta bisa make akal pikiran pikeun nempatkeun logika ieu kana file C ++, sarta ti dinya langsung ngatur sakabéh C ++ API perpustakaan, bypassing siap- dijieun wrappers.

Janten pikeun ngahasilkeun kode anu anjeun peryogikeun

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

... lamun kuring poho nanaon, punten, ieu ngan keur ngagambarkeun skala, sarta detil aya dina dokuméntasi.

Sareng ayeuna crack-fex-pex dimimitian, sapertos kieu:

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

Pikeun kumaha waé nyambungkeun dunya QEMU sareng JS sareng dina waktos anu sami ngaksés fungsi anu dikompilasi gancang, hiji Asép Sunandar Sunarya dijieun (tabél fungsi pikeun impor kana launcher), sarta fungsi dihasilkeun disimpen di dinya. Pikeun gancang ngitung indéks, indéks tina blok tarjamahan kecap enol mimitina dipaké salaku éta, tapi lajeng indéks diitung ngagunakeun rumus ieu mimiti saukur pas kana widang di struct TranslationBlock.

Ku jalan kitu, démo (ayeuna ku lisénsi murky) ngan jalanna saé dina Firefox. pamekar Chrome éta kumaha bae teu siap kanyataan yén batur bakal hoyong nyiptakeun langkung ti sarébu conto modul WebAssembly, ku kituna aranjeunna ngan ukur nyayogikeun gigabyte rohangan alamat maya pikeun tiap ...

Sakitu wae kanggo ayeuna. Sugan aya tulisan deui upami aya anu minat. Nyaéta, aya tetep sahenteuna hungkul sangkan alat block jalan. Éta ogé tiasa janten akal pikeun ngajantenkeun kompilasi modul WebAssembly asynchronous, sapertos biasa di dunya JS, sabab masih aya juru anu tiasa ngalakukeun ieu dugi ka modul asli parantos siap.

Tungtungna teka-teki: Anjeun geus disusun binér dina arsitéktur 32-bit, tapi kode, ngaliwatan operasi memori, nanjak ti Binaryen, tempat dina tumpukan, atawa tempat sejenna di luhur 2 GB tina spasi alamat 32-bit. Masalahna nyaéta tina sudut pandang Binaryen ieu ngaksés alamat anu ageung teuing. Kumaha carana meunang sabudeureun ieu?

Dina cara admin

Kuring henteu mungkas nguji ieu, tapi pamikiran mimiti kuring nyaéta "Kumaha upami kuring dipasang Linux 32-bit?" Teras bagean luhur rohangan alamat bakal dijajah ku kernel. Hiji-hijina patarosan nyaéta sabaraha anu bakal dijajah: 1 atanapi 2 Gb.

Dina cara programmer (pilihan pikeun praktisi)

Hayu urang niup gelembung di luhureun spasi alamat. Kuring sorangan teu ngarti naha gawéna - aya enggeus kudu aya tumpukan. Tapi "kami praktisi: sagalana lumaku pikeun kami, tapi teu saurang ogé weruh naha ..."

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

... leres yén éta henteu cocog sareng Valgrind, tapi, untungna, Valgrind sorangan sacara efektif ngadorong sadayana kaluar ti dinya :)

Panginten aya anu bakal masihan katerangan anu langkung saé ngeunaan kumaha kodeu ieu jalanna ...

sumber: www.habr.com

Tambahkeun komentar