Qemu.js ከጂአይቲ ድጋፍ ጋር፡ መሙላት አሁንም ወደ ኋላ መመለስ ይቻላል።

ከጥቂት አመታት በፊት, Fabrice Bellard jslinux ጻፈ በጃቫስክሪፕት የተጻፈ PC emulator ነው። ከዚያ በኋላ ቢያንስ ነበር ምናባዊ x86. ነገር ግን ሁሉም እኔ እስከማውቀው ድረስ ተርጓሚዎች ነበሩ፣ ቄሙ ግን በጣም ቀደም ብሎ በተመሳሳይ ፋብሪስ ቤላርድ የተፃፈው እና ምናልባትም ማንኛውም እራሱን የሚያከብር ዘመናዊ ኢምፓየር በአስተናጋጅ ስርዓት ኮድ ውስጥ የጂአይቲ ማጠናቀርን ይጠቀማል። አሳሾች ከሚፈቱት ጋር በተያያዘ የተገላቢጦሹን ተግባር ተግባራዊ ለማድረግ ጊዜው አሁን መስሎ ታየኝ፡ JIT የማሽን ኮድ ወደ ጃቫ ስክሪፕት ማጠናቀር፣ ለዚህም ምክንያቱ Qemu ወደብ ማድረጉ ምክንያታዊ ነበር። ለምን በትክክል Qemu ቀላል እና ለተጠቃሚ ምቹ የሆኑ emulators አሉ - ተመሳሳይ VirtualBox ፣ ለምሳሌ - ተጭኗል እና ይሰራል። ግን Qemu አንዳንድ አስደሳች ገጽታዎች አሉት።

  • ክፍት ምንጭ
  • ያለ ከርነል ነጂ የመሥራት ችሎታ
  • በአስተርጓሚ ሁነታ የመሥራት ችሎታ
  • ለሁለቱም የአስተናጋጅ እና የእንግዳ ህንፃዎች ብዛት ድጋፍ

በሦስተኛው ነጥብ ወጪ ፣ አሁን እኔ ቀድሞውኑ ማብራራት እችላለሁ በእውነቱ ፣ በ TCI ሁነታ ፣ የእንግዳ ማሽን መመሪያው እራሳቸው አልተተረጎሙም ፣ ግን ከእነሱ የተገኘው ባይት ኮድ ነው ፣ ግን ይህ ምንነቱን አይለውጥም - ለመገንባት እና Qemu ን በአዲስ አርክቴክቸር ያሂዱ፣ እድለኛ ከሆኑ፣ C compiler በቂ ነው - ኮድ ጀነሬተር መፃፍ ለሌላ ጊዜ ሊራዘም ይችላል።

እና አሁን፣ በነጻ ጊዜዬ ውስጥ የ Qemu ምንጭ ኮድን ከሁለት አመት ከወሰድኩ በኋላ፣ አንድ የሚሰራ ፕሮቶታይፕ ታየ፣ በዚህ ውስጥ አስቀድመው መሮጥ ይችላሉ፣ ለምሳሌ፣ Kolibri OS።

Emscript ምንድን ነው?

በአሁኑ ጊዜ ብዙ አቀናባሪዎች አሉ, የመጨረሻው ውጤት ጃቫስክሪፕት ነው. አንዳንዶቹ፣ ልክ እንደ ስክሪፕት አይነት፣ በመጀመሪያ የተፀነሱት ለድር ለመፃፍ ምርጡ መንገድ ነው። በተመሳሳይ ጊዜ Emscripten ያለውን C ወይም C++ ኮድ ወስደህ አሳሹ ሊረዳው በሚችል ቅጽ ማጠናቀር ነው። በርቷል ይህ ገጽ ብዙ ታዋቂ ፕሮግራሞችን ወደቦች ሰብስቧል- እዚህ, ለምሳሌ, PyPy ን መመልከት ይችላሉ - በነገራችን ላይ, እንደተገለጸው, ቀድሞውኑ JIT አላቸው. እንደ እውነቱ ከሆነ, እያንዳንዱ ፕሮግራም በቀላሉ ሊጠናቀር እና በአሳሽ ውስጥ ሊሰራ አይችልም - በርካታ ቁጥር አለ ዋና መለያ ጸባያት, ነገር ግን በዚያው ገጽ ላይ የተቀረጸው ጽሑፍ እንደሚለው, መታገስ አለቦት, "Emscripten ማንኛውንም ማለት ይቻላል ለማጠናቀር ጥቅም ላይ ሊውል ይችላል. በእጅ ሊያዝ የሚችል የC/C++ ኮድ ወደ ጃቫ ስክሪፕት"። ማለትም፣ በመደበኛው ያልተገለጸ ባህሪ ያላቸው በርካታ ኦፕሬሽኖች አሉ፣ነገር ግን አብዛኛውን ጊዜ በ x86 ላይ ይሰራሉ ​​- ለምሳሌ ያልተሰለፈ የተለዋዋጮች መዳረሻ፣ ይህም በአጠቃላይ በአንዳንድ አርክቴክቸር ላይ የተከለከለ ነው። በአጠቃላይ Qemu የመድረክ አቋራጭ ፕሮግራም ነው እና ለማመን ፈልጌ ነበር፣ እና ስለዚህ ብዙ ያልተገለጸ ባህሪ አልያዘም - ይውሰዱት እና ያጠናቅቁ ፣ ከዚያ ከጂአይቲ ጋር ትንሽ ይንከሩ - እና ጨርሰዋል!

መጀመሪያ ሞክር

በአጠቃላይ፣ Qemuን ወደ ጃቫ ስክሪፕት የማጓጓዝ ሀሳብ ያመጣሁት የመጀመሪያው አይደለሁም። በEmscripten ይህ ይቻል እንደሆነ የReactOS መድረክ ጠየቀ። ቀደም ሲል እንኳን ፋብሪስ ቤላርድ በግል እንዳደረገው ወሬዎች ነበሩ ፣ ግን ስለ jslinux ነበር ፣ እኔ እስከማውቀው ድረስ ፣ በጄኤስ ውስጥ በቂ አፈፃፀምን በእጅ ለማሳካት የተደረገ ሙከራ ነው ፣ እና ከባዶ የተጻፈ። በኋላ ፣ ቨርቹዋል x86 ተፃፈ - ያልተጣመሩ ምንጮች በእሱ ላይ ተለጥፈዋል ፣ እና እንደተገለጸው ፣ የማስመሰል ትልቁ “እውነተኛነት” SeaBIOS እንደ firmware ለመጠቀም አስችሎታል። በተጨማሪም Emscriptenን በመጠቀም Qemu ወደብ ለማድረግ ቢያንስ አንድ ሙከራ ነበር - ይህን ለማድረግ ሞከርኩ socketpairእኔ እስከገባኝ ድረስ ልማቱ ቀርቷል።

