2 puan yazan GN⁺ 2025-02-05 | 1 yorum | WhatsApp'ta paylaş
  • Bir geliştirici, C tabanlı WebAssembly VM Semblance'ı 6 ay boyunca akşamlarını ve hafta sonlarını ayırarak geliştirdi; kısa sürede biten bir yan proje yerine, spesifikasyonu derinlemesine inceleyen uzun soluklu bir öğrenme projesi olarak ilerletti
  • WebAssembly, tarayıcıda güvenilmeyen kodu native'e yakın hızda çalıştırmak için standart bir bytecode'dur ve Fastly, Shopify ve Zed gibi örneklerle tarayıcı dışı kullanım da artmaktadır
  • Semblance'ın amacı WebAssembly Core Specification'ı öğrenmek ve Wasmtime gibi endüstriyel runtime'lara katkı verebilecek seviyede hazırlanmak olduğundan, tüm opcode'ları uygulamak veya core test suite'ten geçmek kapsam dışında bırakıldı
  • Yorumlayıcı, .wasm dosyasındaki magic bytes ve sürüm 1'i doğruladıktan sonra section decoding, import çözümleme, modül instance'lama, export fonksiyonu bulma, stack ve activation frame başlatma, opcode switch loop çalıştırma sırasıyla ilerler
  • Tam teşekküllü bir runtime olmadığı için yavaş, bellek sızıntıları içeriyor ve kötü amaçlı modüllere karşı zafiyet taşıyabiliyor; ancak Hello, World! çalıştırarak spesifikasyonu öğrenme hedefini gerçekleştirmiş durumda

Neden WebAssembly seçildi

  • WebAssembly, sanal stack machine için standart bir komut kümesi ve bytecode formatıdır
  • Başlangıç noktası Emscripten'in C/C++ to JavaScript derleyicisiydi
    • Emscripten, LLVM IR'i JavaScript'e dönüştürerek C ve C++ kodunun web'de çalışmasını sağladı
    • Tarayıcı geliştiricileri ve Emscripten projesi, performans optimizasyonu için üretilen kodu basit bir JavaScript alt kümesiyle sınırladı ve bu alt küme asm.js olarak standartlaştı
    • Daha sonra JavaScript parse overhead'inden kaçınmak için bağımsız bir bytecode formatı olan Wasm tasarlandı
  • Son dönemde WebAssembly'nin tarayıcı dışı kullanımı da artıyor
    • Fastly'nin Edge Compute'u ve Shopify'ın Functions yapısı WebAssembly motorları üzerine kurulu
    • Zed'in uzantı sistemi de Wasm tabanlı
  • Bytecode Alliance, WebAssembly'nin tarayıcı dışında kullanılmasını destekleyen endüstri çapındaki çabaları yönlendiriyor; Wasmtime runtime'ı ve WASI standardizasyonu üzerinde çalışıyor
    • WASI, WebAssembly modüllerinin POSIX benzeri host call'lar aracılığıyla host işletim sistemiyle iletişim kurmasını sağlar
    • Standart girdi/çıktı, dosya sistemi, ağ gibi dış arayüzlerle etkileşim için standart bir yol sunar

Yan projeden öğrenme projesine

  • Tekrarlayan bir biçimde yeni yan projeler başlatıp birkaç hafta sonra ilgisini kaybederek başka projelere geçme alışkanlığı vardı
  • Daha uzun süre odaklanabileceği ve günlük işine kıyasla hesaplama yığınının daha alt seviyelerini ele alan büyük bir projeye ihtiyaç duyuyordu
  • Yön eksikliği yüzünden yarım bırakılmış çok sayıda yan proje olduğu için, net hedefleri ve görünür çıktıları olan bir proje arıyordu
  • Generalist mühendislik profilinin istikrarlı iş bulmasını etkilediğini düşündükten sonra, T-şekilli beceri seti oluşturabileceği bir uzmanlık alanı aramaya başladı
  • WebAssembly'de özel system call'larla özelleştirilmiş bir hesaplama ortamı tasarlanabilmesi, onu platform mühendisliği aracı olarak cazip kıldı

