24

Debugging some code in Visual Studio 2008 (C++), I noticed that the address in my function pointer variable is not the actual address of the function itself. This is an extern "C" function.

int main() {
   void (*printaddr)(const char *) = &print; // debug shows printaddr == 0x013C1429

}

Address: 0x013C4F10
void print() {
  ...
}

The disassembly of taking the function address is:

   void (*printaddr)(const char *) = &print;
013C7465 C7 45 BC 29 14 3C 01 mov         dword ptr [printaddr],offset print (13C1429h) 

EDIT: I viewed the code at address 013C4F10 and the compiler is apparently inserting a "jmp" instruction at that address.

013C4F10 E9 C7 3F 00 00   jmp         print (013C1429h) 

There is actually a whole jump table of every method in the .exe.

Can someone expound on why it does this? Is it a debugging "feature" ?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
codenheim
  • 20,467
  • 1
  • 59
  • 80
  • 1
    Hmm, what is telling you the address of `print` is `0x013C4F10` ? Looking at the disassembly it seems like the address of print is indeed `0x013C1429` and that's the value being stored in `printaddr` – Martin Mar 21 '10 at 00:55
  • The disassembly in Visual Studio shows print at address 0x013C4F10 – codenheim Mar 21 '10 at 01:09
  • @Martin: When I switch to release mode the jump table goes away and the address is indeed the actual function address. – codenheim Mar 21 '10 at 01:46
  • There's a book called 'Linkers and Loaders' (http://www.amazon.com/Linkers-Kaufmann-Software-Engineering-Programming/dp/1558604960) which explains about this. It's a while since I read it, and the MS environment wasn't of primary interest - but there is indeed a jump table which allows for dynamic loading of shared libraries. – Jonathan Leffler Mar 21 '10 at 06:34
  • @mrjoltcola: I upvoted @Martin's original comment because it asked a sensible question about information that was lacking in your question. – Troubadour Mar 21 '10 at 13:28
  • @Jonathan: I happen to have that book. I will check it. Thanks. @Troubadour: The information wasn't lacking, it just wasn't in the format that perhaps you trusted. The address I gave was a cut-and-paste from the disassembly session, so you had to trust me. :) – codenheim Mar 21 '10 at 18:39
  • If the problem is 'incremental linking', I don't think the book covers that. OTOH, I am not convinced the problem is incremental linking - but I've not gone and read the referenced chunk of the MSDN. – Jonathan Leffler Mar 21 '10 at 23:31
  • it's probably to do with the interaction between the linker, and the need to call code in DLLs This article talks about it, I'm not 100% sure how it applied to your example but it seems like it might help you understand http://msdn.microsoft.com/en-us/library/aa271769(VS.60).aspx – jcoder Mar 21 '10 at 13:20

3 Answers3

21

That is caused by 'Incremental Linking'. If you disable that in your compiler/linker settings the jumps will go away.

http://msdn.microsoft.com/en-us/library/4khtbfyf(VS.80).aspx

RaptorFactor
  • 2,810
  • 1
  • 29
  • 36
7

I'm going to hazard a guess here, but it's possibly to enable Edit-and-Continue.

Say you need to recompile that function, you only need to change the indirection table, not all callers. That would dramatically reduce the amount of work to do when the Edit-and-Continue feature is being exercised.

Bahbar
  • 17,760
  • 43
  • 62
  • sounds reasonable, but then the function pointer `printaddr` would still point to the old (non-edited) `print` function... perhaps there's a bug in the debugger? :) – Martin Mar 21 '10 at 13:51
  • @Martin: no, the function pointer always points to the jump table, so that when edit and continue recompiles the function, only the jump table gets modified. The function pointer value does _not_ change, ever. That's the beauty of it, really. Imagine your code stores a function pointer somewhere in memory. Edit and Continue has no way to update that. But by pointing it to a jump table, modifying the jump table catches all the potential usages of the function at once. – Bahbar Mar 21 '10 at 14:50
  • that's not what the disassembly above looks like since the pointer isn't set to point at the jump table but directly to the function instead – Martin Mar 21 '10 at 16:22
  • @Martin: Doh. I guess I wanted to believe too much. Thanks for pointing it out. – Bahbar Mar 21 '10 at 19:28
2

The compiler is inserting a "jmp" instruction at that address to the real method.

013C4F10 E9 C7 3F 00 00   jmp         print (013C1429h)

There is actually a whole jump table of every method in the .exe.

It is a Debugging feature. When I switch to release mode the jump table goes away and the address is indeed the actual function address.

codenheim
  • 20,467
  • 1
  • 59
  • 80