ስለዚህ ፣ የሚመስለው ፣ የምንጭ ኮዶች እዚህ አሉ ፣ እዚህ Emscripten ነው - ይውሰዱት እና ያጠናቅሩት። ነገር ግን ቀሙ የሚመካባቸው ቤተ-መጻሕፍት እና እነዚያ ቤተ-መጻሕፍት የተመኩባቸው ቤተ-መጻሕፍት ወዘተም አሉ ከነዚህም አንዱ ነው። ሊብፊ, የትኛው glib ይወሰናል. በበይነመረቡ ላይ ለኤምስክሪፕተን ትልቅ የላይብረሪ ወደቦች ስብስብ ውስጥም አለ የሚል ወሬ ነበር ፣ ግን በሆነ መንገድ ለማመን ከባድ ነበር ፣ በመጀመሪያ ፣ በአዲስ አጠናቃሪ አይገነባም ፣ ሁለተኛ ፣ በጣም ዝቅተኛ ነው ። -ደረጃ ቤተ-መጽሐፍት ለመውሰድ እና ወደ JS ለማጠናቀር። እና ስለ መሰብሰቢያ ማስገቢያዎች እንኳን ብቻ አይደለም - ምናልባት ፣ ከተጣመሙ ፣ ከዚያ ለአንዳንድ የጥሪ ስብሰባዎች አስፈላጊዎቹን ክርክሮች በመደርደር ላይ መፍጠር እና ያለ እነሱ ተግባር መደወል ይችላሉ። Emscripten ብቻ እዚህ አሉ - ከባድ ተቃራኒ፡ የመነጨው ኮድ ከአሳሹ JS ሞተር ማበልጸጊያ ጋር በደንብ እንዲታይ አንዳንድ ዘዴዎች ጥቅም ላይ ይውላሉ። በተለይም ሪሎፒንግ ተብሎ የሚጠራው - የተቀበለውን LLVM IR በመጠቀም ኮድ ጀነሬተር ከአንዳንድ ረቂቅ የሽግግር መመሪያዎች ጋር አሳማኝ ifs ፣ loops ፣ ወዘተ እንደገና ለመፍጠር ይሞክራል። ክርክሮች ወደ ተግባራት እንዴት ይተላለፋሉ? በተፈጥሮ ፣ ለጄኤስ ተግባራት እንደ ክርክሮች ፣ ማለትም ፣ ከተቻለ ፣ በቆለሉ አይደለም።

መጀመሪያ ላይ ሀሳቡ በቀላሉ የሊብፊን ምትክ በጄኤስ መጻፍ እና መደበኛ ሙከራዎችን ማድረግ ነበር ፣ ግን በመጨረሻ የእኔን አርዕስት ፋይሎች አሁን ባለው ኮድ እንዲሰሩ እንዴት እንደምሰራ ግራ ገባኝ - ምን ማድረግ እችላለሁ ፣ እንደነሱ። " ተግባራቱ በጣም የተወሳሰበ ነውን ያን ያህል ደደብ ነን? libffiን ወደ ሌላ አርክቴክቸር ማውረዴ ነበረብኝ፣ ለማለት ይቻላል - እንደ እድል ሆኖ፣ Emscripten ሁለቱም ማክሮዎች (በጃቫስክሪፕት ፣ አዎ - ጥሩ ፣ ምን አርክቴክቸር ፣ እንደዚህ ያለ ሰብሳቢ) እና በጉዞ ላይ የመነጨውን ኮድ የማስኬድ ችሎታ አላቸው። በአጠቃላይ፣ ለተወሰነ ጊዜ ከመድረክ-ተኮር የሊብፊ ቁርጥራጮች ጋር ከተጣመርኩ በኋላ፣ የተወሰነ የማጠናቀር ኮድ አገኘሁ፣ እና ባጋጠመው የመጀመሪያ ሙከራ ላይ ሄድኩ። የሚገርመኝ ፈተናው የተሳካ ነበር። ኦፊጌቭ ከሊቅነቱ - ምንም ቀልድ የለም ፣ ከመጀመሪያው ጅምር ሰርቷል - እኔ ፣ አሁንም ዓይኖቼን አላመንኩም ፣ ተጨማሪውን የት መቆፈር እንዳለብኝ ለመገምገም እንደገና የተገኘውን ኮድ ለማየት ወጣሁ ። እዚህ ለሁለተኛ ጊዜ ለውጤት ገባሁ - ተግባሬ ያደረኩት ብቸኛው ነገር ነው። ffi_call - የተሳካ ጥሪ ዘግቧል። ትክክለኛ ጥሪ አልነበረም። እናም ማንኛውም ኦሎምፒያድ ሊረዳው የሚችለውን ስህተት ያረመውን የመጀመሪያ የመጎተት ጥያቄዬን ልኬ ነበር - እውነተኛ ቁጥሮች እንደዚያ ሊነፃፀሩ አይገባም a == b እና እንዴት እንኳን a - b < EPS ሞጁሉን መርሳት የለብንም ፣ አለበለዚያ 0 ከ 1/3 ጋር እኩል ይሆናል ... በአጠቃላይ ፣ በጣም ቀላል የሆኑትን ፈተናዎች የሚያልፍ የተወሰነ የሊብፊ ወደብ አገኘሁ ፣ እና ግሊብ የተጠናቀረበት - አስፈላጊ እንደሚሆን ወሰንኩ, ከዚያ እጨምራለሁ. ወደ ፊት ስመለከት፣ እንደ ተለወጠ፣ አቀናባሪው በሊብፊ ተግባር የመጨረሻ ኮድ ውስጥ እንኳን አላካተተም እላለሁ።

ነገር ግን፣ እንዳልኩት፣ አንዳንድ ገደቦች አሉ፣ እና ከተለያዩ ያልተገለጹ ባህሪያት ነጻ አጠቃቀም መካከል፣ የበለጠ ደስ የማይል ባህሪ ገብቷል - ጃቫ ስክሪፕት በንድፍ ብዙ ስክሪፕት በጋራ ማህደረ ትውስታ መፃፍን አይደግፍም። በመርህ ደረጃ፣ ይህ በአብዛኛው ጥሩ ሀሳብ ተብሎ ሊጠራ ይችላል፣ ነገር ግን ስነ-ህንፃው ከሲሽ ዥረቶች ጋር የተቆራኘ ኮድን ለማስተላለፍ አይደለም። በአጠቃላይ ፋየርፎክስ የጋራ ሰራተኞችን በመደገፍ እየሞከረ ነው፣ እና Emscripten ለእነሱ የፕረድ አተገባበር አለው፣ ግን በእሱ ላይ ጥገኛ መሆን አልፈለግሁም። መልቲ ስክሪንን ከቀሙ ኮድ ቀስ በቀስ ነቅዬ ማውጣት ነበረብኝ - ማለትም ክሩ የት እንደተከፈተ ለማወቅ፣ በዚህ ፈትል ውስጥ የሚሄደውን የሉፕ አካል ወደ ተለየ ተግባር ያንቀሳቅሱ እና እነዚህን ተግባራት አንድ በአንድ ከዋናው ሉፕ ይደውሉ።

ሁለተኛ ሙከራ

በአንድ ወቅት, ነገሮች አሁንም እንዳሉ ግልጽ ሆነ, እና በኮዱ መሰረት ስልታዊ ያልሆነ ክራንች መሙላት ወደ ጥሩ ነገር እንደማይመራ ግልጽ ሆነ. ማጠቃለያ: ክራንችዎችን የመጨመር ሂደትን በሆነ መንገድ ማደራጀት አስፈላጊ ነው. ስለዚህ, በዚያን ጊዜ ትኩስ የነበረው ስሪት 2.4.1, ተወስዷል (2.5.0 አይደለም, ምክንያቱም, መቼም አታውቁም, እስካሁን ያልተያዙ የአዲሱ ስሪት ስህተቶች ይኖራሉ, ግን የእኔ ስህተቶች ለእኔ በቂ ናቸው). ), እና የመጀመሪያው ነገር በደህና እንደገና ተጽፏል thread-posix.c. ደህና ፣ ማለትም ፣ ምን ያህል ደህንነቱ የተጠበቀ ነው-አንድ ሰው ወደ ማገድ የሚያመራውን ቀዶ ጥገና ለማድረግ ከሞከረ ወዲያውኑ ተግባሩ ተጠርቷል። abort() - በእርግጥ ይህ ሁሉንም ችግሮች በአንድ ጊዜ አልፈታም ፣ ግን ቢያንስ በጸጥታ የውሂብ አለመመጣጠን ከመቀበል የበለጠ አስደሳች ነው።

