SmidgeonSoft Logo

There and Back Again

JIT Thunk Layer - Reaching the Final Destination

Press F11 again:

Disassembly of THUNK at 0x071A2498
+ 0x71A2498: 85 C9                  TEST     ECX,ECX
  0x71A249A: 74 13                  JZ       0x71A24AF            ; (0x71A24AF); (*+0x15)
  0x71A249C: 8B 01                  MOV      EAX,DWORD PTR [ECX]
  0x71A249E: 3D 0C 00 F6 7F         CMP      EAX,0x7FF6000C
  0x71A24A3: 75 0A                  JNZ      0x71A24AF            ; (0x71A24AF); (*+0xC)
  0x71A24A5: 8B 41 08               MOV      EAX,DWORD PTR [ECX+0x8]
  0x71A24A8: FF 51 14               CALL     DWORD PTR [ECX+0x14]
  0x71A24AB: 85 C0                  TEST     EAX,EAX
  0x71A24AD: 75 06                  JNZ      0x71A24B5            ; (0x71A24B5); (*+0x8)
  0x71A24AF: 58                     POP      EAX                  ; <==Note#4 0x071A24A3(*-0xC), 0x071A249A(*-0x15)
  0x71A24B0: E9 B3 CB 03 00         JMP      0x71DF068
  0x71A24B5: E9 66 59 FC F8         JMP      0x167E20             ; <==0x071A24AD(*-0x8)

We are in another thunk!  After single-stepping and carefully noting the contents of the ECX and EAX registers, you will see that we will hit the statement, JNZ 0x71A24AF.  Single-stepping two more times will yield the following disassembly (Note #4 - the POP EAX removes the return address from the call statement at 0x6ED7B6B just like before):

Disassembly of JITTED Wilderland.WilderlandForm::LonelyMountain (06000005) at 0x071DF068
  ; Stack Size (in BYTES): 16 (0x00000010)
  ; Number of Parameters: 0
  ; Local Variables Size (in BYTES): 8 (0x00000008)
  ; Prologue Size (in BYTES): 22 (0x16)
  ; Standard Frame
> 0x71DF068: 55                     PUSH     EBP
  0x71DF069: 8B EC                  MOV      EBP,ESP
  0x71DF06B: 83 EC 08               SUB      ESP,0x8
  0x71DF06E: 56                     PUSH     ESI
  0x71DF06F: 68 70 7B ED 06         PUSH     0x6ED7B70
  0x71DF074: E8 FB 24 E2 08         CALL     0x10001574
  0x71DF079: 89 55 F8               MOV      DWORD PTR [EBP-0x8],EDX; VAR:0x8
  0x71DF07C: 8B F1                  MOV      ESI,ECX
  ; end of prologue
  ; IL_0000: ldarg.0
  ; IL_0001: ldfld Hobbiton_Button
  ; IL_0006: ldstr "Bilbo Lives!"
  ; IL_000B: callvirt  System.Windows.Forms.Control::set_Text()
  0x71DF07E: 8B 8E DC 00 00 00      MOV      ECX,DWORD PTR [ESI+0xDC]
  0x71DF084: 8B 15 B8 16 B7 05      MOV      EDX,DWORD PTR [0x5B716B8]
  0x71DF08A: 8B 01                  MOV      EAX,DWORD PTR [ECX]
  0x71DF08C: FF 90 E8 00 00 00      CALL     DWORD PTR [EAX+0xE8]
  ; IL_0010: ret
  0x71DF092: 90                     NOP
  0x71DF093: EB 00                  JMP      0x71DF095
  0x71DF095: 68 70 7B ED 06         PUSH     0x6ED7B70
  0x71DF09A: E8 D5 24 E2 08         CALL     0x10001574
  0x71DF09F: 5E                     POP      ESI
  0x71DF0A0: 8B E5                  MOV      ESP,EBP
  0x71DF0A2: 5D                     POP      EBP
  0x71DF0A3: C3                     RET

We are finally at our destination, Wilderland.WilderlandForm::LonelyMountain, which has just been JITted.  You can see this for yourself by selecting View/JIT Events in PEBrowse Interactive and examining the last entry in the list.  Step until you reach the return statement and execute one more statement by pressing F10 or F11.  The disassembly for Wilderland.WilderlandForm::Hobbiton_Button_Click is again displayed but positioned now after the first call statement we entered.  Just like Bilbo in his adventure, we have been "there and back again".  Letting the debugger continue at this point will demonstrate that the caption for the button is now changed to "Bilbo Lives!".

What happens if we wish to repeat the journey and press the "Bilbo Lives!" button again?  The debugger stops execution once again at the beginning of the Wilderland.WilderlandForm::Hobbiton_Button_Click method.  Stepping until the call statement we first examined a while back we will discover that the target of the call will be:

Disassembly of THUNK at 0x06ED7B6B
> 0x6ED7B6B: E8 28 A9 2C 00         CALL     0x71A2498

which is the same statement we saw above after returning from the JIT compiler call.  Stepping into this call and then single-stepping until we hit again the method, Wilderland.WilderlandForm::LonelyMountain, will prove that the code is not JITted again, but that we still will pass through one of the thunks we saw earlier.  So, just like Bilbo's continued possession of the One Ring affected him throughout his long life, our code continues to pass through one of the JIT compilers thunks.

Hopefully, this examination of the thunks your code passes through will inspire you to further investigate the mechanics of code being generated on the fly in the .NET environment.  My explanation just briefly touched on the single parameter, TheOneRing, but did not highlight its lifetime on the stack.  Also, we did not venture into the JIT compiler itself -- the more adventurous of you might want to follow this path but I will warn you:  It is a journey through Mirkwood and there are black spiders lurking!

prev page 1st page next page
Home | FAQ | News | Software | Documentation | SiteSearch | Licensing | Links | SiteIndex | AboutUs | ContactUs
Page best viewed at 1024x768.   Page last updated 2006-11-19.   This site is PIKT® powered.
Copyright © 1998-2006 Russell Osterlund.  All rights reserved.  SmidgeonSoft is a wholly-owned division of SmidgeonSoft, LLC.
Home FAQ News Software Documentation SiteSearch