QEMU.js፡ አሁን በቁም ነገር እና በWASM

አንድ ጊዜ ለመዝናናት ወሰንኩ የሂደቱን ተለዋዋጭነት ያረጋግጡ እና ጃቫ ስክሪፕትን (በይበልጥ በትክክል፣ Asm.js) ከማሽን ኮድ እንዴት ማመንጨት እንደሚችሉ ይወቁ። QEMU ለሙከራ የተመረጠ ሲሆን ከተወሰነ ጊዜ በኋላ በሀብር ላይ አንድ ጽሑፍ ተፃፈ። በአስተያየቶቹ ውስጥ ፕሮጀክቱን በ WebAssembly ውስጥ እንደገና እንድሠራ እና ሌላው ቀርቶ እራሴን እንድተው እመክራለሁ ሊጠናቀቅ ተቃርቧል በሆነ መንገድ ፕሮጀክቱን አልፈልግም ነበር ... ስራው እየቀጠለ ነበር, ግን በጣም በዝግታ, እና አሁን, በቅርብ ጊዜ በዚያ ጽሑፍ ውስጥ ታየ. አስተያየት በርዕሱ ላይ "ታዲያ ይህ ሁሉ እንዴት ተጠናቀቀ?" ለዝርዝር ምላሼ፣ “ይህ እንደ ጽሑፍ ይመስላል” ሰማሁ። ደህና, ከቻሉ, አንድ ጽሑፍ ይኖራል. ምናልባት አንድ ሰው ጠቃሚ ሆኖ ያገኘው ይሆናል. ከእሱ አንባቢው ስለ QEMU ኮድ ማመንጨት ጀርባዎች ዲዛይን አንዳንድ እውነታዎችን ይማራል ፣ እንዲሁም ለድር መተግበሪያ የ Just-in-time compiler እንዴት እንደሚፃፍ።

ተግባራት

QEMU ን ወደ ጃቫ ስክሪፕት እንዴት “በሆነ መንገድ” ወደብ እንደምችል አስቀድሜ ስለተማርኩ በዚህ ጊዜ በጥበብ ለመስራት እና የቆዩ ስህተቶችን ላለመድገም ተወሰነ።

ስህተት ቁጥር አንድ፡ ከነጥብ ልቀት ቅርንጫፍ