በአጠቃላይ የEmscripten አማራጮች ኮድ ወደ JS በማስተላለፍ ላይ ብዙ ያግዛሉ። -s ASSERTIONS=1 -s SAFE_HEAP=1 - ወደ ያልተጣመረ አድራሻ መድረስ ያሉ አንዳንድ ያልተገለጸ ባህሪን ይይዛሉ (ይህም ከመሳሰሉት የተተየቡ ድርድሮች ኮድ ጋር ፈጽሞ የማይጣጣም ነው) HEAP32[addr >> 2] = 1) ወይም የተግባር ጥሪ ከተሳሳተ የነጋሪዎች ብዛት ጋር።

በነገራችን ላይ የአሰላለፍ ስህተቶች የተለየ ጉዳይ ናቸው. አስቀድሜ እንዳልኩት Qemu "Degenerate" TCI (ጥቃቅን ኮድ ተርጓሚ) የመተርጎም ኮድ ትውልድ ጀርባ አለው እና እድለኛ ከሆንክ C compiler Qemu ን በአዲስ አርክቴክቸር ለመገንባት እና ለማስኬድ በቂ ነው ቁልፍ ቃላት "እድለኛ ከሆንክ". ዕድለኛ አልነበርኩም፣ እና TCI ባይት ኮድ ሲተነተን ያልተጣመረ መዳረሻን እንደሚጠቀም ታወቀ። ያም ማለት በሁሉም ዓይነት ARM እና ሌሎች የግድ የተጣጣመ መዳረሻ ያላቸው ኪሙ ያጠናቅራል ምክንያቱም መደበኛ የ TCG ጀርባ ስላላቸው ቤተኛ ኮድ ያመነጫል፣ ነገር ግን TCI በእነሱ ላይ ይሰራል ወይ ሌላ ጥያቄ ነው። ሆኖም ፣ እንደ ተለወጠ ፣ ተመሳሳይ የሆነ ነገር በ TCI ሰነዶች ውስጥ በግልፅ ታይቷል። በዚህ ምክንያት፣ በሌላ የቄሙ ክፍል የተገኙት ያልተመጣጠነ ንባብ የተግባር ጥሪዎች ወደ ኮድ ተጨመሩ።

ክምር ውድመት

በውጤቱም, በቲሲአይ ውስጥ ያለው ያልተጣጣመ መዳረሻ ተስተካክሏል, ዋናው ሉፕ ፕሮሰሰር, RCU, እና በተራው አንድ ነገር ተብሎ ይጠራል. እና እዚህ እኔ ከአማራጩ ጋር Qemu እየሮጥኩ ነው። -d exec,in_asm,out_asm, ይህም ማለት የትኞቹ የኮድ ብሎኮች እንደሚፈጸሙ መናገር ያስፈልግዎታል, እና በትርጉም ጊዜ, የእንግዳ ኮድ ምን እንደሆነ, የአስተናጋጅ ኮድ ምን እንደ ሆነ (በዚህ ጉዳይ ላይ ባይትኮድ) ይጻፉ. ይጀምራል፣ በርካታ የትርጉም ብሎኮችን ያስፈጽማል፣ የተውኩትን የማረም መልእክት ይጽፋል RCU አሁን ይጀምራል እና ... ይበላሻል። abort() ተግባር ውስጥ free(). ተግባርን በመምረጥ free() ከተመደበው ማህደረ ትውስታ በፊት ባሉት ስምንት ባይቶች ውስጥ ባለው የቆሻሻ መጣያ ራስጌ ውስጥ ፣ በብሎክ መጠኑ ወይም እንደዚህ ያለ ነገር ፋንታ ቆሻሻ እንደነበረ ለማወቅ ችሏል።

ክምርን ማበላሸት - እንዴት ጥሩ ነው ... እንደዚህ ባለ ሁኔታ ውስጥ አንድ ጠቃሚ መሳሪያ አለ - ከተመሳሳይ ምንጮች (ከተቻለ) ተወላጅ ሁለትዮሽ ይገንቡ እና በቫልግሪንድ ስር ያካሂዱት. ከጥቂት ቆይታ በኋላ, ሁለትዮሽ ዝግጁ ነበር. በተመሳሳዩ አማራጮች እሮጣለሁ - አሁንም በመነሻ ላይ ይወድቃል ፣ ሳይደርስ ፣ በእውነቱ አፈፃፀም። ደስ የማይል ነው ፣ በእርግጥ - አየህ ፣ የምንጭ ኮዶች በትክክል ተመሳሳይ አልነበሩም ፣ ይህ አያስገርምም ፣ ምክንያቱም ማዋቀር ጥቂት ሌሎች አማራጮችን ፈልጎ አገኘሁ ፣ ግን ቫልግሪንድ አለኝ - መጀመሪያ ይህንን ስህተት አስተካክላለሁ ፣ እና ከዚያ ፣ እኔ ከሆንኩ ። እድለኛ ነኝ ፣ ዋናው ይመጣል። እኔ ቫልግሪንድ ስር ተመሳሳይ ነገር እየሮጥኩ ነው ... Y-y-y, uh-uh, uh-uh, ጀመረ, በመደበኛነት ተጀመረ እና የተሳሳተ ትውስታ መዳረሻ አንድ ነጠላ ማስጠንቀቂያ ያለ የመጀመሪያውን ስህተት አለፈ, ስለ ውድቀት ሳይጠቅስ. እነሱ እንደሚሉት፣ ህይወት ለዚህ አላዘጋጀችኝም - የተበላሽ ፕሮግራም በቫልግሪንድ ስር ሲጀመር መበላሸቱ ያቆማል። የሆነው ነገር እንቆቅልሽ ነው። የእኔ መላምት አንድ ጊዜ አሁን ባለው መመሪያ አካባቢ ፣በመነሻ ጊዜ ከተከሰቱ በኋላ ፣ gdb ሥራ አሳይቷል ። memset-አንድን በመጠቀም የሚሰራ ጠቋሚ ያለው mmx, ወይም xmm ይመዘግባል፣ ከዚያ ምናልባት የሆነ የአሰላለፍ ስህተት ነበር፣ ምንም እንኳን አሁንም ለማመን ከባድ ነው።

