Reputation: 394
I have 3 classes:
class Base { virtual foo() {...} }
class A : Base { virtual foo() override {...} }
class B : A { virtual bar() {...} /* introduce bar, but no foo override */ }
and I want to understand how this virtual function calls works under the hood.
If I call A a; a.foo()
- the compiler generates Call
instruction FF 10
which leads to near-jump instruction E9 01 02 03 04
. The last 4 bytes - relative offset from vtable-record to real function. It is pretty obvious and clear. But if I call B b; b.foo()
- the Call
instruction leads to another kind of Jump FF 25
. Visual Studio disassemblers displays it like this:
00007FFA2CAB1C85 FF 25 AD 76 21 01 jmp qword ptr [A::foo (07FFA2DCC9338h)]
I expected to get jump to 07FFA2DCC9338h
address, but instead, it jumps to 07FFA4AD05885h
(I suppose VS is lying with predicted address):
00007FFA4AD05885 E9 96 5D 01 00 jmp A::foo (07FFA4AD1B620h)
And this jump instuction (E9
) forwards me to the real function.
But I do not understand how FF 25
works. Unfortunately, my assembly knowledge is very poor, I read some documentation, it says about some "gates", and I do not understand it.
Is it possible to predict the jump location for far-jump(FF
) by having current instruction address(RIP
) and jump-arguments?
Upvotes: 1
Views: 468
Reputation: 394
Thanks @Jester, seems you are right.
E9
- jumps to specific relative code instruction.
FF 25
- calculates some specific relative location, read the memory from there, and use this memory as a pointer to next code instruction.
I just detected that
E9 ... jmp A::foo (07FFA4AD1B620h)
FF 25 ... jmp qword ptr [A::foo (07FFA2DCC9338h)]
qword ptr[...] says that I should derefer the value!
Upvotes: 2