የመጀመሪያ ስህተቴ የእኔን ስሪት ከላይኛው ስሪት 2.4.1 ሹካ ነበር። ከዚያ ጥሩ ሀሳብ ሆኖ ታየኝ-ነጥብ መለቀቅ ካለ ፣ ምናልባት ከቀላል 2.4 የበለጠ የተረጋጋ ነው ፣ እና የበለጠ ቅርንጫፉም እንዲሁ። master. እና ትክክለኛ መጠን ያላቸውን የራሴን ስህተቶች ለመጨመር እቅድ ስለነበረኝ፣ ምንም ሌላ የማንንም ሰው አያስፈልገኝም። እንደዛ ሳይሆን አይቀርም። ነገር ግን ነገሩ እዚህ አለ፡ QEMU ዝም ብሎ አይቆምም እና በአንድ ወቅት የተፈጠረውን ኮድ በ10 በመቶ ማሻሻልን አስታወቁ።"አዎ፣ አሁን ልቀዘቅዝ ነው" ብዬ አሰብኩና ተበታተነኝ። እዚህ ዳይግሬሽን ማድረግ አለብን-በ QEMU.js ነጠላ-ክር ተፈጥሮ እና የመጀመሪያው QEMU ባለብዙ-ክር አለመኖርን አያመለክትም (ማለትም ፣ በተመሳሳይ ጊዜ በርካታ የማይዛመዱ የኮድ ዱካዎችን የመስራት ችሎታ ፣ እና "ሁሉንም ከርነሎች ተጠቀም" ብቻ ሳይሆን ለእሱ ወሳኝ ነው, የክር ዋና ተግባራት ከውጭ ለመደወል "ማጠፍ" ነበረብኝ. ይህም በውህደቱ ወቅት አንዳንድ የተፈጥሮ ችግሮችን ፈጠረ። ሆኖም ግን, ከቅርንጫፉ ውስጥ አንዳንድ ለውጦች የመሆኑ እውነታ masterየእኔን ኮድ ለማዋሃድ የሞከርኩበት ፣ እንዲሁም በነጥብ መልቀቂያው ውስጥ (እና በቅርንጫፌ ውስጥ) ቼሪ ተመርጠዋል እንዲሁም ምናልባት ምቾት አይጨምርም ነበር።

በአጠቃላይ፣ ፕሮቶታይፕን መጣል፣ ለክፍሎች መገንጠል እና አዲስ ስሪት ከባዶ መገንባት አሁንም ጠቃሚ እንደሆነ ወስኛለሁ እናም አሁን ባለው አዲስ ነገር ላይ በመመስረት። master.

ስህተት ቁጥር ሁለት: TLP ዘዴ

በመሠረቱ ይህ ስህተት አይደለም ፣ በአጠቃላይ ፣ “የት እና እንዴት መንቀሳቀስ?” እና በአጠቃላይ “እዚያ እንደርሳለን?” የሚለውን ሁለቱንም ሙሉ በሙሉ አለመግባባት በሚፈጠርበት ሁኔታ ፕሮጀክት የመፍጠር ባህሪ ብቻ ነው ። በእነዚህ ሁኔታዎች ውስጥ ብልሹ ፕሮግራም ትክክለኛ አማራጭ ነበር፣ ግን፣ በተፈጥሮ፣ ሳያስፈልግ መድገም አልፈልግም። በዚህ ጊዜ በጥበብ ልሠራው ፈለግሁ፡ አቶሚክ ድርጊቶች፣ ንቃተ ህሊናዊ ኮድ ለውጦች (እና “የዘፈቀደ ቁምፊዎችን እስኪያጠናቅቅ ድረስ (ከማስጠንቀቂያ ጋር)” ሳይሆን፣ ሊነስ ቶርቫልድስ በአንድ ወቅት ስለ አንድ ሰው እንደተናገረው፣ በዊኪ ጥቅስ መሰረት) ወዘተ.

ስህተት ቁጥር ሶስት: ፎርዱን ሳያውቅ ወደ ውሃ ውስጥ መግባት

አሁንም ይህንን ሙሉ በሙሉ አላስወገድኩም ፣ አሁን ግን በትንሹ የመቋቋም መንገድ ላለመከተል እና “እንደ ትልቅ ሰው” ለማድረግ ወስኛለሁ ፣ ማለትም ፣ የ TCG ጀርባዬን ከባዶ ይፃፉ ፣ ስለሆነም በኋላ እንዲህ ማለት አለብኝ: "አዎ, ይህ በእርግጥ, ቀስ በቀስ ነው, ነገር ግን ሁሉንም ነገር መቆጣጠር አልችልም - TCI የተጻፈው እንደዚህ ነው..." ከዚህም በላይ ይህ መጀመሪያ ላይ ግልጽ የሆነ መፍትሔ ይመስላል ሁለትዮሽ ኮድ አመነጫለሁ።. እነሱ እንደሚሉት፣ “ጌንት ተሰብስቧልу, ግን ያ አይደለም": ኮዱ በእርግጥ ሁለትዮሽ ነው, ነገር ግን ቁጥጥር በቀላሉ ወደ እሱ ሊተላለፍ አይችልም - ለማጠናቀር ወደ አሳሹ ውስጥ በግልፅ መጫን አለበት, ይህም ከ JS ዓለም የተወሰነ ነገርን ያመጣል, ይህም አሁንም ያስፈልገዋል. የሆነ ቦታ መዳን. ሆኖም ፣ በመደበኛ የ RISC አርክቴክቸር ፣ እኔ እስከገባኝ ድረስ ፣ አንድ የተለመደ ሁኔታ ለታደሰ ኮድ የመመሪያውን መሸጎጫ በግልፅ እንደገና ማስጀመር አስፈላጊ ነው - ይህ እኛ የምንፈልገው ካልሆነ ፣ ከዚያ በማንኛውም ሁኔታ ፣ ቅርብ ነው። በተጨማሪም፣ ካለፈው ሙከራዬ፣ መቆጣጠሪያው ወደ የትርጉም ማገጃው መሃል የሚተላለፍ እንደማይመስል ተረድቻለሁ፣ ስለዚህም ከየትኛውም ማካካሻ በቢትኮድ መተርጎም አያስፈልገንም እና በቀላሉ በቲቢ ላይ ካለው ተግባር ማመንጨት እንችላለን። .

መጥተው ረገጠ

በጁላይ ወር ላይ ኮዱን እንደገና መፃፍ የጀመርኩት ቢሆንም፣ አንድ ምትሃታዊ ምት ሳይታወቅ ፈልቅቋል፡ ብዙ ጊዜ ከ GitHub የሚላኩ ደብዳቤዎች ለጉዳዮች እና ስለ ጎትት ጥያቄዎች ምላሽ እንደ ማሳወቂያ ይደርሳሉ፣ ግን እዚህ፣ በድንገት በክር ውስጥ መጥቀስ Binaryen እንደ qemu backend በዐውደ-ጽሑፉ ውስጥ "እንዲህ ያለ ነገር አድርጓል, ምናልባት የሆነ ነገር ይናገር ይሆናል." እየተነጋገርን የነበረው የEmscripten ተዛማጅ ቤተ-መጽሐፍትን ስለመጠቀም ነበር። ቢናርየን WASM JIT ለመፍጠር። ደህና፣ እዚያ Apache 2.0 ፍቃድ እንዳለዎት ተናግሬአለሁ፣ እና QEMU በአጠቃላይ በ GPLv2 ስር ይሰራጫል፣ እና እነሱ በጣም ተኳሃኝ አይደሉም። በድንገት ፈቃድ ሊሆን እንደሚችል ታወቀ በሆነ መንገድ አስተካክለው (አላውቅም፡ ምናልባት ይቀይሩት፡ ምናልባት ድርብ ፍቃድ፡ ምናልባት ሌላ ነገር...)። ይህ በእርግጥ ደስተኛ አድርጎኛል, ምክንያቱም በዚያን ጊዜ አስቀድሜ በቅርበት ተመልክቼ ነበር ሁለትዮሽ ቅርጸት WebAssembly፣ እና በሆነ መንገድ አዝኛለሁ እና ለመረዳት የማልችል ነበር። መሰረታዊ ብሎኮችን ከሽግግር ግራፍ ጋር የሚበላ፣ ባይትኮድ የሚያዘጋጅ እና አስፈላጊ ከሆነም በራሱ በአስተርጓሚ ውስጥ የሚያስኬድ ቤተ መፃህፍትም ነበር።

ከዚያም ተጨማሪ ነበር ደብዳቤ። በQEMU የደብዳቤ መላኪያ ዝርዝር ውስጥ፣ ነገር ግን ይህ ስለ “ለማንኛውም ማን ያስፈልገዋል?” ለሚለው ጥያቄ የበለጠ ነው። እና ነው። በድንገት, አስፈላጊ ሆኖ ተገኝቷል. ቢያንስ፣ በበለጠ ወይም ባነሰ ፍጥነት የሚሰራ ከሆነ የሚከተሉትን የአጠቃቀም እድሎች በአንድ ላይ መቧጨር ይችላሉ።

  • ያለ ምንም ጭነት ትምህርታዊ ነገር ማስጀመር
  • ቨርቹዋልላይዜሽን በ iOS ላይ፣ በወሬው መሰረት፣ በበረራ ላይ ኮድ የማመንጨት መብት ያለው ብቸኛው መተግበሪያ የጄኤስ ሞተር ነው (ይህ እውነት ነው?)
  • የሚኒ-ስርዓተ ክወና ማሳያ - ነጠላ-ፍሎፒ ፣ አብሮ የተሰራ ፣ ሁሉም ዓይነት firmware ፣ ወዘተ…

የአሳሽ አሂድ ጊዜ ባህሪዎች

አስቀድሜ እንደተናገርኩት QEMU ከብዙ-ክርክር ጋር የተሳሰረ ነው፣ ግን አሳሹ የለውም። ደህና ፣ ማለትም ፣ አይደለም… በመጀመሪያ በጭራሽ አልነበረም ፣ ከዚያ ዌብ ዎርከሮች ታዩ - እኔ እስከሚገባኝ ፣ ይህ በመልእክት ማስተላለፍ ላይ የተመሠረተ ባለብዙ-ክር ነው ያለ የጋራ ተለዋዋጮች. በተጋራው የማህደረ ትውስታ ሞዴል ላይ ተመስርተው ያሉትን ኮድ ሲያስገቡ በተፈጥሮ ይህ ትልቅ ችግር ይፈጥራል። ከዚያም በሕዝብ ግፊት፣ በስሙም ተተግብሯል። SharedArrayBuffers. ቀስ በቀስ ተዋወቀው፣ መጀመሩን በተለያዩ አሳሾች አከበሩ፣ ከዚያም አዲስ አመትን አከበሩ፣ ከዚያም ሜልትዳውን... ከዚያ በኋላ ግምታዊ ወይም የተጋነነ የጊዜ መለኪያ ድምዳሜ ላይ ደርሰዋል፣ ነገር ግን በጋራ ማህደረ ትውስታ ታግዘው እና ሀ ቆጣሪውን የሚጨምር ክር ፣ ሁሉም ተመሳሳይ ነው። በትክክል በትክክል ይሰራል. ስለዚህ በተጋራ ማህደረ ትውስታ ባለብዙ-ክር ንባብን አሰናክለናል። በኋላ ላይ መልሰው ያበሩት ይመስላል, ነገር ግን ከመጀመሪያው ሙከራ ግልጽ ሆኖ, ያለሱ ህይወት አለ, እና እንደዛ ከሆነ, ባለብዙ ክርክሮች ላይ ሳንተማመን ለማድረግ እንሞክራለን.

ሁለተኛው ባህሪ ከቁልል ጋር የዝቅተኛ ደረጃ ማጭበርበሪያዎች የማይቻል ነው፡ በቀላሉ መውሰድ፣ የአሁኑን አውድ ማስቀመጥ እና በአዲስ ቁልል ወደ አዲስ መቀየር አይችሉም። የጥሪ ቁልል የሚተዳደረው በJS ቨርቹዋል ማሽን ነው። አሁንም ቢሆን የቀድሞ ፍሰቶችን ሙሉ በሙሉ በእጅ ለማስተዳደር ስለወሰንን ችግሩ ምን ይመስላል? እውነታው ግን በQEMU ውስጥ ያለው I/O ብሎክ የሚተገበረው በኮሮታይን ነው፣ እና እዚህ ላይ ነው ዝቅተኛ ደረጃ ቁልል ማጭበርበር ጠቃሚ የሚሆነው። እንደ እድል ሆኖ፣ Emscipten ቀድሞውንም ያልተመሳሰሉ ስራዎችን ዘዴ ይዟል፣ ሁለቱም፦ አስምር и አስተርጓሚ. የመጀመሪያው በተፈጠረ ጃቫስክሪፕት ኮድ ውስጥ ጉልህ በሆነ እብጠት ውስጥ ይሰራል እና ከአሁን በኋላ አይደገፍም። ሁለተኛው አሁን ያለው "ትክክለኛ መንገድ" እና ለአገሬው ተርጓሚ በባይቴኮድ ማመንጨት ይሰራል። በእርግጥ ቀስ ብሎ ይሰራል, ነገር ግን ኮዱን አያበሳጭም. እውነት ነው፣ ለዚህ ​​ዘዴ የኮርኦቲን ድጋፍ በተናጥል መሰጠት ነበረበት (ለAsyncify ቀድሞውንም የተፃፉ ኮርቲኖች ነበሩ እና በግምት ተመሳሳይ ኤፒአይ ለአስተርጓሚ ትግበራ ነበር ፣ እነሱን ማገናኘት ያስፈልግዎታል)።

በአሁኑ ጊዜ ኮዱን በWASM ወደተጠናቀረበት እና በEmterpreter በመጠቀም መተርጎም አልቻልኩም ስለዚህ የማገጃ መሳሪያዎች እስካሁን አይሰሩም (በቀጣዩ ተከታታይ ይመልከቱ, እንደሚሉት ...). ማለትም ፣ በመጨረሻ እንደዚህ ያለ አስቂኝ የተነባበረ ነገር ማግኘት አለብዎት።

  • የተተረጎመ እገዳ I/O. ደህና፣ በእርግጥ የተመሰለውን NVMe ከቤተኛ አፈጻጸም ጋር ጠብቀው ነበር? 🙂
  • በስታቲስቲክስ የተጠናቀረ ዋና የQEMU ኮድ (ተርጓሚ፣ ሌሎች የተመሰሉ መሣሪያዎች፣ ወዘተ.)
  • በተለዋዋጭ የተቀናበረ የእንግዳ ኮድ ወደ WASM

የQEMU ምንጮች ባህሪዎች

ምናልባት እርስዎ አስቀድመው እንደገመቱት፣ የእንግዳ አርክቴክቸርን የመኮረጅ ኮድ እና የአስተናጋጅ ማሽን መመሪያዎችን የማመንጨት ኮድ በQEMU ውስጥ ተለያይተዋል። እንዲያውም ትንሽ ተንኮለኛ ነው፡-

  • የእንግዳ አርክቴክቸር አለ።
  • ናት አፋጣኝ፣ ማለትም ፣ KVM ለሃርድዌር ቨርቹዋል በሊኑክስ (ለእንግዶች እና አስተናጋጅ ስርዓቶች እርስ በርሳቸው የሚስማሙ) ፣ TCG ለ JIT ኮድ የትም ቦታ። ከQEMU 2.9 ጀምሮ፣ በዊንዶው ላይ ለHAXM ሃርድዌር ቨርቹዋልነት ደረጃ ድጋፍ ታየ (ዝርዝሮችን።)
  • TCG ጥቅም ላይ የዋለ እና የሃርድዌር ቨርቹዋል ካልሆነ ለእያንዳንዱ አስተናጋጅ አርክቴክቸር እና ለአለም አቀፍ አስተርጓሚ የተለየ የኮድ ማመንጨት ድጋፍ አለው።
  • ... እና በዚህ ዙሪያ - የተስተካከሉ ተጓዳኝ አካላት ፣ የተጠቃሚ በይነገጽ ፣ ፍልሰት ፣ ሪኮርድ-እንደገና ፣ ወዘተ.

በነገራችን ላይ ይህን ያውቁ ኖሯል፡- QEMU ሙሉውን ኮምፒዩተር ብቻ ሳይሆን ፕሮሰሰሩንም ለተለየ የተጠቃሚ ሂደት በአስተናጋጅ ከርነል ውስጥ መኮረጅ ይችላል፣ ይህም ለምሳሌ በ AFL fuzzer ለሁለትዮሽ መሳሪያዎች ስራ ላይ ይውላል። ምናልባት የሆነ ሰው ይህን የQEMU አሠራር ወደ JS መላክ ይፈልግ ይሆን? 😉

እንደ አብዛኛዎቹ ረጅም ጊዜ የቆዩ ነጻ ሶፍትዌሮች፣ QEMU በጥሪው ነው የተሰራው። configure и make. የሆነ ነገር ለመጨመር ወስነሃል እንበል፡ የ TCG ጀርባ፣ የክር ትግበራ፣ ሌላ ነገር። ከAutoconf ጋር የመገናኘት እድል ላይ ለመደሰት/ለማስፈራራት (በተገቢው መሰረት ይሰመርበት) አትቸኩል - በእውነቱ፣ configure QEMU በራሱ የተጻፈ ይመስላል እና ከምንም የተፈጠረ አይደለም።

WebAssembly

ስለዚህ ይህ ነገር WebAssembly (የ WASM በመባል የሚታወቀው) ምንድን ነው? ይህ የAsm.js ምትክ ነው፣ ከአሁን በኋላ የሚሰራ ጃቫስክሪፕት ኮድ አስመስሎ አይደለም። በተቃራኒው ፣ እሱ ሙሉ በሙሉ ሁለትዮሽ እና የተመቻቸ ነው ፣ እና ኢንቲጀርን ወደ እሱ መፃፍ እንኳን በጣም ቀላል አይደለም-ለታመቀ ፣ በቅርጸቱ ውስጥ ይቀመጣል። LEB128 እ.ኤ.አ..

ስለ Asm.js ስለ relooping algorithm ሰምተው ይሆናል - ይህ የ JS ሞተሮች የተቀየሱበት የ “ከፍተኛ ደረጃ” ፍሰት መቆጣጠሪያ መመሪያዎችን (ማለትም ፣ ከዚያ-ሌላ ፣ ወዘተ) ወደነበረበት መመለስ ነው ። ዝቅተኛ-ደረጃ LLVM IR፣ በአቀነባባሪው ወደተሰራው የማሽን ኮድ ቅርብ። በተፈጥሮ፣ የQEMU መካከለኛ ውክልና ወደ ሁለተኛው ቅርብ ነው። እዚህ ያለ ይመስላል፣ ባይትኮድ፣ የሥቃዩ መጨረሻ... እና ከዚያም ብሎኮች፣ ካልሆነ እና ሉፕስ አሉ!...

እና ይሄ Binaryen ጠቃሚ የሆነበት ሌላ ምክንያት ነው፡- በተፈጥሮ በ WASM ውስጥ ከሚከማቹት ጋር ቅርበት ያላቸው ከፍተኛ ደረጃ ብሎኮችን መቀበል ይችላል። ነገር ግን በመካከላቸው ካሉት መሰረታዊ ብሎኮች እና ሽግግሮች ግራፍ ኮድ ማውጣት ይችላል። ደህና፣ የዌብአሴብሊ ማከማቻ ቅርጸቱን ከሚመች C/C++ ኤፒአይ ይደብቃል ብዬ ተናግሬያለሁ።

TCG (ጥቃቅን ኮድ ጄኔሬተር)

ቲ.ሲ. መጀመሪያ ነበር። backend for the C compiler.ከዚያም በግልጽ ከጂሲሲ ጋር ያለውን ውድድር መቋቋም አልቻለም፣ነገር ግን በመጨረሻ በ QEMU ውስጥ ለአስተናጋጅ መድረክ ኮድ ማመንጨት ዘዴ ቦታውን አገኘ። እንዲሁም አንዳንድ ረቂቅ ባይትኮድ የሚያመነጭ TCG ጀርባ አለ፣ እሱም ወዲያውኑ በአስተርጓሚ ነው የሚሰራው፣ ግን በዚህ ጊዜ ላለመጠቀም ወሰንኩ። ይሁን እንጂ በ QEMU ውስጥ በተግባሩ አማካኝነት ወደ ተፈጠረ ቲቢ መሸጋገርን ማስቻል ይቻላል tcg_qemu_tb_exec፣ ለእኔ በጣም ጠቃሚ ሆኖ ተገኘ።

አዲስ የTCG ጀርባ ወደ QEMU ለማከል ንዑስ ማውጫ መፍጠር አለብህ tcg/<имя архитектуры> (በዚህ ጉዳይ tcg/binaryen), እና ሁለት ፋይሎችን ይዟል: tcg-target.h и tcg-target.inc.c и ማዘዝ ስለ ሁሉም ነገር ነው። configure. እዚያ ሌሎች ፋይሎችን ማስቀመጥ ይችላሉ, ነገር ግን ከእነዚህ ከሁለቱ ስሞች እንደሚገምቱት, ሁለቱም አንድ ቦታ ይካተታሉ: አንድ እንደ መደበኛ ራስጌ ፋይል (በዚህ ውስጥ ተካትቷል). tcg/tcg.h, እና ያ አስቀድሞ በማውጫዎች ውስጥ በሌሎች ፋይሎች ውስጥ አለ tcg, accel እና ብቻ ሳይሆን)፣ ሌላኛው - እንደ ኮድ ቅንጭብጭብ ብቻ tcg/tcg.c, ነገር ግን ወደ ቋሚ ተግባራቱ መዳረሻ አለው.