Semblance'ın hedefi ve kapsamı

  • Projenin adı Semblance ve C ile yazılmış bir WebAssembly yorumlayıcısı
  • Ana hedef, WebAssembly Core Specification'a aşina olmaktı
  • Uzun vadede Wasmtime gibi endüstriyel runtime'lara katkı verebilecek düzeyde WebAssembly bilgisi edinmek de amaçlandı
  • Bu bir öğrenme projesi olduğu için tüm opcode'ları uygulamak veya core test suite'ten geçmek hedeflenmedi
  • Başarı ölçütü olarak “Hello, World!” çalıştırabilmek yeterli görüldü
  • Profesyonel C geliştirme deneyimi olmadığını ve C kodunun kalitesinin ideal olmadığını kabul ediyor; code review memnuniyetle karşılanıyor

Hello, World! çalıştırma akışı

  • Örnek C kodu, harici puts fonksiyonunu bildiriyor ve hello() içinde "Hello, World!\n" çıktısını veriyor
  • Clang ile WebAssembly üretiliyor
    • --target=wasm32
    • -nostdlib
    • -Wl,--no-entry
    • -Wl,--export-all
    • -Wl,--allow-undefined
    • -O3
  • Oluşturulan hello.wasm, semblance hello.wasm --invoke hello komutuyla çalıştırılıyor
  • Program başlatıldığında stack üzerinde komut satırı argümanları, decode edilmiş WebAssembly modülü ve runtime durumunu tutan store için bellek başlatılıyor
  • Komut satırı argümanları parse ediliyor ve hatalıysa program sonlandırılıyor

Binary decoding ve modül yapısı

  • Yorumlayıcı önce WebAssembly binary format'ını decode ediyor
  • Dosyanın başındaki "\0asm" magic bytes doğrulanıyor
  • Binary format sürümünün 1 olup olmadığı kontrol ediliyor
  • Ardından içerdiği sections decode ediliyor
  • Decode tamamlandığında WasmModule yapısı hello.wasm içindeki fonksiyonlar, tipler, import'lar, data ve diğer alanlarla dolduruluyor
    • types
    • funcs
    • tables
    • mems
    • globals
    • elems
    • datas
    • start
    • imports
    • exports
    • customs
    • meta

Import çözümleme ve env::puts

  • Semblance'ın şu anda sağladığı tek host fonksiyonu env::puts
  • Host fonksiyonu import'u, store içinde native function pointer ayırıp oluşan funcaddr değerini modülün imports dizisine yerleştirerek işleniyor
  • hostcall_puts, argüman olarak aldığı i32 offset'i kullanıyor
    • Store'un ilk memory instance'ından data pointer alıyor
    • Offset konumundaki string'i printf("%s", ...) ile standart çıktıya yazdırıyor
  • Import listesi dolaşılırken module name "env" ve item name "puts" olan kayıt bulunursa, host fonksiyonu register_hostcall_puts ile kaydediliyor

Instance'lama ve opcode yürütme

  • Import çözümlemesinden sonra modül instance ediliyor
  • Instance'lama bir doğrulama aşaması içeriyor
    • Tip kontrolü ve modülün doğru biçimde olup olmadığını sınayan testler yapılıyor
    • Memory, global ve table başlatılıyor
    • start fonksiyonu varsa çağrılıyor
  • Instance'lama sonucu WasmModuleInst; bu yapı yürütme zamanı durumunu ve kullanıma hazır export'ları içeriyor
  • --invoke komut satırı argümanında verilen ada göre export fonksiyonu bulunuyor
    • Export'lar dolaşılarak adı eşleşen WasmExportInst döndürülüyor
    • Dönen export'un bir function olup olmadığı doğrulanıyor
  • Fonksiyon çağrısı için stack ve activation frame başlatılması gerekiyor
  • Çalıştırmanın çekirdeği opcode switch loop
    • Fonksiyon gövdesindeki Wasm instructions sırayla okunuyor
    • Opcode'a göre stack ve store üzerinde işlemler uygulanıyor
    • Örnek olarak i32.const, i64.const, f32.const, f64.const, i32.ge_s, call, nop, unreachable, end işleniyor
    • Ele alınmayan opcode'lar için "unhandled opcode [...]" yazdırılıyor ve trap döndürülüyor