እሺ፣ Valgrind እዚህ እየረዳ ያለ አይመስልም። እና እዚህ በጣም አስቀያሚው ነገር ተጀመረ - ሁሉም ነገር ፣ የሚመስለው ፣ የሚጀምረው እንኳን ፣ ግን በሚሊዮኖች የሚቆጠሩ መመሪያዎች በፊት ሊከሰት በሚችል ክስተት ምክንያት ፍጹም ባልታወቁ ምክንያቶች ይወድቃል። ለረዥም ጊዜ, እንዴት ማሳደግ እንደሚቻል እንኳን ግልጽ አልነበረም. በመጨረሻ፣ አሁንም ተቀምጬ ማረም ነበረብኝ። ራስጌው እንደገና የተፃፈበትን ማተም ቁጥሩ እንደማይመስል ይልቁንም አንድ ዓይነት ሁለትዮሽ ዳታ ያሳያል። እና እነሆ እና እነሆ ፣ ይህ ሁለትዮሽ ሕብረቁምፊ በፋይሉ ውስጥ ከ BIOS ጋር ተገኝቷል - ማለትም ፣ አሁን በበቂ ሁኔታ በእርግጠኝነት መናገር የተቻለው ቋት ሞልቷል ፣ እና ለዚህ ቋት የተጻፈው እንኳን ግልፅ ነበር። ደህና ፣ ከዚያ እንደዚህ ያለ ነገር - በ Emscripten ውስጥ ፣ እንደ እድል ሆኖ ፣ የአድራሻውን ቦታ በዘፈቀደ አይፈጥርም ፣ በውስጡም ምንም ቀዳዳዎች የሉም ፣ ስለዚህ በኮዱ ውፅዓት ውሂብ መሃል ላይ አንድ ቦታ መፃፍ ይችላሉ ከመጨረሻው ሩጫ ፣ ይመልከቱ። በመረጃው ላይ፣ ጠቋሚውን ይመልከቱ፣ እና ያ ካልተለወጠ፣ ለማሰላሰል መረጃ ያግኙ። እውነት ነው፣ ከማንኛውም ለውጥ በኋላ ለማገናኘት ጥቂት ደቂቃዎችን ያሳልፋሉ፣ ግን ምን ማድረግ ይችላሉ። በውጤቱም, ባዮስ (BIOS) ከጊዚያዊ ቋት ወደ እንግዳ ማህደረ ትውስታ የሚገለብጥ አንድ የተወሰነ መስመር ተገኝቷል - እና በእርግጥ, በመጠባበቂያው ውስጥ በቂ ቦታ አልነበረም. የዚያ እንግዳ ቋት አድራሻ ምንጭ ማግኘት አንድ ተግባር አስከትሏል። qemu_anon_ram_alloc በፋይል ውስጥ oslib-posix.c - አመክንዮው እንደሚከተለው ነበር-አንዳንድ ጊዜ አድራሻውን ከ 2 ሜባ መጠን ካለው ግዙፍ ገጽ ጋር ማመጣጠን ጠቃሚ ሊሆን ይችላል ፣ ለዚህም እኛ እንጠይቃለን ። mmap በመጀመሪያ ትንሽ ተጨማሪ, እና ከዚያ በእርዳታ አማካኝነት ትርፍውን ይመልሱ munmap. እና እንደዚህ አይነት አሰላለፍ የማያስፈልግ ከሆነ ከ 2 ሜጋ ባይት ይልቅ ውጤቱን እንጠቁማለን getpagesize() - mmap ግን አሁንም የተጣጣመ አድራሻ ይሰጣል ... ስለዚህ በEmscripten ውስጥ mmap ብቻ ይደውሉ malloc, እና ያ, በእርግጥ, በገጹ ላይ አይጣጣምም. በአጠቃላይ፣ ለሁለት ወራት ያበሳጨኝ ስህተት በለውጥ ተስተካክሏል። двух መስመሮች.

የጥሪ ተግባራት ባህሪያት

እና አሁን ፕሮሰሰር አንድ ነገር እየቆጠረ ነው ፣ Qemu አይበላሽም ፣ ግን ስክሪኑ አይበራም ፣ እና ፕሮሰሰሩ በውጤቱ በመመዘን በፍጥነት ቀለበቶችን ያደርጋል። -d exec,in_asm,out_asm. አንድ መላምት ነበር፡ የሰዓት ቆጣሪ ማቋረጦች አይመጡም (በደንብ፣ ወይም በአጠቃላይ፣ ሁሉም ማቋረጦች)። እና በእርግጥ ፣ ማቋረጦች በተወሰኑ ምክንያቶች ከሠሩት ከአገሬው ተወላጅ ስብሰባ ካልተከፈቱ ፣ ተመሳሳይ ምስል ተገኝቷል። ግን ይህ በፍፁም መልሱ አልነበረም፡ ከላይ ካለው አማራጭ ጋር የወጡትን ዱካዎች ማነፃፀር እንደሚያሳየው የማስፈጸሚያ መንገዶች ቀደም ብለው ይለያያሉ። እዚህ ላይ አስጀማሪውን በመጠቀም የተቀዳውን ንፅፅር መናገሩ አለበት emrun የማረም ውፅዓት ከግንባታ ውፅዓት ጋር በትክክል ሜካኒካል ሂደት አይደለም። በአሳሹ ውስጥ የሚሰራው ፕሮግራም እንዴት እንደሚገናኝ በትክክል አላውቅም emrun, ነገር ግን በውጤቱ ውስጥ ያሉ አንዳንድ መስመሮች እንደገና ተስተካክለው ይለወጣሉ, ስለዚህ የልዩነቱ ልዩነት ትራኮች ተለያይተዋል ብሎ ለማመን ምክንያት አይደለም. በአጠቃላይ, እንደ መመሪያው ግልጽ ሆነ ljmpl ወደ ተለያዩ አድራሻዎች የሚደረግ ሽግግር አለ, እና ባይትኮድ በመሠረቱ የተለየ ነው: በአንደኛው ውስጥ የረዳት ተግባሩን ለመጥራት መመሪያ አለ, በሌላኛው ግን አይደለም. መመሪያውን ከተመለከትን እና እነዚህን መመሪያዎች የሚተረጉመውን ኮድ ካጠና በኋላ ፣ በመጀመሪያ ፣ በመዝገቡ ውስጥ በቀጥታ ከሱ በፊት እንደነበረ ግልፅ ሆነ ። cr0 መዝገብ ተሰራ - እንዲሁም በረዳት እገዛ - ፕሮሰሰሩን ወደ የተጠበቀ ሁነታ በማስተላለፍ እና በሁለተኛ ደረጃ የ js ስሪት ወደ የተጠበቀ ሁነታ አልተለወጠም. እውነታው ግን ሌላው የEmscripten ባህሪ እንደ መመሪያ ትግበራ ኮድን ለመቀበል ፈቃደኛ አለመሆን ነው። call በTCI ውስጥ የትኛውም ተግባር ጠቋሚ ወደ አንድ ዓይነት ይጥላል long long f(int arg0, .. int arg9) - ተግባራት በትክክለኛው የክርክር ብዛት መጠራት አለባቸው። ይህ ደንብ ከተጣሰ, እንደ ማረም ቅንጅቶች, ፕሮግራሙ ይወድቃል (ጥሩ ነው), ወይም የተሳሳተውን ተግባር ጨርሶ ይደውሉ (ይህም ለማረም አሳዛኝ ይሆናል). ሦስተኛው አማራጭ ደግሞ አለ - ክርክሮችን የሚጨምሩ / የሚጥሉ መጠቅለያዎችን ለማንቃት ፣ ግን በአጠቃላይ እነዚህ መጠቅለያዎች ብዙ ቦታ ይወስዳሉ ፣ ምንም እንኳን በእውነቱ እኔ ከመቶ በላይ መጠቅለያዎች ብቻ እፈልጋለሁ ። ይህ ብቻ በጣም አሳዛኝ ነው, ነገር ግን ይበልጥ ከባድ ችግር ሆኖ ተገኘ: ወደ መጠቅለያ ተግባራት የመነጨ ኮድ ውስጥ, ክርክሮች ተቀይሯል-የተለወጠ ነበር, ብቻ ​​የመነጩ ክርክሮች ጋር ተግባር አንዳንድ ጊዜ ተብሎ አይደለም - መልካም, ልክ ውስጥ. የእኔ የlibffi አተገባበር። ይኸውም አንዳንድ ረዳቶች በቀላሉ አልተገደሉም።

እንደ እድል ሆኖ፣ Qemu በማሽን ሊነበብ የሚችል የረዳቶች ዝርዝር እንደ ራስጌ ፋይል አለው።

DEF_HELPER_0(lock, void)
DEF_HELPER_0(unlock, void)
DEF_HELPER_3(write_eflags, void, env, tl, i32)