እንዴት እንደሚሰራ በዝርዝር ምርመራዎች ላይ ብዙ ጊዜ እንዳጠፋ በመወሰን የነዚህን ሁለት ፋይሎች "አጽም" ከሌላ የጀርባ አተገባበር ገለበጥኩ፣ ይህም በፍቃዱ ራስጌ ላይ በትክክል አመልክቷል።

ፋይል tcg-target.h በቅጹ ውስጥ በዋናነት ቅንብሮችን ይዟል #define-ሰ:

  • በዒላማው ስነ-ህንፃ ላይ ምን ያህል መመዝገቢያ እና ስፋት ምን ያህል ነው (የምንፈልገውን ያህል አለን ፣ የምንፈልገውን ያህል - ጥያቄው በአሳሹ “ሙሉ በሙሉ ዒላማ” ሥነ ሕንፃ ላይ የበለጠ ቀልጣፋ ኮድ ውስጥ ምን እንደሚፈጠር የበለጠ ነው። ...)
  • የአስተናጋጅ መመሪያዎችን ማመጣጠን-በ x86 ፣ እና በ TCI ውስጥ እንኳን ፣ መመሪያዎች በጭራሽ አልተጣመሩም ፣ ግን በኮድ ቋት ውስጥ በጭራሽ መመሪያዎችን ሳይሆን መመሪያዎችን ወደ Binaryen ቤተ-መጽሐፍት አወቃቀሮች አስገባለሁ ፣ ስለዚህ እላለሁ: 4 ባይት
  • ጀርባው ምን ዓይነት አማራጭ መመሪያዎችን ሊያመነጭ ይችላል - በ Binaryen ውስጥ ያገኘነውን ሁሉ እናካትታለን ፣ አፋጣኙ የቀረውን ወደ ልሹ ቀለል እንዲል ያድርጉ
  • በኋለኛው የተጠየቀው የTLB መሸጎጫ ግምታዊ መጠን ስንት ነው። እውነታው ግን በ QEMU ውስጥ ሁሉም ነገር ከባድ ነው: ምንም እንኳን የእንግዳውን MMU ግምት ውስጥ በማስገባት ሸክም / ማከማቻን የሚያከናውኑ የረዳት ተግባራት ቢኖሩም (አሁን ያለ እኛ የት እንሆናለን?), የትርጉም መሸጎጫቸውን በመዋቅር መልክ ያስቀምጣሉ, የማቀነባበሪያው ሂደት በቀጥታ ወደ ስርጭት ብሎኮች ለመክተት ምቹ ነው። ጥያቄው በዚህ መዋቅር ውስጥ የትኛው ማካካሻ በትንሽ እና ፈጣን የትዕዛዝ ቅደም ተከተል በጣም ቀልጣፋ ነው?
  • እዚህ አንድ ወይም ሁለት የተያዙ መዝገቦችን ዓላማ ማስተካከል፣ ቲቢን በአንድ ተግባር መጥራትን ማንቃት እና እንደ አማራጭ ሁለት ትናንሽ መግለጽ ይችላሉ። inline- ተግባራት flush_icache_range (ነገር ግን ይህ የእኛ ጉዳይ አይደለም)