call komutu ve host fonksiyonu çağrısı

  • WasmOpCall işleyicisi, call opcode'unun immediate değeri olan funcidx ile store içinden function instance'ı buluyor
  • Function type bilgisine göre gerekli argümanlar stack'ten pop ediliyor
  • Function instance türü kontrol edilerek bunun bir Wasm fonksiyonu mu yoksa native host function mı olduğu ayırt ediliyor
  • Host fonksiyonuysa, saklanan hostfunc function pointer'ı native call olarak çalıştırılıyor
  • Dönüş değeri varsa yeniden stack'e push ediliyor
  • hello fonksiyonunun end opcode'una ulaşıldığında opcode switch loop sona eriyor ve kontrol main'e dönüyor

Sonuç ve kalan sınırlamalar

  • Çalıştırma sonucu standart çıktıda şu şekilde görünüyor
    • Hello, World!
    • Ok []
  • Proje basit bir “Hello, World!” programını çalıştırabiliyor
  • Opcode kapsamı tam değil
  • Kod dağınık, yavaş ve bellek sızıntıları içeriyor
  • Kötü amaçlı modüllere karşı savunmasız olabilir
  • Buna rağmen WebAssembly Core Specification hakkında çok şey öğrenildi ve bir mühendis olarak alışılmış alanın dışına çıkmaya yardımcı oldu
  • Kendi yorumlayıcısını yazdıktan sonra, Wasmtime gibi endüstriyel runtime'lara katkı verebilecek kadar WebAssembly bilgisi edindiğini düşünüyor
  • Bundan sonra birkaç opcode daha eklemeyi sürdürebilir, ancak bu projeyi ana proje olarak devam ettirme aşamasını sonlandırmak istiyor