በጣም አስቂኝ ጥቅም ላይ ይውላሉ: በመጀመሪያ, ማክሮዎች በጣም በሚያስገርም መንገድ እንደገና ተገልጸዋል DEF_HELPER_n, እና ከዚያ ያካትቱ helper.h. እስከ እውነታው ድረስ ማክሮው ወደ መዋቅር ጀማሪ እና ወደ ኮማ ተዘርግቷል ፣ እና ከዚያ ድርድር ይገለጻል ፣ እና በንጥረ ነገሮች ምትክ - #include <helper.h> በውጤቱም, በመጨረሻ ቤተ-መጽሐፍቱን ለመሞከር ምክንያት አገኘሁ pyparsing, እና በትክክል ለእነዚያ እና በትክክል ለሚፈልጉት ተግባራት መጠቅለያዎችን የሚያመነጭ ስክሪፕት ተጽፏል።

እና አሁን, ከዚያ በኋላ, ሂደተሩ ያገኘ ይመስላል. ምንም እንኳን memtest86+ በቤተኛ ጉባኤ ውስጥ መስራት ቢችልም ስክሪኑ በጭራሽ ስላልተጀመረ ይመስላል። እዚህ ላይ የ Qemu ብሎክ I/O ኮድ በኮሮቲን ውስጥ መጻፉን ግልጽ ማድረግ ያስፈልጋል። Emscripten የራሱ በጣም ተንኮለኛ አተገባበር አለው፣ ግን አሁንም በQemu ኮድ ውስጥ መደገፍ አለበት፣ እና ፕሮሰሰሩን አሁን ማረም ይችላሉ፡ Qemu አማራጮችን ይደግፋል። -kernel, -initrd, -appendበማንኛውም የማገጃ መሳሪያዎች ሳይጠቀሙ ሊኑክስን ወይም ለምሳሌ memtest86+ ማስነሳት ይችላሉ። ግን ችግሩ እዚህ አለ፡ በአገሬው ጉባኤ ውስጥ አንድ ሰው የሊኑክስ ከርነል ወደ ኮንሶሉ የሚወጣውን አማራጭ ከአማራጭ ጋር መመልከት ይችላል። -nographic, እና ከአሳሹ ወደ ተጀመረበት ተርሚናል ምንም ውጤት የለም emrun፣ አልመጣም። ማለትም ፣ ግልጽ አይደለም-አቀነባባሪው እየሰራ አይደለም ወይም የግራፊክስ ውፅዓት። እና ከዚያ ትንሽ መጠበቅ ታየኝ። “አቀነባባሪው ተኝቶ ሳይሆን በቀስታ ብልጭ ድርግም የሚል” ሆኖ ተገኘ እና ከአምስት ደቂቃ በኋላ ፍሬው ብዙ መልእክቶችን ወደ ኮንሶሉ ላይ ጣለው እና ተንጠልጥሎ ቀጠለ። አንጎለ ኮምፒውተር በአጠቃላይ እንደሚሰራ ግልጽ ሆነ እና ከ SDL2 ጋር ለመስራት ኮዱን መቆፈር ያስፈልግዎታል። እንደ አለመታደል ሆኖ ይህን ቤተ-መጽሐፍት እንዴት እንደምጠቀም አላውቅም፣ ስለዚህ በአንዳንድ ቦታዎች በዘፈቀደ እርምጃ መውሰድ ነበረብኝ። በአንድ ወቅት፣ መስመሩ parallel0 በሰማያዊ ዳራ ላይ በስክሪኑ ላይ ብልጭ ድርግም ይላል፣ ይህም ወደ አንዳንድ ሀሳቦች አመራ። በውጤቱም, ነጥቡ Qemu በአንድ አካላዊ መስኮት ውስጥ በርካታ ምናባዊ መስኮቶችን ይከፍታል, በመካከላቸው Ctrl-Alt-n ን በመጠቀም መቀያየር ይችላሉ-በአገሬው ጉባኤ ውስጥ ይሰራል, ነገር ግን በ Emscripten ውስጥ አይደለም. አማራጮችን በመጠቀም አላስፈላጊ መስኮቶችን ካስወገዱ በኋላ -monitor none -parallel none -serial none እና ስክሪኑ በሙሉ በእያንዳንዱ ፍሬም ላይ እንደገና እንዲቀረጽ ለማስገደድ መመሪያዎች በድንገት ተሰራ።

ኮሮቲንስ

ስለዚህ በአሳሹ ውስጥ መኮረጅ ይሠራል ፣ ግን በአንድ ዲስክ ላይ ምንም አስደሳች ነገር በእሱ ውስጥ ሊጀመር አይችልም ፣ ምክንያቱም I / O ምንም እገዳ ስለሌለ - ለኮርቲኖች ድጋፍን መተግበር ያስፈልግዎታል። Qemu ቀድሞውንም በርካታ የኮርኦታይን ጀርባ አለው፣ ነገር ግን በጃቫ ስክሪፕት እና በEmscripten ኮድ ጀነሬተር ልዩ ባህሪዎች ምክንያት፣ ቁልል መገጣጠም ብቻ መጀመር አይችሉም። "ሁሉም ነገር ጠፍቷል, ፕላስተር እየተወገደ ነው" ይመስላል, ነገር ግን Emscripten ገንቢዎች ሁሉንም ነገር አስቀድመው ወስደዋል. ይህ በጣም አስቂኝ ነው የተተገበረው፡ እንደ ተግባር ጥሪ እንጥራ emscripten_sleep እና ሌሎች በርካታ ሰዎች Asyncify ዘዴን በመጠቀም፣ እንዲሁም ጠቋሚ ጥሪዎች እና ጥሪዎች ካለፉት ሁለት ጉዳዮች አንዱ ቁልል ላይ ወደሚችልበት ማንኛውም ተግባር። እና አሁን ከእያንዳንዱ አጠራጣሪ ጥሪ በፊት የአስምር አውድ እንመርጣለን እና ከጥሪው በኋላ ወዲያውኑ ያልተመሳሰለ ጥሪ መከሰቱን እንፈትሻለን ፣ እና ካለ ፣ በዚህ አሲኒክ አውድ ውስጥ ሁሉንም የአካባቢ ተለዋዋጮች እናስቀምጣለን ፣ የትኛውን ተግባር ያመልክቱ። መቆጣጠሪያውን ወደ አፈፃፀሙ ለመቀጠል አስፈላጊ በሚሆንበት ጊዜ ለማስተላለፍ እና አሁን ካለው ተግባር ይውጡ። ውጤቱን የማጥናት ወሰን እዚያ ነው። ማባከን - ከተመሳሳይ ጥሪ ከተመለሰ በኋላ ለቀጣይ የኮድ አፈፃፀም ፍላጎቶች አቀናባሪው ከተጠራጣሪ ጥሪ በኋላ የሚጀምረውን ተግባር “stubs” ያመነጫል - እንደዚህ: አጠራጣሪ ጥሪዎች ካሉ ፣ ከዚያ ተግባሩ በሆነ ቦታ ይባክናል n / 2 ጊዜ - ያ አሁንም ነው፣ ከእያንዳንዱ የማይመሳሰል ጥሪ በኋላ፣ የአካባቢያዊ ተለዋዋጮችን የተወሰነ ክፍል ወደ መጀመሪያው ተግባር ማቆየት እንዳለብዎት ልብ ይበሉ። በመቀጠል፣ ቀላል የፓይዘን ስክሪፕት መፃፍ ነበረብኝ፣ እሱም በተለይ የተበላሹ ተግባራት ስብስብ እንደሚለው፣ ምናልባትም፣ “ተመሳሳይነት በራሳቸው ውስጥ እንዲያልፍ አይፈቅዱም” (ማለትም፣ መደራረብ እና አሁን የገለጽኩትን ሁሉ)። በእነሱ ውስጥ አይሰራም) ይጠቁማል ፣ በጠቋሚዎች ጥሪዎች ውስጥ እነዚህ ተግባራት እንደ አልተመሳሰለም ተደርገው እንዳይቆጠሩ በአቀነባባሪው ችላ ሊባሉ ይገባል ። እና ከዚያ JS-ፋይሎች ከ 60 ሜባ በታች ቀድሞውኑ ከመጠን በላይ ናቸው - ምንም እንኳን ቢያንስ 30. ምንም እንኳን ፣ አንዴ የግንባታ ስክሪፕት አዘጋጀሁ ፣ እና በአጋጣሚ የአገናኝ አማራጮችን ጣለው ፣ ከእነዚህም መካከል -O3. የተፈጠረውን ኮድ አሂዳለው፣ እና Chromium ማህደረ ትውስታን ይበላል እና ይበላሻል። ያኔ በአጋጣሚ ሊወርድ የፈለገውን ተመለከትኩኝ...እሺ ምን ልበል፣ 500+ MB javascriptን በአሳቢነት እንዳጠናና እንዲያመቻች ከተጠየቅኩኝ ደግሞ እዘጋለሁ።

