äŒè©±ãã»ãšãã©çºçããªãã¡ã¢ãªé åããããŸãã ãã ãããã®é åã¯ããããã¢ããªã±ãŒã·ã§ã³ã®æäœã«ãããäž»èŠãªé åã§ãã æãäžè¬çã«äœ¿çšããããã®ã§ãã€ã³ã¹ã¿ã³ãå²ãåœãŠãšã¡ã¢ãªã®è§£æŸãéåžžã«å¶éãããŠããŸãã ãã®é åã¯ãã¹ããªãŒã ã¹ã¿ãã¯ããšåŒã°ããŸãã ããã«ããããžã®ãã€ã³ã¿ã¯ãã¹ããªãŒã ã®ã³ã³ããã¹ãã«å ¥ãããã»ããµã¬ãžã¹ã¿ã«ãã£ãŠæ¬è³ªçã«ãšã³ã³ãŒãããããããã¹ããªãŒã ã®å®è¡å ã§ã¹ããªãŒã ã¹ã¿ãã¯ã¯ç¬èªã®ãã®ã«ãªããŸãã ãªãå¿ èŠãªã®ã§ããïŒ DOSããã°ã©ã ããWindows 10äžã«ã€ã³ã¹ããŒã«ããã.NET FrameworkãŸã§ããã¹ãŠãæ©èœããåºç€ã«åºã¥ããŠãäœã¬ãã«æ§é ã®äžçã«çªå ¥ããŸãããã
ããã§ã¯ãåºæ¬çãªã³ãŒãã®äŸãåæããŸãããã
void Method1() { Method2(123); } void Method2(int arg) { // ... }
ãã®ã³ãŒãã§ã¯æ³šç®ãã¹ãããšã¯äœãèµ·ãããŸããããééãããŸãããããã®éãåæ§ã§ããã§ããéã詳ãã調ã¹ãŸãã
ã泚æ
Habréã§å ¬éãããŠããç« ã¯æŽæ°ãããŠãããããããããã§ã«å€ããã®ã§ãã ãã®ãããææ°ã®ããã¹ãã«ã€ããŠã¯å ã«æ»ããŠãã ããã
- CLR BookïŒ GitHubãç®æ¬¡
- CLR BookïŒ GitHubãç«
- ãªãªãŒã¹0.5.2ã®æžç±ãPDFïŒ GitHubãªãªãŒã¹
`Method1`ãany` Method2`ãåŒã³åºããšããã®ãããªåŒã³åºãã¯ãã¹ãŠïŒ.NETã ãã§ãªããä»ã®ãã©ãããã©ãŒã ã§ãïŒæ¬¡ã®æäœãå®è¡ããŸãã
- JITã«ãã£ãŠã³ã³ãã€ã«ãããã³ãŒããæåã«è¡ãããšã¯ãã¡ãœãããã©ã¡ãŒã¿ãŒãã¹ã¿ãã¯ã«ä¿åããããšã§ãïŒ3çªç®ããéå§ïŒã ãã®å Žåãæåã®2ã€ã¯ã¬ãžã¹ã¿ãä»ããŠéä¿¡ãããŸãã ã€ã³ã¹ã¿ã³ã¹ã¡ãœããã®æåã®ãã©ã¡ãŒã¿ãŒã¯ãã¡ãœãããåäœãããªããžã§ã¯ãã«ãã€ã³ã¿ãŒãæž¡ãããšãèŠããŠããããšãéèŠã§ãã ããªãã¡ ãã€ã³ã¿ãŒ `this`ã ãã®ããããããã®ïŒã»ãšãã©ãã¹ãŠã®ïŒå Žåãã¬ãžã¹ã¿ãŒã«ã¯ãã©ã¡ãŒã¿ãŒã1ã€ã ãæ®ããŸãã ãããŠãä»ã®çã®ããã«-ã¹ã¿ãã¯;
- 次ã«ãã³ã³ãã€ã©ã¯ãcallãã¡ãœãããåŒã³åºãåœä»€ãããã·ã¥ããã¡ãœããããã®ãªã¿ãŒã³ã¢ãã¬ã¹ãã¹ã¿ãã¯ã«ããã·ã¥ããŸãããcallãåœä»€ã«ç¶ãã¢ãã¬ã¹ã§ãã ãããã£ãŠãã¡ãœããã¯åŒã³åºãå ã®ã³ãŒããæ©èœãç¶ããããšãã§ããããã«ãã©ãã«æ»ãå¿ èŠãããããç¥ã£ãŠããŸãã
- ãã¹ãŠã®ãã©ã¡ãŒã¿ãŒãæž¡ãããã¡ãœãããåŒã³åºãããåŸãã¹ã¿ãã¯ã§å æãããŠãããã€ããã«ãŠã³ãããããšãæ°ã«ããããªãå Žåã¯ãã¡ãœãããçµäºããå Žåã«ã¹ã¿ãã¯ã埩å ããæ¹æ³ãäœããã®æ¹æ³ã§ç解ããå¿ èŠããããŸãã ãããè¡ãããã«ãEBPã¬ãžã¹ã¿ã®å€ãä¿åããŸããããã¯ãçŸåšã®ãã¬ãŒã ãã¬ãŒã ïŒã€ãŸããåŒã³åºãããç¹å®ã®ã¡ãœããã®æ å ±ãä¿åãããŠããã»ã¯ã·ã§ã³ïŒã®å é ãžã®ãã€ã³ã¿ãŒãåžžã«ä¿åããŸãã ãã®ã¬ãžã¹ã¿ã®å€ãååŒã³åºãã§ä¿åããããšã«ãããã¹ã¿ãã¯ãã¬ãŒã ã®åçŽã«æ¥ç¶ããããªã¹ããå®éã«äœæããŸãã ããããå®éã«ã¯ã¹ããŒã¹ãªãã§æ¬¡ã ãšã¯ã£ãããšç§»åããããšã«æ³šæããŠãã ããã ãã ãããã¬ãŒã ã®äžããã®ã¡ã¢ãªã®è§£æŸãç°¡çŽ åããã¢ããªã±ãŒã·ã§ã³ããããã°ã§ããããã«ããããã«ïŒãããã¬ã¯ãããã®ãã€ã³ã¿ã䜿çšããŠã¹ã¿ãã¯ãã¬ãŒã¹ã衚瀺ããŸãïŒãåäžãªã³ã¯ãªã¹ããäœæãããŸãã
- ã¡ãœãããåŒã³åºããšãã«æåŸã«è¡ãããšã¯ãããŒã«ã«å€æ°ã«ã¡ã¢ãªãå²ãåœãŠãããšã§ãã ã³ã³ãã€ã©ãŒã¯å¿ èŠãªéãäºåã«ç¥ã£ãŠãããããå¿ èŠãªãã€ãæ°ã ããã€ã³ã¿ãŒãã¹ã¿ãã¯ã®æäžéšïŒSP / ESP / RSPïŒã«ç§»åããŠããã«å®è¡ããŸãã
- æåŸã«ã5çªç®ã®æ®µéã§ãã¡ãœããã³ãŒããå®è¡ããã䟿å©ãªæäœãè¡ãããŸãã
- ã¡ãœãããçµäºãããšãã¹ã¿ãã¯ã®æäžéšãEBPïŒçŸåšã®ã¹ã¿ãã¯ãã¬ãŒã ã®å é ãä¿åãããŠããå ŽæïŒãã埩å ãããŸãã
- 次ã«ãæåŸã®ã¹ããã㯠`ret`ã¹ããŒãã¡ã³ããä»ããŠã¡ãœãããçµäºããããšã§ãã ããã¯ãã¹ã¿ãã¯ãããåŒã³åºããåœä»€ã«ãã£ãŠä»¥åã«æ éã«æ®ãããæ»ãã¢ãã¬ã¹ãåãå»ãããã®ã¢ãã¬ã¹ã«ç§»è¡ããŸãã
åãããã»ã¹ãç»åã§èŠãããšãã§ããŸãïŒ
ãŸããã¹ã¿ãã¯ã¯æäžäœã¢ãã¬ã¹ããæäžäœã¢ãã¬ã¹ãžãšãæé·ãããããšã«æ³šæããŠãã ããã å察æ¹åã«ã
ããããã¹ãŠèŠãŠã¿ããšã倧éšåã§ã¯ãªãå Žåãããã»ããµãè¡ã£ãŠãããã¹ãŠã®æäœã®å°ãªããšãååã¯ããã€ããŒãã§ã¯ãªãããã°ã©ã æ§é ã®ã¡ã³ããã³ã¹ã§ãããšããçµè«ã«ãããªãã¯æããæãã€ããŸãã ããªãã¡ ã¡ãœããåŒã³åºãã®ãµãŒãã¹ãåãçžäºã«å°ãèœåã®ãã§ãã¯ãäžè¬çãªããªãšãŒã·ã§ã³ã®ã³ã³ãã€ã«ãã€ã³ã¿ãŒãã§ã€ã¹ããŒãã«ã§ã®ã¡ãœããã®æ€çŽ¢...ç¹ã«ãææ°ã®ã³ãŒããã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠåäœããç¬èªã®ã¡ãœãããå®è¡ããå€ãã®å°ããªã¡ãœããã«åå²ãããŠããããšãæãåºãå Žå...ãŸããåºæ¬çãªåãšã€ã³ã¿ãŒãã§ã€ã¹ãŸãã¯çžç¶äººãžã®åãã£ã¹ããåæã«è¡ãããšããããããŸãã ãããã®ãã¹ãŠã®æ°ããæ¡ä»¶ã«ãããã€ã³ãã©ã¹ãã©ã¯ãã£ã³ãŒãã®ç¡é§ã«é¢ããçµè«ã¯ååã«æçããå¯èœæ§ããããŸãã ããã«ã€ããŠç§ã«èšããããšã¯ãJITãå«ãã³ã³ãã€ã©ã«ã¯ãããçç£çãªã³ãŒããäœæã§ããå€ãã®ãã¯ããã¯ããããŸãã å¯èœãªå Žå-ã¡ãœãããåŒã³åºã代ããã«ããã®æ¬äœå šäœãæ¿å ¥ãããå¯èœã§ããã°ãVSDã€ã³ã¿ãŒãã§ã€ã¹ã§ã¡ãœãããæ€çŽ¢ãã代ããã«ãçŽæ¥åŒã³åºããè¡ãããŸãã æ²ããããšã«ãã€ã³ãã©ã¹ãã©ã¯ãã£ã®è² è·ã枬å®ããã®ã¯éåžžã«å°é£ã§ããã€ã³ãã©ã¹ãã©ã¯ãã£ã³ãŒãã®äœæ¥å Žæã®ååŸã«JITterãŸãã¯ã³ã³ãã€ã©ãäœããã®ã¡ããªãã¯ãæ¿å ¥ããå¿ èŠããããŸãã ããªãã¡ ã¡ãœãããåŒã³åºãããåãããã³ã¹ã¿ãã¯ãã¬ãŒã ã®åæååŸã®ã¡ãœããå ã ã¡ãœãããçµäºããåãã¡ãœãããçµäºããåŸã ã³ã³ãã€ã«åãã³ã³ãã€ã«åŸã ãªã©ãªã©ã ããããæ²ããããšã«ã€ããŠè©±ãã®ã§ã¯ãªããåãåã£ãæ å ±ã䜿ã£ãŠäœãã§ãããã«ã€ããŠè©±ããŸãããã
äŸå€ã«ã€ããŠå°ã
ã¡ãœããã³ãŒãã®å éšãèŠããšãã¹ããªãŒã ã¹ã¿ãã¯ã§æ©èœããå¥ã®æ§é ã«æ°ä»ãã§ãããã èªåã§å€æããïŒ
void Method1() { try { Method2(123); } catch { // ... } } void Method2(int arg) { Method3(); } void Method3() { try { //... } catch { //... } }
`Method3`ããåŒã³åºãããã¡ãœããã®ããããã§äŸå€ãçºçããå Žåãå¶åŸ¡ã¯` Method3`ã¡ãœããã® `catch`ãããã¯ã«è¿ãããŸãã ããã«ãäŸå€ãåŠçãããªãå Žåããã®åŠçã¯ã¡ãœãã `Method1`ã§éå§ãããŸãã ããããäœãèµ·ãããªãå Žåã `Method3`ã¯äœæ¥ãå®äºããå¶åŸ¡ã¯ã¡ãœãã` Method2`ã«æž¡ãããäŸå€ãçºçããå¯èœæ§ããããŸãã ãã ããèªç¶ãªçç±ã«ããããMethod3ãã§ã¯ãªããMethod1ãã§åŠçãããŸãã ãã®ãããªäŸ¿å©ãªèªååã®åé¡ã¯ãäŸå€ãã³ãã©ãŒã®ãã§ãŒã³ã圢æããããŒã¿æ§é ãããããã宣èšãããŠããã¡ãœããã®ã¹ã¿ãã¯ãã¬ãŒã ã«ãããããšã§ãã äŸå€èªäœã«ã€ããŠã¯åå¥ã«èª¬æããŸãããããã§ã¯ã.NET Framework CLRãšCore CLRã®äŸå€ã¢ãã«ãç°ãªããšã ãèšããŸãã CoreCLRã¯ç°ãªããã©ãããã©ãŒã ã§ç°ãªãããã«åŒ·å¶ããããããäŸå€ã¢ãã«ã¯ç°ãªããç°ãªãå®è£ ã®PALïŒPlatform Adaption LayerïŒã¬ã€ã€ãŒãä»ããŠãã©ãããã©ãŒã ã«å¿ããŠè¡šç€ºãããŸãã 倧èŠæš¡ãª.NET Framework CLRã¯ãããå¿ èŠãšããŸãããWindowsãã©ãããã©ãŒã ã®ãšã³ã·ã¹ãã ã«ååšããé·å¹Žã«ããã£ãŠSEHïŒæ§é åäŸå€åŠçïŒãšåŒã°ããæåãªäŸå€åŠçã¡ã«ããºã ãååšããŠããŸããã ãã®ã¡ã«ããºã ã¯ãããŸããŸãªããã°ã©ãã³ã°èšèªã§èšè¿°ãããã¢ãžã¥ãŒã«éã®ãšã³ãããŒãšã³ãã®äŸå€åŠçãæäŸãããããã»ãŒãã¹ãŠã®ããã°ã©ãã³ã°èšèªïŒæçµã³ã³ãã€ã«çšïŒã§äœ¿çšãããŸãã 次ã®ããã«æ©èœããŸãã
- tryãããã¯ã«å ¥ããšãæåã®ãã£ãŒã«ããåã®äŸå€åŠçãããã¯ïŒããšãã°ãtry-catchãããåŒã³åºãã¡ãœããïŒããããã¯ã¿ã€ããäŸå€ã³ãŒããããã³ãã³ãã©ãŒã¢ãã¬ã¹ãæãæ§é ãã¹ã¿ãã¯ã«é 眮ãããŸãã
- ã¹ã¬ããã®TEBïŒã¹ã¬ããç°å¢ãããã¯ãæ¬è³ªçã«ã¯ã¹ã¬ããã®ã³ã³ããã¹ãïŒã§ã¯ãäŸå€ãã³ãã©ãŒã®ãã§ãŒã³ã®çŸåšã®ãããã®ã¢ãã¬ã¹ããäœæãããã®ã«å€æŽãããŸãã ãããã£ãŠããããã¯ããã§ãŒã³ã«è¿œå ããŸããã
- tryãçµäºãããšãéã®æäœãå®è¡ãããŸããå€ãé ç¹ãTEBã«æžã蟌ãŸããããããã³ãã©ãŒããã§ãŒã³ããåé€ãããŸãã
- äŸå€ãçºçããå Žåãé ç¹ãTEBããååŸããã次ã«ããã§ãŒã³å ã§ãã³ãã©ãŒãåŒã³åºãããäŸå€ããããã«ç¹ã«é©ããŠãããã©ããã確èªããŸãã ãã®å ŽåãåŠçãããã¯ãå®è¡ãããŸãïŒcatchãªã©ïŒã
- TEBã§ã¯ãäŸå€ãåŠçããã¡ãœããã®åã«ã¹ã¿ãã¯äžã«ããSEHæ§é ã®ã¢ãã¬ã¹ã埩å ãããŸãã
ã芧ã®ãšãããé£ããããšã§ã¯ãããŸããã ãã ãããããã®æ å ±ã¯ãã¹ãŠã¹ã¿ãã¯äžã«ããããŸãã
ã¹ã¬ããã¹ã¿ãã¯ã®äžå®å šæ§ã«ã€ããŠ
ã»ãã¥ãªãã£ã®åé¡ãšãçè«çã«çºçããå¯èœæ§ã®ããåé¡ã«ã€ããŠå°ãèããŠã¿ãŸãããã ãããè¡ãããã«ãåºæ¬çã«éåžžã®é åã§ããã¹ããªãŒã ã¹ã¿ãã¯ã®æ§é ãããäžåºŠèŠãŠã¿ãŸãããã ãã¬ãŒã ãæ§ç¯ãããã¡ã¢ãªç¯å²ã¯ã端ãã端ãŸã§æé·ããããã«ç·šæãããŸãã ããªãã¡ åŸã®ãã¬ãŒã ã¯åã®ã¢ãã¬ã¹ã«é 眮ãããŸãã ãŸãããã§ã«è¿°ã¹ãããã«ããã¬ãŒã ã¯åäžã®ãªã³ã¯ãªã¹ãã§æ¥ç¶ãããŠããŸãã ããã¯ããã¬ãŒã ãµã€ãºãåºå®ãããŠãããããããã¬ãŒã«ãã£ãŠãèªã¿åããããå¿ èŠãããããã§ãã åæã«ãããã»ããµã¯ãã¬ãŒã ãåºå¥ããŸãããå¿ èŠã«å¿ããŠãã©ã®ã¡ãœããã§ãã¡ã¢ãªé åå šäœãèªã¿åãããšãã§ããŸãã ãããŠãå®éã«ã¡ã¢ãªãå²ãåœãŠãããŠããã»ã¯ã·ã§ã³ã«åå²ãããŠããä»®æ³ã¡ã¢ãªã«ããããšãèæ ®ãããšãã¹ã¿ãã¯ã®ä»»æã®ã¢ãã¬ã¹ã§ç¹å¥ãªWinAPIé¢æ°ã䜿çšããŠããã® '' csharpã¢ãã¬ã¹ãé 眮ãããŠããå²ãåœãŠãããã¡ã¢ãªã®ç¯å²ãååŸã§ããŸã ããŠãåäžãªã³ã¯ãªã¹ããæŽçããããšã¯æè¡ã®åé¡ã§ãïŒ
// int x; // , MEMORY_BASIC_INFORMATION *stackData = new MEMORY_BASIC_INFORMATION(); VirtualQuery((void *)&x, stackData, sizeof(MEMORY_BASIC_INFORMATION));
ããã«ãããåŒã³åºããã¡ãœããã®ããŒã«ã«å€æ°ãšããŠã®ãã¹ãŠã®ããŒã¿ãååŸããã³å€æŽã§ããŸãã ã¢ããªã±ãŒã·ã§ã³ããµã³ãããã¯ã¹ãäœããã®æ¹æ³ã§æ§æããªãå Žåãã¢ããªã±ãŒã·ã§ã³ã®æ©èœãæ¡åŒµãããµãŒãããŒãã£ã©ã€ãã©ãªãåŒã³åºããããã¬ãŒã ã¯ãŒã¯å ã§ããµãŒãããŒãã£ã©ã€ãã©ãªã¯ãæäŸããAPIããããæå³ããªãå Žåã§ãããŒã¿ãçãããšãã§ããŸãã ãã®ææ³ã¯ãããªãã«ãšã£ãŠã¯ãšãã§ããªãããã«æãããããããŸããããã¹ã¿ãã¯ã«æ»ææš©éãèšå®ãããAppDomainã®ãããªçŸãããã®ããªãC / C ++ã®äžçã§ã¯ãããããããã³ã°ã¢ããªã±ãŒã·ã§ã³ããèŠãããæãå žåçãªãã®ã§ãã ããã ãã§ãªãããªãã¬ã¯ã·ã§ã³ãä»ããŠå¿ èŠãªã¿ã€ãã確èªããèªå® ã§ãã®æ§é ãç¹°ãè¿ããã¹ã¿ãã¯ãããªããžã§ã¯ããžã®ãªã³ã¯ããã©ã£ãŠãVMTã¢ãã¬ã¹ãç§ãã¡ã®ãã®ã«çœ®ãæããç¹å®ã®ã€ã³ã¹ã¿ã³ã¹ã®ãã¹ãŠã®äœæ¥ãç§ãã¡ã«ãªãã€ã¬ã¯ãããŸãã ãšããã§ãSEHã¯ã¢ããªã±ãŒã·ã§ã³ã®ãããã³ã°ã«ã䜿çšãããŠããŸãã ãŸããäŸå€ãã³ãã©ã®ã¢ãã¬ã¹ãå€æŽããŠãOSã«æªæã®ããã³ãŒããå®è¡ãããããšãã§ããŸãã ããããããããã¹ãŠã®çµè«ã¯éåžžã«ç°¡åã§ããã¢ããªã±ãŒã·ã§ã³ã®æ©èœãæ¡åŒµããã©ã€ãã©ãªã䜿çšããå Žåã¯ãåžžã«ãµã³ãããã¯ã¹ãæ§æããŠãã ããã ãã¡ãããããããçš®é¡ã®ãã©ã°ã€ã³ãã¢ããªã³ããã®ä»ã®æ¡åŒµæ©èœãæå³ããŸãã
çŽ æŽãããäŸïŒã¹ããªãŒã ã¯ããŒãã³ã°
èªãã å 容ãã¹ãŠã现éšãŸã§èŠããã«ã¯ãããã€ãã®åŽé¢ãããããã¯ãåãäžãããšããåé¡ã«åãçµãå¿ èŠããããŸãã ã¹ããªãŒã ã¹ã¿ãã¯ã«å¯ŸããŠã©ã®ãããªäŸãæ§ç¯ã§ããã®ã§ããããã å¥ã®ã¡ãœãããåŒã³åºããŸããïŒ ããžãã¯...ãã¡ããããã§ã¯ãããŸããã1æ¥ã«äœåºŠããããè¡ããŸãã 代ããã«ãå®è¡ã®ãããŒãè€è£œããŸãã ããªãã¡ 1ã€ã®ã¹ã¬ããã®ä»£ããã«ç¹å®ã®ã¡ãœãããåŒã³åºããåŸã2ã€ã®ã¹ã¬ãããäœæã§ããããã«ããŸãããïŒç§ãã¡ã®ã¹ã¬ãããšæ°ããã¹ã¬ããã®2ã€ã§ãããã¯ããŒã³ã¡ãœããã®åŒã³åºãæç¹ããã³ãŒããå®è¡ãç¶ããŸãã ãããŠã次ã®ããã«ãªããŸãã
void MakeFork() { // : // var sameLocalVariable = 123; var sync = new object(); // var stopwatch = Stopwatch.StartNew(); // var forked = Fork.CloneThread(); // . // forked = true , false lock(sync) { Console.WriteLine("in {0} thread: {1}, local value: {2}, time to enter = {3} ms", forked ? "forked" : "parent", Thread.CurrentThread.ManagedThreadId, sameLocalVariable, stopwatch.ElapsedMilliseconds); } // , // MakeFork(), .. , // . } // : // in forked thread: 2, local value: 123, time to enter = 73 ms // in parent thread: 1, local value: 123, time to enter = 77 ms
åæããã³ã³ã»ããã¯èå³æ·±ãã§ãã ãã¡ããããã®ãããªã¢ã¯ã·ã§ã³ã®é©åæ§ã«ã€ããŠã¯å€ãã®è°è«ããããŸããããã®äŸã®ã¿ã¹ã¯ã¯ããã®ããŒã¿æ§é ã®æäœã®ç解ã«åŒŸäžžã眮ãããšã§ãã ã¯ããŒã³äœææ¹æ³ ãã®è³ªåã«çããã«ã¯ãå¥ã®è³ªåã«çããå¿ èŠããããŸããäžè¬çã«ãããŒã決å®ãããã®ã¯äœã§ããïŒ ãŸãããããŒã¯æ¬¡ã®ããŒã¿æ§é ãšé åã«ãã£ãŠæ±ºå®ãããŸãã
- ããã»ããµã¬ãžã¹ã¿ã®ã»ããã ãã¹ãŠã®ã¬ãžã¹ã¿ã¯ãåœä»€å®è¡ã¹ããªãŒã ã®ç¶æ ã決å®ããŸããçŸåšã®å®è¡åœä»€ã®ã¢ãã¬ã¹ãããã¹ããªãŒã ã¹ã¿ãã¯ã®ã¢ãã¬ã¹ããã³ãããåäœããããŒã¿ãŸã§ã
- [ã¹ã¬ããç°å¢ãããã¯]ïŒhttps://en.wikipedia.org/wiki/Win32_Thread_Information_BlockïŒãŸãã¯TIB / TEBãäŸå€ãã³ãã©ãŒã®ã¢ãã¬ã¹ãå«ãã·ã¹ãã æ å ±ãã¹ã¬ããããšã«ä¿åããŸãã
- ã¬ãžã¹ã¿SSïŒESPã«ãã£ãŠã¢ãã¬ã¹ã決å®ãããã¹ããªãŒã ã®ã¹ã¿ãã¯ã
- ã¹ããªãŒã ã®ãã©ãããã©ãŒã ã³ã³ããã¹ããã¹ããªãŒã ã®ããŒã«ã«ããŒã¿ãå«ã¿ãŸãïŒãªã³ã¯ã¯TIBããååŸãããŸãïŒ
ãŸãã確ãã«ç§ãã¡ãç¥ããªããããããªãäœãã ã¯ããããšãã°ããã¹ãŠãç¥ãå¿ èŠã¯ãããŸããããã®ã³ãŒãã¯ç£æ¥çšã«ã¯ãªããŸãããããããã¯ãç解ããã®ã«åœ¹ç«ã€åªããäŸãšããŠåœ¹ç«ã¡ãŸãã ãããã£ãŠã圌ã¯ãã¹ãŠãèæ ®ãããæãåºæ¬çãªãã®ã ããèæ ®ããŸãã ãããŠããããåºæ¬çãªåœ¢ã§æ©èœããããã«ã¯ãã¬ãžã¹ã¿ã®ã»ãããæ°ããã¹ããªãŒã ã«ã³ããŒããå¿ èŠããããŸãïŒSSã¯ESPãä¿®æ£ããããšã§ãã¹ã¿ãã¯ãæ°ãããªãããïŒããŸããã¹ã¿ãã¯èªäœãç·šéããŠãå¿ èŠãªãã®ãæ£ç¢ºã«å«ãŸããããã«ããŸãã
ã ããã ãããŒã¹ã¿ãã¯ããã©ã®ã¡ãœãããåŒã³åºãããã©ã®ããŒã¿ãæäœããããæ¬è³ªçã«æ±ºå®ããå Žåããããã®æ§é ãå€æŽããããšã§ãã¡ãœããã®ããŒã«ã«å€æ°ãã¡ãœãããã¹ã¿ãã¯ããåæããæ¹æ³ãå€æŽããããã¡ãœãããå¥ã®ã¡ãœããã«å€æŽããããè¿œå ãããã§ããããšãããããŸããã§ãŒã³å ã®ä»»æã®å Žæã ããŠãããã«æ±ºããŸããã 次ã«ãããã€ãã®æ¬äŒŒã³ãŒããèŠãŠã¿ãŸãããã
void RootMethod() { MakeFork(); }
MakeForkïŒïŒãåŒã³åºããããšãããã¬ãŒã¹ã®ã¹ã¿ãã¯ã«é¢ããŠäœãæåŸ ããŸããïŒ èŠªã¹ã¬ããã®ãã¹ãŠãå€æŽãããã«æ®ããåãã¹ã¬ããããŒã«ããïŒé床ã®ããã«ïŒ
MakeFork
ããããŒã«ã«å€æ°ãšãšãã«
MakeFork
ã¡ãœããã®åŒã³åºããã·ãã¥ã¬ãŒãããã³ãŒãã¯ã¡ãœããã®æåããã§ã¯ãªããåŒã³åºãã«ç¶ããã€ã³ãããå®è¡ãããŸã
CloneThread
ã ããªãã¡ ãã¡ã³ã¿ãžãŒã®ã¹ã¿ãã¯ãã¬ãŒã¹ã¯æ¬¡ã®ããã«ãªããŸãã
// Parent Thread RootMethod -> MakeFork // Child Thread ThreadPool -> MakeFork
æåã¯äœããããŸããïŒ ã¹ããªãŒã ããããŸãã ãŸããããã§ã³ãŒããå®è¡ããŠãæ°ããã¹ã¬ãããäœæããããã¹ã¬ããããŒã«ã§ã¿ã¹ã¯ãã¹ã±ãžã¥ãŒã«ãããããããšãã§ããŸãã ãŸãããã¹ããããåŒã³åºãã«é¢ããæ å ±ã¯åŒã³åºãã¹ã¿ãã¯ã«æ ŒçŽãããå¿ èŠã«å¿ããŠæäœã§ããããšãç解ããŠããŸãïŒããšãã°ãC ++ / CLIã䜿çšïŒã ããã«ãèŠåã«åŸã£ãŠãã¹ã¿ãã¯ã®æäžéšã«ããretåœä»€ã®ãªã¿ãŒã³ã¢ãã¬ã¹ãEBPã¬ãžã¹ã¿ã®å€ãå ¥åããããŒã«ã«ã«ã¹ããŒã¹ãå²ãåœãŠãïŒå¿ èŠãªå ŽåïŒããšã«ãããã¡ãœããåŒã³åºããã·ãã¥ã¬ãŒãã§ããŸãã CïŒããã¹ããªãŒã ã¹ã¿ãã¯ã«æåã§æžã蟌ãããšã¯å¯èœã§ãããããããéåžžã«æ éã«äœ¿çšããããã«ã¬ãžã¹ã¿ãå¿ èŠã«ãªããããC ++ã®ãŸãŸã«ããŠããããšã¯ã§ããŸããã ããã§ç§ã®äººçã§åããŠïŒå人çã«ã¯ïŒCLI / C ++ãå©ãã«ãªããæ··åã³ãŒããæžãããšãã§ããŸãïŒåœä»€ã®äžéšã¯.NETã«ãããäžéšã¯C ++ã«ãããæã«ã¯ã¢ã»ã³ãã©ã¬ãã«ã«ãããªããŸãã ãŸãã«å¿ èŠãªãã®ã
ã³ãŒããMakeForkãåŒã³åºããšãã¹ã¬ããã¹ã¿ãã¯ã¯ã©ã®ããã«ãªããŸããïŒMakeForkã¯CloneThreadãåŒã³åºããCloneThreadã¯ã¢ã³ãããŒãžCLI / C ++ã®äžçã«å ¥ããã¯ããŒã³ã¡ãœããïŒå®è£ èªäœïŒãåŒã³åºããŸã-ããã«ïŒ ã¹ããŒã ãèŠãŠã¿ãŸãããïŒã¹ã¿ãã¯ãæäžäœã¢ãã¬ã¹ããæäžäœã¢ãã¬ã¹ã«æé·ããããšãæãåºããŸããå³ããå·ŠãžïŒã
ã·ãŒãå šäœãã¹ããŒã ããã¹ããŒã ã«ãã©ãã°ããªãããã«ããããã«ãäžèŠãªãã®ãç Žæ£ããŠåçŽåããŸãã
ã¹ã¬ãããäœæããããã¹ã¬ããããŒã«ããæºåãæŽã£ãã¹ã¬ãããååŸãããšãã¹ããŒã ã«ãŸã åæåãããŠããªãå¥ã®ã¹ã¿ãã¯ã衚瀺ãããŸãã
ããã§ã®ã¿ã¹ã¯ã¯ãæ°ããã¹ã¬ããã§
Fork.CloneThread()
ã¡ãœããã®éå§ãã·ãã¥ã¬ãŒãããããšã§ãã ãããè¡ãã«ã¯ãã¹ã¬ããã¹ã¿ãã¯ã®æåŸã«äžé£ã®ãã¬ãŒã ãè¿œå ããå¿ èŠããããŸãïŒThreadPoolã«æž¡ãããããªã²ãŒããã
Fork.CloneThread()
ãåŒã³åºãããããããC ++ãããŒãžã©ãããŒã³ãŒãã®ã©ãããŒãä»ããŠCLI / C ++ã¡ãœãããåŒã³åºãããŸããã ãããè¡ãã«ã¯ãã¹ã¿ãã¯ã®å¿ èŠãªã»ã¯ã·ã§ã³ãã¢ã¬ã€ã«ã³ããŒããã ãã§ãïŒãã¬ãŒã ãã§ãŒã³ã®æ§ç¯ãæäŸããEBPã¬ãžã¹ã¿ã®ã³ããŒã¯ãåŸæããã»ã¯ã·ã§ã³ããå€ãã»ã¯ã·ã§ã³ã«ãèŠãããããšã«æ³šæããŠãã ããïŒã
ããã«ãåã®å±±ã«åŸæããã»ã¯ã·ã§ã³ã®ã³ããŒæäœåŸã®ã¹ã¿ãã¯ã®æŽåæ§ã確ä¿ããããã«ããEBPããã£ãŒã«ãã®ã¢ãã¬ã¹ãæ°ããå Žæã«ããã¢ãã¬ã¹ãäºåã«èšç®ããããã«ã³ããŒäžã§çŽæ¥ä¿®æ£ããŸãã
æåŸã®ã¹ãããã§ã¯ãéåžžã«æ éã«ãæå°éã®ã¬ãžã¹ã¿ã䜿çšããŠãåã¹ããªãŒã ã®ã¹ã¿ãã¯ã®æåŸã«é åãã³ããŒãããã®åŸãESPããã³EBPã¬ãžã¹ã¿ãæ°ããå Žæã«ã·ããããŸãã ã¹ã¿ãã¯ã®èŠ³ç¹ãããããããã¹ãŠã®ã¡ãœããã®åŒã³åºããã·ãã¥ã¬ãŒãããŸããã
ãããããŸã ã³ãŒãã«é¢ããŠã¯ããã§ã¯ãããŸããã ã³ãŒãã®èŠ³ç¹ãããäœæããã°ããã®ã¡ãœããã«å ¥ãå¿ èŠããããŸãã æãç°¡åãªæ¹æ³ã¯ãã¡ãœããããæãåºãæ¹æ³ãåçŽã«ã·ãã¥ã¬ãŒãããããšã§ãïŒ
ESP
ã
EBP
ã«åŸ©å ãã
EBP
ã§ãã€ã³ããããã®ãå ¥ããŠ
ret
ã¹ããŒãã¡ã³ããåŒã³åºããã¹ããªãŒã ã¯ããŒãã³ã°ã®C ++ã¡ãœãããšåŒã°ããã¯ãã®C ++ã¡ãœããããã®åºå£ãéå§ããŸãã
MakeFork()
å¶åŸ¡ãè¿ããŸãããåã¹ã¬ããå ã«ãããŸãã ãã¯ããã¯ã¯ããŸããããŸããã
ããã§ã¯ãã³ãŒããèŠãŠã¿ãŸãããã æåã«è¡ãããšã¯ãCLI / C ++ã³ãŒãã.NETã¹ããªãŒã ãäœæããæ©èœã§ãã ãããè¡ãã«ã¯ã.NETã§äœæããå¿ èŠããããŸãã
extern "C" __declspec(dllexport) void __stdcall MakeManagedThread(AdvancedThreading_Unmanaged *helper, StackInfo *stackCopy) { AdvancedThreading::Fork::MakeThread(helper, stackCopy); }
ãã©ã¡ãŒã¿ã®çš®é¡ã«ã€ããŠã¯ãŸã 泚æãæã£ãŠããŸããã ãããã¯ãã¹ã¿ãã¯ã®ã©ã®éšåã芪ã¹ããªãŒã ããåã¹ããªãŒã ã«æç»ããå¿ èŠããããã«é¢ããæ å ±ã転éããããã«å¿ èŠã§ãã ã¹ã¬ããäœæã¡ãœããã¯ãããªã²ãŒãã§ã¢ã³ãããŒãžã¡ãœãããžã®åŒã³åºããã©ããããããŒã¿ã転éããã¹ã¬ããããŒã«ã«ããåŠçã®ããã«ããªã²ãŒãããã¥ãŒã«å ¥ããŸãã
[MethodImpl(MethodImplOptions::NoInlining | MethodImplOptions::NoOptimization | MethodImplOptions::PreserveSig)] static void MakeThread(AdvancedThreading_Unmanaged *helper, StackInfo *stackCopy) { ForkData^ data = gcnew ForkData(); data->helper = helper; data->info = stackCopy; ThreadPool::QueueUserWorkItem(gcnew WaitCallback(&InForkedThread), data); } [MethodImpl(MethodImplOptions::NoInlining | MethodImplOptions::NoOptimization | MethodImplOptions::PreserveSig)] static void InForkedThread(Object^ state) { ForkData^ data = (ForkData^)state; data->helper->InForkedThread(data->info); }
ãããŠæåŸã«ãã¯ããŒã³äœææ¹æ³èªäœïŒãŸãã¯ã.NETéšåïŒïŒ
[MethodImpl(MethodImplOptions::NoInlining | MethodImplOptions::NoOptimization | MethodImplOptions::PreserveSig)] static bool CloneThread() { ManualResetEvent^ resetEvent = gcnew ManualResetEvent(false); AdvancedThreading_Unmanaged *helper = new AdvancedThreading_Unmanaged(); int somevalue; // * helper->stacktop = (int)(int *)&somevalue; int forked = helper->ForkImpl(); if (!forked) { resetEvent->WaitOne(); } else { resetEvent->Set(); } return forked; }
ãã®ã¡ãœãããã¹ã¿ãã¯ã®ãã¬ãŒã ãã§ãŒã³ã®ã©ãã«ããããç解ããããã«ãèªåçšã«ã¹ã¿ãã¯å€æ°ïŒ*ïŒã®ã¢ãã¬ã¹ãä¿åããŸãã ãã®ã¢ãã¬ã¹ã¯ã以äžã§èª¬æããã¯ããŒã³äœææ¹æ³ã§äœ¿çšããŸãã ãŸããäœãåé¡ãªã®ããç解ã§ããããã«ãã¹ã¿ãã¯ã³ããŒã«é¢ããæ å ±ãä¿åããããã«å¿ èŠãªæ§é ã®ã³ãŒãã瀺ããŸãã
public class StackInfo { public: // int EAX, EBX, ECX, EDX; int EDI, ESI; int ESP; int EBP; int EIP; short CS; // void *frame; // int size; // , // int origStackStart, origStackSize; };
: . â â , , .
. ããªãã¡ . ããã§ã¯å§ããŸãããã
Fork.CloneThread()
, ( debugger assistants). .NET : C++ : .
int AdvancedThreading_Unmanaged::ForkImpl() { StackInfo copy; StackInfo* info;
, - . , `goto` `CloneThread` . « » `JmpPointOnMethodsChainCallEmulation` : « » 0.
// Save ALL registers _asm { mov copy.EAX, EAX mov copy.EBX, EBX mov copy.ECX, ECX mov copy.EDX, EBX mov copy.EDI, EDI mov copy.ESI, ESI mov copy.EBP, EBP mov copy.ESP, ESP // Save CS:EIP for far jmp mov copy.CS, CS mov copy.EIP, offset JmpPointOnMethodsChainCallEmulation // Save mark for this method, from what place it was called push 0 }
, `JmpPointOnMethodsChainCallEmulation` : `0`? , : `NonClonned`. `0`, `1`, «» , `1` goto ( goto ). `CloneThread` , .
JmpPointOnMethodsChainCallEmulation: _asm { pop EAX cmp EAX, 0 je NonClonned pop EBP mov EAX, 1 ret } NonClonned:
, , . , . EBP: «Next» . , , . , . managed
CloneThread
: . , .
int *curptr = (int *)copy.EBP; int frames = 0; // // Calculate frames count between current call and Fork.CloneTherad() call // while ((int)curptr < stacktop) { curptr = (int*)*curptr; frames++; }
managed
CloneThread
,
CloneThread
MakeFork
.
MakeFork
( ), :
*(int *)curptr
. .
// // We need to copy stack part from our method to user code method including its locals in stack // int localsStart = copy.EBP; // our EBP points to EBP value for parent method + saved ESI, EDI int localsEnd = *(int *)curptr; // points to end of user's method's locals (additional leave) byte *arr = new byte[localsEnd - localsStart]; memcpy(arr, (void*)localsStart, localsEnd - localsStart);
, â , . , . , :
// Get information about stack pages MEMORY_BASIC_INFORMATION *stackData = new MEMORY_BASIC_INFORMATION(); VirtualQuery((void *)copy.EBP, stackData, sizeof(MEMORY_BASIC_INFORMATION)); // fill StackInfo structure info = new StackInfo(copy); info->origStackStart = (int)stackData->BaseAddress; info->origStackSize = (int)stackData->RegionSize; info->frame = arr; info->size = (localsEnd - localsStart); // call managed ThreadPool.QueueUserWorkitem to make fork MakeManagedThread(this, info); return 0; }
: . , , . , MakeFork , , , .
void AdvancedThreading_Unmanaged::InForkedThread(StackInfo * stackCopy) { StackInfo copy;
MakeFork
. .
SS:ESP
.
short CS_EIP[3]; // Save original registers to restore __asm pushad // safe copy w-out changing registers for(int i = 0; i < sizeof(StackInfo); i++) ((byte *)©)[i] = ((byte *)stackCopy)[i]; // Setup FWORD for far jmp *(int*)CS_EIP = copy.EIP; CS_EIP[2] = copy.CS;
â
EBP
, . , .
// calculate ranges int beg = (int)copy.frame; int size = copy.size; int baseFrom = (int) copy.origStackStart; int baseTo = baseFrom + (int)copy.origStackSize; int ESPr; __asm mov ESPr, ESP // target = EBP[ - locals - EBP - ret - whole stack frames copy] int targetToCopy = ESPr - 8 - size; // offset between parent stack and current stack; int delta_to_target = (int)targetToCopy - (int)copy.EBP; // offset between parent stack start and its copy; int delta_to_copy = (int)copy.frame - (int)copy.EBP;
.
// In stack copy we have many saved EPBs, which where actually one-way linked list. // we need to fix copy to make these pointers correct for our thread's stack. int ebp_cur = beg; while(true) { int val = *(int*)ebp_cur; if(baseFrom <= val && val < baseTo) { int localOffset = val + delta_to_copy; *(int *)ebp_cur += delta_to_target; ebp_cur = localOffset; } else break; }
, . . , . . .
CHECKREF(EAX); CHECKREF(EBX); CHECKREF(ECX); CHECKREF(EDX); CHECKREF(ESI); CHECKREF(EDI);
, . ,
MakeFork
(
return
). .
MakeFork
.
RestorePointAfterClonnedExited
,
call
,
EBP
, . `push` , `MakeFork` . !
// prepare for __asm nret __asm push offset RestorePointAfterClonnedExited __asm push EBP for(int i = (size >> 2) - 1; i >= 0; i--) { int val = ((int *)beg)[i]; __asm push val; };
, .
// restore registers, push 1 for Fork() and jmp _asm { push copy.EAX push copy.EBX push copy.ECX push copy.EDX push copy.ESI push copy.EDI pop EDI pop ESI pop EDX pop ECX pop EBX pop EAX
0
0
.
1
jmp
ForkImpl
. , . ,
ForkImpl
MakeFork
, ,
RestorePointAfterClonnedExited
, .. `MakeFork` . « TheadPool», , .
push 1 jmp fword ptr CS_EIP } RestorePointAfterClonnedExited: // Restore original registers __asm popad return; }
? â :
:
, MakeFork . â .
, 4 . . , . . ? 4 . , , . , : .. 2 . , : 1 , 1 .
, : ESP . , , , StackOverflowException: ( ), , Guard Page, , StackOverflow , .NET, StackOverflowException .NET .
, : . . ããªãã¡ API API - . .
- CLR Book: GitHub
- 0.5.0 , PDF: GitHub Release