ፋይል tcg-target.inc.cእርግጥ ነው፣ በመጠን መጠኑ በጣም ትልቅ ነው እና በርካታ አስገዳጅ ተግባራትን ይይዛል።

  • አጀማመር ፣ በየትኛዎቹ ኦፕሬተሮች ላይ የትኛዎቹ መመሪያዎች ሊሰሩ እንደሚችሉ ላይ ገደቦችን ጨምሮ። ከሌላ ደጋፊ በግልፅ በእኔ የተቀዳ
  • አንድ የውስጥ ባይትኮድ መመሪያ የሚወስድ ተግባር
  • እንዲሁም ረዳት ተግባራትን እዚህ ማስቀመጥ ይችላሉ, እና እንዲሁም የማይለዋወጥ ተግባራትን ከ መጠቀም ይችላሉ tcg/tcg.c

ለራሴ, የሚከተለውን ስልት መርጫለሁ-በሚቀጥለው የትርጉም እገዳ የመጀመሪያ ቃላቶች ውስጥ, አራት ጠቋሚዎችን ጻፍኩኝ-የመጀመሪያ ምልክት (በአካባቢው የተወሰነ እሴት) 0xFFFFFFFFየቲቢውን ወቅታዊ ሁኔታ የሚወስነው)፣ አውድ፣ የተፈጠረ ሞጁል እና ለማረም አስማት ቁጥር። መጀመሪያ ላይ ምልክቱ ተቀምጧል 0xFFFFFFFF - nየት n - ትንሽ አወንታዊ ቁጥር, እና በእያንዳንዱ ጊዜ በአስተርጓሚው ሲፈፀም በ 1. ሲደርስ ይጨምራል 0xFFFFFFFE, ማጠናቀር ተካሂዷል, ሞጁሉ በተግባር ሠንጠረዥ ውስጥ ተቀምጧል, ወደ ትንሽ "አስጀማሪ" ገብቷል, ይህም አፈፃፀም ከጀመረበት ጊዜ ጀምሮ ነበር. tcg_qemu_tb_execእና ሞጁሉ ከQEMU ማህደረ ትውስታ ተወግዷል።