እንደ አለመታደል ሆኖ በAsyncify የድጋፍ ቤተ-መጽሐፍት ውስጥ ያሉት ቼኮች ለጓደኛሞች አልነበሩም longjmp-ami, በቨርቹዋል ፕሮሰሰር ኮድ ውስጥ ጥቅም ላይ የሚውሉ, ነገር ግን እነዚህን ቼኮች የሚያሰናክል እና ሁሉም ነገር ጥሩ እንደሆነ አስገድዶ አውዶችን የሚያድስ ትንሽ ፕላስተር በኋላ, ኮዱ ሠርቷል. እና ከዚያ አንድ እንግዳ ነገር ተጀመረ፡ አንዳንድ ጊዜ የማመሳሰያ ኮድ ቼኮች ይሰሩ ነበር - እንደ አፈፃፀሙ አመክንዮ ከሆነ ማገድ ካለበት ኮዱን የሚያበላሹት - አንድ ሰው ቀድሞውኑ የተያዘውን ሙቴክስ ለመያዝ ሞክሮ ነበር። እንደ እድል ሆኖ, ይህ በተከታታይ ኮድ ውስጥ ምክንያታዊ ችግር አይደለም - እኔ በኤምስክሪፕት የሚሰጠውን መደበኛውን የዋና ሉፕ ተግባር ብቻ ተጠቀምኩ ፣ ግን አንዳንድ ጊዜ ያልተመሳሰለው ጥሪ ቁልልውን ሙሉ በሙሉ ፈታው እና በዚያ ቅጽበት ሠርቷል ። setTimeout ከዋናው ሉፕ - ስለዚህ ኮዱ ከቀዳሚው ድግግሞሽ ሳይወጣ ወደ ዋናው ዑደት ገባ። ማለቂያ በሌለው ሉፕ ላይ እንደገና ይፃፉ እና emscripten_sleep, እና የ mutex ችግሮች ቆመዋል. ኮዱ የበለጠ አመክንዮአዊ ሆኗል - ለነገሩ ፣ በእውነቱ ፣ የሚቀጥለውን የአኒሜሽን ፍሬም የሚያዘጋጅ ኮድ የለኝም - ፕሮሰሰሩ አንድ ነገር ሲያሰላ እና ማያ ገጹ በየጊዜው ይሻሻላል። ነገር ግን ችግሮቹ በዚህ ብቻ አላቆሙም፡ አንዳንድ ጊዜ የቅሙ ግድያ ያለምንም ልዩነት እና ስህተት በጸጥታ ያበቃል። በዚያን ጊዜ ተስፋ ቆርጬበት ነበር ፣ ግን ወደ ፊት ስመለከት ፣ ችግሩ ይህ ነው እላለሁ-የኮርቲን ኮድ ፣ በእውነቱ ፣ አይጠቀምም setTimeout (በደንብ, ወይም ቢያንስ እርስዎ እንደሚያስቡት ብዙ ጊዜ አይደለም): ተግባር emscripten_yield ልክ ያልተመሳሰል የጥሪ ባንዲራ ያጋልጣል። ጨው ሁሉ ያ ነው። emscripten_coroutine_next ያልተመሳሰለ ተግባር አይደለም፡ ከውስጥ፣ ባንዲራውን ይፈትሻል፣ ዳግም ያስጀምረው እና መቆጣጠሪያውን ወደ ትክክለኛው ቦታ ያስተላልፋል። ማለትም የቁልል መፍታት እዚያ ያበቃል። ችግሩ ያለው ከጥቅም-በኋላ-ነጻ በመጣው የኮሮቲን ፑል ሲሰናከል በነበረበት ጊዜ አስፈላጊ የሆነ የኮድ መስመር ከነባሩ የኮርኦታይን ደጋፊ ስላልገለበጥኩ ተግባሩ ነው። qemu_in_coroutine በውሸት መመለስ ሲገባው እውነት ተመለሰ። ይህም ጥሪውን አደረሰ emscripten_yield, በላዩ ላይ ምንም ቁልል አልነበረም emscripten_coroutine_next, ቁልል እስከ ላይ ተዘርግቷል, ግን አይደለም setTimeoutእንዳልኩት ለኤግዚቢሽን አልነበረም።

የጃቫስክሪፕት ኮድ ማመንጨት

እና እዚህ ፣ በእውነቱ ፣ የተገባው ቃል “እቃውን ወደ ኋላ መመለስ” ነው። እውነታ አይደለም. በእርግጥ Qemu ን በአሳሹ ውስጥ እና በውስጡም Node.js ን ካስኬዱ ፣ በተፈጥሮ ፣ በ Qemu ውስጥ ኮድ ከተፈጠረ በኋላ ፣ ሙሉ ለሙሉ የተለየ ጃቫ ስክሪፕት እናገኛለን። ግን አሁንም ፣ ምን - አይደለም ፣ ግን የተገላቢጦሽ ለውጥ።

በመጀመሪያ፣ Qemu እንዴት እንደሚሰራ ትንሽ። እባክዎን ወዲያውኑ ይቅርታ ያድርጉልኝ፡ እኔ ፕሮፌሽናል የቄሙ ገንቢ አይደለሁም እና ድምዳሜዎቼ በቦታዎች ላይ የተሳሳቱ ሊሆኑ ይችላሉ። እነሱ እንደሚሉት, "የተማሪው አስተያየት ከመምህሩ አስተያየት, የፔኖ አክሲዮማቲክስ እና የጋራ ማስተዋል ጋር እንዲጣጣም አይገደድም." Qemu በርካታ የሚደገፉ የእንግዳ አርክቴክቸር አለው እና እያንዳንዳቸው እንደ ማውጫ አላቸው። target-i386. በሚገነቡበት ጊዜ, ለብዙ የእንግዳ አርክቴክቸር ድጋፍን መግለጽ ይችላሉ, ነገር ግን ውጤቱ ጥቂት ሁለትዮሽ ብቻ ይሆናል. የእንግዳ አርክቴክቸርን የሚደግፍ ኮድ በበኩሉ አንዳንድ ውስጣዊ የ Qemu ስራዎችን ያመነጫል፣ ይህም TCG (ጥቃቅን ኮድ ጀነሬተር) አስቀድሞ ወደ አስተናጋጅ አርክቴክቸር ማሽን ኮድ ይቀየራል። በ tcg ማውጫ ውስጥ ባለው የ readme ፋይል ላይ እንደተገለጸው፣ እሱ በመጀመሪያ የመደበኛ C ማጠናከሪያ አካል ነበር፣ እሱም ለጂአይቲ ተስተካክሏል። ስለዚህ፣ ለምሳሌ፣ ከዚህ ሰነድ አንፃር ኢላማ አርክቴክቸር እንግዳ አይደለም፣ ግን አስተናጋጅ አርክቴክቸር ነው። በአንድ ወቅት, ሌላ አካል ታየ - ጥቃቅን ኮድ ተርጓሚ (ቲሲአይ) , እሱም ኮድ (አንድ አይነት የውስጥ ስራዎች ማለት ይቻላል) ለአንድ የተወሰነ አስተናጋጅ አርክቴክቸር ኮድ ጄኔሬተር በሌለበት ሁኔታ ማከናወን አለበት. እንደ እውነቱ ከሆነ, ሰነዶቹ እንደሚለው, ይህ አስተርጓሚ ሁልጊዜም እንደ JIT ኮድ ጄኔሬተር ላይሰራ ይችላል, በቁጥር ብቻ ሳይሆን በጥራትም ጭምር. ምንም እንኳን የእሱ መግለጫ ሙሉ በሙሉ ወቅታዊ ስለመሆኑ እርግጠኛ አይደለሁም።

