tags:

views:

449

answers:

3

I was reading some articles on net regarding Vtable thunks and I read somewhere that thunks can be used to hook /chain procedures calls.

Is it achievable?

Does anyone know how that works , also I am not able to find good resource explaining thunks. Any suggestions for that?

A: 

There are some description and links in Wikipedia.

Kirill V. Lyadvinsky
A: 

Well, you read that thunks are a solution, and now you are looking for a problem to solve?

Thunks, generally, are short "forwarding" functions that provide minor - usually hardcoded - adjustments.

VTable chunks are explained very well in wikipedia at the moment. They use the common pattern: generate a small function to avoid calculation / extra work at run time.

Other places I've seen / used thunks:

Associating a window handle with a window object: for each window to be subclassed, a small thunk is generated on the fly that calls the window procedure with the object reference, the thunk is then used as window procedure.

Delay Loading DLLs: the thunk makes sure the DLL is loaded the first time any function is called.

Trapping COM interface calls: the thunks provide an injection point for diagnostics, and jump to the actual method.

peterchen
Could you please point me the resources /links that can show some example doing all these with thunks if there are any?
Alien01
For window procedures see the section on ATL at http://web.archive.org/web/20051125022758/www.rpi.edu/~pudeyo/articles/wndproc/ (ATL uses thunks to accomplish this.)
Tadmas
+3  A: 

Implementing a raw thunk in the style of v-table thunks is a last resort. Whatever you need to accomplish can most likely be achieved with a wrapper function, and it will be much less painful.

In general, a thunk does the following:

  1. Fix up the input parameters (e.g., convert to a different format)
  2. Call the real implementation
  3. Clean up step 1 / fix the output parameters

To see an example of how it works, let's turn to our good friend Raymond Chen and his discussion of adjuster thunks:

http://blogs.msdn.com/oldnewthing/archive/2004/02/06/68695.aspx

The thunk he used was as follows:

[thunk]:CSample::QueryInterface`adjustor{4}':
  sub     DWORD PTR [esp+4], 4 ; this -= sizeof(lpVtbl)
  jmp     CSample::QueryInterface

As he describes, you have a class that implements the same methods through multiple interfaces, so it has multiple v-tables. (If you don't know COM, all you need to know is that it works with v-tables directly, so a pointer to a specific interface must contain function pointers to all the methods of that interface in order.)

If you implement two interfaces with different methods in a particular slot, you need multiple v-tables. But, you only write the overlapping methods once, so that method needs to be able to work with both "this" pointers. To do that, the compiler generates a method that does the fixup necessary and calls the original implementation.

So, this thunk does the following steps:

  1. Fix up the input parameters, namely the hidden "this" pointer, in the first line.
  2. Call the real implementation in the second line.
  3. Cleanup: none required (see below)

This is where the jmp instruction comes in. Normally, if you were to call the function using call, it would return to you, and you'd have to ret back to your caller. Since there is no cleanup to do, the compiler does an optimization where it moves execution straight to the real implementation and let's the real implementation's return statement return to your caller. This is only an optimization, not a fundamental part of thunking. For example, 16/32-bit thunks will convert the input / output parameters between 16 and 32 bits as necessary, so it can't skip the cleanup step; it has to call, not jmp.

The moral of the story is: if you need to do something, such as the jmp optimization, that you can't write directly in C++ or your other high level language of choice, go ahead and write an assembly language thunk. Otherwise, just write a wrapper and be done with it.

Honestly, it sounds like you're asking for the performance optimization, and most of the time (1) the compiler is better at optimizing than we think and (2) it's not going to give you as big of an improvement as you think.

Tadmas