ክላሲኮችን ለማብራራት, "ክራች, በዚህ ድምጽ ውስጥ ለፕሮጀክቱ ልብ ምን ያህል የተጠላለፈ ነው ...". ሆኖም ፣ ትውስታው የሆነ ቦታ እየፈሰሰ ነበር። ከዚህም በላይ በ QEMU የሚተዳደር ማህደረ ትውስታ ነበር! የሚቀጥለውን መመሪያ በምጽፍበት ጊዜ (መልካም ፣ ማለትም ጠቋሚ) ፣ አገናኙ ቀደም ብሎ በዚህ ቦታ የነበረውን የሚሰርዝ ኮድ ነበረኝ ፣ ግን ይህ አልረዳም። በእውነቱ፣ በቀላል ሁኔታ፣ QEMU በሚነሳበት ጊዜ ማህደረ ትውስታን ይመድባል እና የመነጨውን ኮድ እዚያ ይጽፋል። ማስቀመጫው ሲያልቅ ኮዱ ይጣላል እና የሚቀጥለው በእሱ ቦታ መፃፍ ይጀምራል.

ኮዱን ካጠናሁ በኋላ፣ በአስማት ቁጥር ያለው ብልሃት በመጀመሪያው ማለፊያ ላይ ባልታወቀ ቋት ላይ ስህተት የሆነ ነገር በማስለቀቅ በከባድ ውድመት ላይ እንዳልወድቅ እንደፈቀደ ተረዳሁ። ግን በኋላ ላይ ተግባሬን ለማለፍ ቋቱን የሚጽፈው ማነው? የEmscripten ገንቢዎች እንደሚመክሩት አንድ ችግር ሲያጋጥመኝ የተገኘውን ኮድ ወደ ቤተኛ አፕሊኬሽኑ መለስኩለት፣ ሞዚላ ሪከርድ-ድጋሚ አጫውትበት... በአጠቃላይ፣ በመጨረሻ አንድ ቀላል ነገር ተገነዘብኩ፡ ለእያንዳንዱ ብሎክ። ሀ struct TranslationBlock ከገለጻው ጋር. የት እንደሆነ ገምት... ልክ ነው፣ ልክ በቋት ውስጥ ከመዘጋቱ በፊት። ይህንን በመገንዘብ ክራንች መጠቀምን ለማቆም ወሰንኩ (ቢያንስ አንዳንዶቹ) እና በቀላሉ የአስማት ቁጥሩን ወረወርኩ እና የቀሩትን ቃላት ወደ ሌላ አስተላልፌአለሁ። struct TranslationBlockየትርጉም መሸጎጫ ዳግም ሲጀመር በፍጥነት ሊያልፍ የሚችል ነጠላ የተገናኘ ዝርዝር መፍጠር እና ማህደረ ትውስታን ነጻ ማድረግ።