መጀመሪያ ላይ ሙሉ የ TCG ጀርባ ለመስራት ሞከርኩ ፣ ግን በፍጥነት በምንጭ ኮዶች እና በባይቴኮድ መመሪያው ላይ ሙሉ በሙሉ ግልፅ ያልሆነ መግለጫ ግራ ተጋባሁ ፣ ስለሆነም የ TCI አስተርጓሚውን ለመጠቅለል ወሰንኩ ። ይህ በአንድ ጊዜ በርካታ ጥቅሞችን ሰጥቷል-

  • የኮድ ጀነሬተርን በሚተገበርበት ጊዜ የመመሪያውን መግለጫ ሳይሆን የአስተርጓሚውን ኮድ መመልከት ይቻል ነበር።
  • ለእያንዳንዱ የተገናኘ የትርጉም እገዳ ተግባራትን ማመንጨት ይቻላል ፣ ግን ለምሳሌ ፣ ከመቶው ግድያ በኋላ ብቻ።
  • በተፈጠረው ኮድ ላይ ለውጥ በሚከሰትበት ጊዜ (እና ይህ ፣ እንደሚታየው ፣ የሚቻል ነው ፣ የቃሉን መጠገኛ በያዙት ተግባራት በመመዘን) የተፈጠረውን የ JS ኮድ ውድቅ ማድረግ አለብኝ ፣ ግን ቢያንስ እሱን ለማደስ አንድ ነገር ይኖረኛል ። ከ

ሦስተኛውን ነጥብ በተመለከተ፣ ኮዱ ለመጀመሪያ ጊዜ ከተፈጸመ በኋላ መታጠፍ እንደሚቻል እርግጠኛ አይደለሁም፣ ነገር ግን የመጀመሪያዎቹ ሁለት ነጥቦች በቂ ናቸው።

መጀመሪያ ላይ ኮዱ የተፈጠረው በዋናው የባይቴኮድ መመሪያ አድራሻ በትልቁ መቀየሪያ መልክ ነበር፣ነገር ግን ስለ ኤምስክሪፕተን ፅሁፉን በማስታወስ፣ የፈጠረውን JS ማመቻቸት እና እንደገና መዞር፣ የበለጠ የሰው ኮድ ለማመንጨት ወሰንኩ፣በተለይም በemmpirically ወደ የትርጉም እገዳው ብቸኛው የመግቢያ ነጥቡ ጅምር እንደሆነ ተረጋግጧል። ብዙም ሳይቆይ፣ ከትንሽ ጊዜ በኋላ ኮድ የሚያመነጭ ኮድ ጄኔሬተር አገኘን በ ifs (ምንም እንኳን ያለ loops)። ነገር ግን መጥፎው ዕድል ይኸውና ወድቆ መመሪያው የተሳሳተ ርዝመት እንዳለው መልእክት ሰጥቷል። በዚህ ሁኔታ, በዚህ የመድገም ደረጃ የመጨረሻው መመሪያ ነበር brcond. ደህና፣ የዚህን መመሪያ ትውልድ ከተደጋጋሚ ጥሪ በፊት እና በኋላ አንድ አይነት ቼክ እጨምራለሁ፣ እና ... አንዳቸውም አልተፈጸሙም ፣ ግን ከተቀየረ በኋላ ፣ ማረጋገጫው አሁንም ወድቋል። በመጨረሻ ፣ የተፈጠረውን ኮድ ከመረመርኩ በኋላ ፣ ከተቀየረው በኋላ ፣ አሁን ያለው መመሪያ ጠቋሚው ከቁልል እንደገና እንደተጫነ እና ምናልባትም በተፈጠረው የጃቫ ስክሪፕት ኮድ የተበላሸ መሆኑን ተገነዘብኩ። እንደዚያም ሆነ። ቋቱን ከአንድ ሜጋባይት ወደ አስር ማሳደግ ወደ ምንም ነገር አላመራም ፣ እና የኮድ ጀነሬተር በክበብ ውስጥ እየሰራ መሆኑ ግልፅ ሆነ። አሁን ካለው የቲቢ ወሰን አልፈን አለመሄዳችንን ማረጋገጥ ነበረብን፣ እና ካደረግን የቀጣዩን ቲቢ አድራሻ በመቀነስ ምልክት ስጠን ግድያውን እንቀጥል። በተጨማሪም, ይህ ችግሩን ይፈታል "ይህ የባይቴኮድ ቁራጭ ከተቀየረ ለመሰረዝ የትኞቹ የመነጩ ተግባራት?" - ከዚህ የትርጉም እገዳ ጋር የሚዛመደውን ተግባር ብቻ ማበላሸት ያስፈልግዎታል። በነገራችን ላይ በChromium ውስጥ ያለውን ነገር ሁሉ ባጠፋም (ፋየርፎክስን ስለምጠቀም ​​እና ለሙከራ የተለየ አሳሽ ለመጠቀም ስለሚቀልልኝ) ፋየርፎክስ ከ asm.js ስታንዳርድ ጋር ተኳሃኝነቶችን እንዳስተካክል ረድቶኛል፣ ከዚያ በኋላ ኮዱ በ ውስጥ በፍጥነት መስራት ጀመረ። Chromium

የመነጨ ኮድ ምሳሌ