1 yorum

 
GN⁺ 2025-02-05
Hacker News yorumları
  • Daha önce Scheme ile bir Wasm yorumlayıcısı yapmıştım; bunu doğrudan uygulayan daha fazla kişi görmek sevindirici.
    Sandığınız kadar zor değil; spesifikasyona bir göz atıp denemenizi öneririm. Tüm komutları uygulamanız gerekmiyor, keyif alacak kadarını yapmak bile yeterli.

  • Aynı türden bir uygulayıcı olarak bir ipucu vereyim: spec-test içinde derleme yöntemi pek sezgisel olmayan tuhaf metinsel Wasm biçimleri çok, ama wast2json dönüştürücüsünü kullanırsanız normal ikili Wasm dosyalarıyla birlikte daha basit bir JSON açıklaması üretebilirsiniz.

    • Chicory’de de aynı yöntemi kullandık: https://github.com/dylibso/chicory
      Bu test paketini ne kadar hızlı çalıştırabilir hale getirirseniz, yineleme hızına ve doğruluğa o kadar yardımcı olur.
      Hepsini çalışır hale getirmek biraz zaman aldı, ama bir kez başardıktan sonra her şeyi çalıştırabilecek noktaya çok hızlı ulaştık; test paketi eksiksiz olmasa da yaklaşık %95’ini kapsıyor: https://github.com/WebAssembly/testsuite
    • Ben de bir derleyici yapıyorum; bu faydalı oldu.
      Bu testleri daha önce görmüştüm ama nasıl kullanacağımı bilmediğim için sinir bozucu ve kafa karıştırıcı gelmişti.
  • Doğrudan Wasm yorumlama ile ilgili olarak şu makale oldukça ilginçti: https://arxiv.org/abs/2205.01183
    Buna dayanarak https://github.com/peterseymour/winter projesini yaptım ve Wasm’ın düşündüğüm kadar basit olmadığını öğrendim.

  • Acemi sorusu: Doğrudan hedef olarak kod yazmadığınız bir durumda yorumlayıcı hata ayıklaması nasıl yapılıyor, merak ediyorum.
    İşlem kodu dizgilerini fuzzing’den geçirmek ne kadar işe yarıyor, ayrıca sunucu tarafı Wasm motorları ile tarayıcı tabanlı motorlar arasında pratikte ne kadar büyük fark var ve birini diğerine dönüştürmek ne kadar iş gerektirir, bunları da merak ediyorum.

  • İlginç bir yaklaşım ve harika bir çalışma.
    Özünü görmek isteyenler için çoğu şu dosyada: https://github.com/irrio/semblance/blob/main/src/wrun.c
    Düşününce, projenin standart arayüzü olarak Wasm-C-API’yi (https://github.com/WebAssembly/wasm-c-api) izlemesi iyi olurdu gibi geliyor.
    Zaten bir C API’si ve Wasmer, V8, wasmi gibi çoğu Wasm çalışma zamanı tarafından benimsenmiş durumda; bu yüzden o API’ye aşina geliştiriciler daha kolay deneyebilir.
    Yazar Wasm’a yeterince aşinaysa ve Wasmer’a katkıda bulunmak isterse yamalar veya iyileştirmeler de memnuniyetle karşılanır.

    • Yazar kesinlikle Wasm’a yeterince aşina görünüyor ve muhtemelen WebAssembly ticari marka hakkını denemiş şirketten uzak duracak kadar da biliyordur.
      “VC yatırımı almış Wasmer’ın kâr amacı gütmeyen kuruluşun adı olan WebAssembly’yi ticari marka olarak tescil ettirmeye çalışmasına yönelik anlaşılır endişe” denmişti; bu da hatayı kabul etmek demek.
    • Wasmer’ın Installed-Size: 266 MB olması da neyin nesi?
    • Bildiğim kadarıyla Wasmer’ın Wasm-C-API’yi benimsediğini söylemek pek doğru değil.
      https://github.com/wasmerio/wasmer/issues/2615 ihmal edildi ve sonra otomatik olarak kapatıldı.
  • Biraz daha tartışmalı bir soru: geçici tail call komutları eklemeyi düşünüyor musunuz, merak ediyorum.
    Wasm spesifikasyonu tarafında bunun fazla “yüksek seviyeli” olduğu gerekçesiyle reddedilmişti, ama C komitesi de bir zamanlar Dennis Ritchie’nin önerisini reddetmişti.
    Yine de ben paramı hâlâ Ritchie’den yana koyardım; Rob Pike da sanırım o yönde bahse girmişti.
    Öyle olmasaydı Golang’i neden yapsın ki? Çağrı yalnızca yüksek seviyeli olduğunda tail call da yüksek seviyelidir.

  • Orca’ya bir bakmanız iyi olabilir. Oraya iyi katkı verebilecek gibi görünüyorsunuz.
    [0] https://orca-app.dev

  • Ben de yeni ve parlak şeyler arasında dolaşmak yerine tek bir projeye odaklanmaya karar verdim; istisna olarak yapay zeka yardımcılarına angarya işleri yaptırıyorum.
    En hafif ifadeyle, epey sinir bozucu.
    Ayrıca C ile çağrı yaparken birden çok argümanı vb. işlemek için libffi gibi bir kütüphane kullanmayı da önerecektim.

  • WebAssembly zed gibi yerlerde eklenti API’si olarak kullanıldığında, eklenti geliştiricilerinin kodu nasıl hata ayıkladığını merak ediyorum.
    Örneğin breakpoint ile hata ayıklama mümkün mü, kod çökerse stack trace alınabiliyor mu, bunları merak ediyorum.