አንዳንድ ክራንች ይቀራሉ: ለምሳሌ, በኮድ ቋት ውስጥ ምልክት የተደረገባቸው ጠቋሚዎች - አንዳንዶቹ በቀላሉ ናቸው BinaryenExpressionRef፣ ማለትም ፣ በተፈጠረው መሰረታዊ እገዳ ውስጥ በመስመር ላይ መቀመጥ ያለባቸውን አገላለጾች ይመለከታሉ ፣ ከፊሉ በ BBs መካከል የሚደረግ ሽግግር ሁኔታ ነው ፣ ከፊል የት መሄድ እንዳለበት ነው ። ደህና፣ እንደ ቅድመ ሁኔታው ​​መገናኘት የሚያስፈልጋቸው ለ Relooper አስቀድመው የተዘጋጁ ብሎኮች አሉ። እነሱን ለመለየት ፣ ሁሉም ቢያንስ በአራት ባይት የተስተካከሉ ናቸው የሚለው ግምት ጥቅም ላይ ይውላል ፣ ስለሆነም ለመለያው በጣም ትንሹን ሁለት ቢት በደህና መጠቀም ይችላሉ ፣ አስፈላጊ ከሆነ እሱን ማስወገድ ብቻ ማስታወስ ያስፈልግዎታል። በነገራችን ላይ ከ TCG loop ለመውጣት ምክንያቱን ለማመልከት በQEMU ውስጥ እንደዚህ ያሉ መለያዎች ቀድሞውኑ ጥቅም ላይ ይውላሉ።