Compiling 0x15b46d0:
CompiledTB[0x015b46d0] = function(stdlib, ffi, heap) {
"use asm";
var HEAP8 = new stdlib.Int8Array(heap);
var HEAP16 = new stdlib.Int16Array(heap);
var HEAP32 = new stdlib.Int32Array(heap);
var HEAPU8 = new stdlib.Uint8Array(heap);
var HEAPU16 = new stdlib.Uint16Array(heap);
var HEAPU32 = new stdlib.Uint32Array(heap);

var dynCall_iiiiiiiiiii = ffi.dynCall_iiiiiiiiiii;
var getTempRet0 = ffi.getTempRet0;
var badAlignment = ffi.badAlignment;
var _i64Add = ffi._i64Add;
var _i64Subtract = ffi._i64Subtract;
var Math_imul = ffi.Math_imul;
var _mul_unsigned_long_long = ffi._mul_unsigned_long_long;
var execute_if_compiled = ffi.execute_if_compiled;
var getThrew = ffi.getThrew;
var abort = ffi.abort;
var qemu_ld_ub = ffi.qemu_ld_ub;
var qemu_ld_leuw = ffi.qemu_ld_leuw;
var qemu_ld_leul = ffi.qemu_ld_leul;
var qemu_ld_beuw = ffi.qemu_ld_beuw;
var qemu_ld_beul = ffi.qemu_ld_beul;
var qemu_ld_beq = ffi.qemu_ld_beq;
var qemu_ld_leq = ffi.qemu_ld_leq;
var qemu_st_b = ffi.qemu_st_b;
var qemu_st_lew = ffi.qemu_st_lew;
var qemu_st_lel = ffi.qemu_st_lel;
var qemu_st_bew = ffi.qemu_st_bew;
var qemu_st_bel = ffi.qemu_st_bel;
var qemu_st_leq = ffi.qemu_st_leq;
var qemu_st_beq = ffi.qemu_st_beq;

function tb_fun(tb_ptr, env, sp_value, depth) {
  tb_ptr = tb_ptr|0;
  env = env|0;
  sp_value = sp_value|0;
  depth = depth|0;
  var u0 = 0, u1 = 0, u2 = 0, u3 = 0, result = 0;
  var r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0, r6 = 0, r7 = 0, r8 = 0, r9 = 0;
  var r10 = 0, r11 = 0, r12 = 0, r13 = 0, r14 = 0, r15 = 0, r16 = 0, r17 = 0, r18 = 0, r19 = 0;
  var r20 = 0, r21 = 0, r22 = 0, r23 = 0, r24 = 0, r25 = 0, r26 = 0, r27 = 0, r28 = 0, r29 = 0;
  var r30 = 0, r31 = 0, r41 = 0, r42 = 0, r43 = 0, r44 = 0;
    r14 = env|0;
    r15 = sp_value|0;
  START: do {
    r0 = HEAPU32[((r14 + (-4))|0) >> 2] | 0;
    r42 = 0;
    result = ((r0|0) != (r42|0))|0;
    HEAPU32[1445307] = r0;
    HEAPU32[1445321] = r14;
    if(result|0) {
    HEAPU32[1445322] = r15;
    return 0x0345bf93|0;
    }
    r0 = HEAPU32[((r14 + (16))|0) >> 2] | 0;
    r42 = 8;
    r0 = ((r0|0) - (r42|0))|0;
    HEAPU32[(r14 + (16)) >> 2] = r0;
    r1 = 8;
    HEAPU32[(r14 + (44)) >> 2] = r1;
    r1 = r0|0;
    HEAPU32[(r14 + (40)) >> 2] = r1;
    r42 = 4;
    r0 = ((r0|0) + (r42|0))|0;
    r2 = HEAPU32[((r14 + (24))|0) >> 2] | 0;
    HEAPU32[1445307] = r0;
    HEAPU32[1445308] = r1;
    HEAPU32[1445309] = r2;
    HEAPU32[1445321] = r14;
    HEAPU32[1445322] = r15;
    qemu_st_lel(env|0, r0|0, r2|0, 34, 22759218);
if(getThrew() | 0) abort();
    r0 = 3241038392;
    HEAPU32[1445307] = r0;
    r0 = qemu_ld_leul(env|0, r0|0, 34, 22759233)|0;
if(getThrew() | 0) abort();
    HEAPU32[(r14 + (24)) >> 2] = r0;
    r1 = HEAPU32[((r14 + (12))|0) >> 2] | 0;
    r2 = HEAPU32[((r14 + (40))|0) >> 2] | 0;
    HEAPU32[1445307] = r0;
    HEAPU32[1445308] = r1;
    HEAPU32[1445309] = r2;
    qemu_st_lel(env|0, r2|0, r1|0, 34, 22759265);
if(getThrew() | 0) abort();
    r0 = HEAPU32[((r14 + (24))|0) >> 2] | 0;
    HEAPU32[(r14 + (40)) >> 2] = r0;
    r1 = 24;
    HEAPU32[(r14 + (52)) >> 2] = r1;
    r42 = 0;
    result = ((r0|0) == (r42|0))|0;
    if(result|0) {
    HEAPU32[1445307] = r0;
    HEAPU32[1445308] = r1;
    }
    HEAPU32[1445307] = r0;
    HEAPU32[1445308] = r1;
    return execute_if_compiled(22759392|0, env|0, sp_value|0, depth|0) | 0;
    return execute_if_compiled(23164080|0, env|0, sp_value|0, depth|0) | 0;
    break;
  } while(1); abort(); return 0|0;
}
return {tb_fun: tb_fun};
}(window, CompilerFFI, Module.buffer)["tb_fun"]

መደምደሚያ

ስለዚህ, ስራው አሁንም አልተጠናቀቀም, ነገር ግን ይህንን የረጅም ጊዜ ግንባታ ለማጠናቀቅ በሚስጥር, እኔ ጠግቤያለሁ. እናም እስካሁን ያለኝን ለመለጠፍ ወሰንኩ። ኮዱ በቦታዎች አስፈሪ ነው, ምክንያቱም ሙከራ ነው, እና ምን መደረግ እንዳለበት አስቀድሞ ግልጽ አይደለም. ምናልባት፣ ከዚያ በአንዳንድ ተጨማሪ ዘመናዊ የ Qemu ስሪት ላይ መደበኛ የአቶሚክ ሰነዶችን መስጠት አለቦት። እስከዚያው ድረስ በብሎግ ቅርፀት ውስጥ በጊት ውስጥ ቅርንጫፍ አለ-በሩሲያኛ ዝርዝር መግለጫ ለእያንዳንዱ በሆነ መንገድ “ደረጃ” ተጨምሯል ። እንደ እውነቱ ከሆነ, ይህ ጽሑፍ በከፍተኛ ደረጃ የመደምደሚያውን እንደገና መተረክ ነው git log.

ሁሉንም መሞከር ይችላሉ እዚህ (ተጠንቀቅ ፣ ትራፊክ)።

አስቀድሞ የሚሰራው ነገር፡-

  • x86 ምናባዊ ፕሮሰሰር እየሰራ ነው።
  • ከማሽን ኮድ ወደ ጃቫስክሪፕት የጂአይቲ ኮድ ጄኔሬተር የሚሰራ ፕሮቶታይፕ አለ።
  • ሌሎች ባለ 32-ቢት የእንግዳ አርክቴክቸር ለመገንባት ባዶ አለ፡ አሁን ለኤምአይፒኤስ አርክቴክቸር በሊኑክስ ማስነሻ ደረጃ ላይ በአሳሹ ውስጥ ያለውን ማንጠልጠያ ማድነቅ ይችላሉ።

ሌላ ምን ማድረግ ይቻላል

  • ማስመሰልን ማፋጠን። በጂአይቲ ሁነታም ቢሆን ከቨርቹዋል x86 ቀርፋፋ ይመስላል (ነገር ግን ብዙ የተመሰለ ሃርድዌር እና አርክቴክቸር ያለው ሙሉ Qemu ሊኖር ይችላል)
  • መደበኛ በይነገጽ ይስሩ - ከእኔ የድር ገንቢ ፣ እውነቱን ለመናገር ፣ በጣም - በጣም ነው ፣ ስለሆነም ለአሁን የቻልኩትን መደበኛውን የኢምስክሪፕት ዛጎል እንደገና ቀርፀዋል።
  • ይበልጥ ውስብስብ የQemu ባህሪያትን ለማሄድ ይሞክሩ - አውታረ መረብ፣ VM ፍልሰት፣ ወዘተ።
  • የተዘመነ: ቀደም ሲል የቄሙ እና ሌሎች ፕሮጀክቶች በረኞች እንዳደረጉት ጥቂት እድገቶችዎን እና የሳንካ ሪፖርቶችን ለEmscripten ወደላይ መስጠት ያስፈልግዎታል። ለEmscripten ያደረጉትን አስተዋፅዖ በተዘዋዋሪ እንደ ተግባራቸው ለመጠቀም ስላስቻሉት እናመሰግናለን።

ምንጭ: hab.com

አስተያየት ያክሉ