Binaryen በመጠቀም

በ WebAssembly ውስጥ ያሉ ሞጁሎች ተግባራትን ይዘዋል, እያንዳንዳቸው አካልን ይይዛሉ, እሱም መግለጫ ነው. አገላለጾች ያልተለመዱ እና ሁለትዮሽ ስራዎች ናቸው, ብሎኮች የሌሎች መግለጫዎችን ዝርዝሮች ያካተቱ, የቁጥጥር ፍሰት, ወዘተ. ቀደም ብዬ እንደተናገርኩት፣ እዚህ ያለው የቁጥጥር ፍሰት ልክ እንደ ከፍተኛ ደረጃ ቅርንጫፎች፣ loops፣ የተግባር ጥሪዎች፣ ወዘተ የተደራጀ ነው። ለተግባሮች የሚነሱ ክርክሮች በቆለሉ ላይ አይተላለፉም፣ ነገር ግን በግልጽ፣ ልክ በJS ውስጥ። አለምአቀፍ ተለዋዋጮችም አሉ, ነገር ግን እኔ አልተጠቀምኩም, ስለዚህ ስለእነሱ አልነግርዎትም.

ተግባራት እንዲሁ የአካባቢ ተለዋዋጮች አሏቸው ፣ ከዜሮ የተቆጠሩ ፣ በዓይነት: int32 / int64 / ተንሳፋፊ / ድርብ። በዚህ ሁኔታ, የመጀመሪያው n የአካባቢ ተለዋዋጮች ወደ ተግባሩ የሚተላለፉ ክርክሮች ናቸው. እባክዎን ያስታውሱ ምንም እንኳን እዚህ ሁሉም ነገር ከቁጥጥር ፍሰት አንፃር ሙሉ በሙሉ ዝቅተኛ ደረጃ ባይሆንም ኢንቲጀሮች አሁንም "የተፈረመ / ያልተፈረመ" ባህሪን አይሸከሙም: ቁጥሩ እንዴት እንደሚሠራ በኦፕሬሽኑ ኮድ ላይ የተመሰረተ ነው.

በአጠቃላይ, Binaryen ያቀርባል ቀላል C-APIሞጁል ትፈጥራለህ በእሱ ውስጥ አገላለጾችን መፍጠር - unary, binary, blocks from other expressions, control flow, ወዘተ. ከዚያም እንደ አካሉ አገላለጽ ተግባር ትፈጥራለህ። እርስዎ ልክ እንደ እኔ ዝቅተኛ-ደረጃ የሽግግር ግራፍ ካሎት፣ የመልሶ ማሰራጫው አካል ይረዳዎታል። እኔ እስከገባኝ ድረስ በብሎክ ውስጥ የማስፈጸሚያ ፍሰት ከፍተኛ ቁጥጥርን መጠቀም ይቻላል ከግድያው ድንበሮች በላይ እስካልሄደ ድረስ - ማለትም የውስጥ ፈጣን መንገድ / ቀርፋፋ ማድረግ ይቻላል. አብሮ በተሰራው የTLB መሸጎጫ ሂደት ኮድ ውስጥ የመንገዱን ቅርንጫፎችን መፍጠር፣ ነገር ግን በ"ውጫዊ" መቆጣጠሪያ ፍሰት ላይ ጣልቃ ላለመግባት። ሪሎፐርን ሲያስፈቱት ብሎኮች ይለቀቃሉ፤ አንድ ሞጁል ሲፈቱ ለእሱ የተመደቡት መግለጫዎች፣ ተግባራት፣ ወዘተ ይጠፋሉ መድረክ.

ነገር ግን፣ ያለአላስፈላጊ ሁኔታ መፍጠር እና የአስተርጓሚ ምሳሌን ሳይሰርዙ ኮድን በበረራ ላይ ለመተርጎም ከፈለጉ፣ ይህንን አመክንዮ ወደ C++ ፋይል ማስገባት ምክንያታዊ ሊሆን ይችላል እና ከዚያ በቀጥታ የላይብረሪውን C++ ኤፒአይ በቀጥታ ያስተዳድሩ እና ዝግጁነትን በማለፍ የተሰሩ መጠቅለያዎች.

ስለዚህ የሚፈልጉትን ኮድ ለመፍጠር

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

... ምንም ነገር ከረሳሁ፣ ይቅርታ፣ ይህ ልኬቱን ለመወከል ብቻ ነው፣ እና ዝርዝሮቹ በሰነድ ውስጥ አሉ።

እና አሁን ክራክ-ፌክስ-ፔክስ ይጀምራል፣ እንደዚህ ያለ ነገር፡-

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

የ QEMU እና JS ዓለሞችን በሆነ መንገድ ለማገናኘት እና በተመሳሳይ ጊዜ የተጠናቀሩ ተግባራትን በፍጥነት ለመድረስ አንድ ድርድር ተፈጠረ (ወደ አስጀማሪው ለማስመጣት የተግባር ሰንጠረዥ) እና የተፈጠሩ ተግባራት እዚያ ተቀምጠዋል። ኢንዴክስን በፍጥነት ለማስላት የዜሮ ቃል የትርጉም ብሎክ ኢንዴክስ መጀመሪያ ላይ እንደ እሱ ጥቅም ላይ ውሎ ነበር፣ ነገር ግን ይህን ፎርሙላ በመጠቀም የተሰላው ኢንዴክስ በቀላሉ በመስክ ውስጥ መግጠም ጀመረ። struct TranslationBlock.

በነገራችን ላይ, ማሳያ (በአሁኑ ጊዜ ከደማቅ ፈቃድ ጋር) በፋየርፎክስ ውስጥ ብቻ በደንብ ይሰራል። Chrome ገንቢዎች ነበሩ። በሆነ መንገድ ዝግጁ አይደለም አንድ ሰው ከአንድ ሺህ በላይ የWebAssembly ሞጁሎችን መፍጠር ስለሚፈልግ በቀላሉ ለእያንዳንዱ አንድ ጊጋባይት ምናባዊ አድራሻ ቦታ መድቧል።

ለጊዜው ይሄው ነው. ምናልባት ማንም ፍላጎት ካለው ሌላ ጽሑፍ ሊኖር ይችላል. ይኸውም ቢያንስ ይቀራል ብቻ የማገጃ መሳሪያዎች እንዲሰሩ ያድርጉ. በJS አለም እንደተለመደው የWebAssembly ሞጁሎችን ማጠናቀር ያልተመሳሰለ ማድረግ ምክንያታዊ ሊሆን ይችላል፣ ምክንያቱም ቤተኛ ሞጁል እስኪዘጋጅ ድረስ ይህን ሁሉ ማድረግ የሚችል አስተርጓሚ አሁንም አለ።

በመጨረሻም እንቆቅልሽ፡- በ32-ቢት አርክቴክቸር ላይ ሁለትዮሽ ሰብስበሃል፣ ነገር ግን ኮዱ፣ በማስታወሻ ስራዎች፣ ከBinaryen መውጣት፣ ቁልል ላይ፣ ወይም ሌላ ቦታ ላይ ባለ 2-ቢት የአድራሻ ቦታ ላይኛው 32 ጂቢ። ችግሩ ከBinaryen እይታ ይህ በጣም ትልቅ የውጤት አድራሻ መድረስ ነው። በዚህ ዙሪያ እንዴት መሄድ ይቻላል?

በአስተዳዳሪው መንገድ

ይህንን ለመፈተሽ አላበቃሁም፣ ግን የመጀመሪያ ሀሳቤ "32-ቢት ሊኑክስን ብጫንስ?" ከዚያም የአድራሻው ቦታ የላይኛው ክፍል በከርነል ተይዟል. ብቸኛው ጥያቄ ምን ያህል እንደሚይዝ ነው፡ 1 ወይም 2 Gb.

በፕሮግራመር መንገድ (የባለሙያዎች አማራጭ)

በአድራሻው ቦታ ላይኛው ክፍል ላይ አረፋ እናነፋ። ለምን እንደሚሰራ እኔ ራሴ አልገባኝም - እዚያ ገና ቁልል መኖር አለበት። ግን "እኛ ተለማማጆች ነን፡ ሁሉም ነገር ይሰራልናል ግን ለምን እንደሆነ ማንም አያውቅም..."

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

ከቫልግሪንድ ጋር ተኳሃኝ አለመሆኑ እውነት ነው ፣ ግን እንደ እድል ሆኖ ፣ ቫልግሪንድ እራሱ ሁሉንም ሰው ከዚያ ያስወጣል :)

ምናልባት አንድ ሰው ይህ የእኔ ኮድ እንዴት እንደሚሰራ የተሻለ ማብራሪያ ይሰጥ ይሆናል...

ምንጭ: hab.com

አስተያየት ያክሉ