Во-первых, у типов классов есть vtable. Экземпляры этого типа имеют указатель на vtable.
Это означает, что если содержимое vtable изменяется для типа, все экземпляры этого типа
пострадавшие. Но конкретный экземпляр может изменить свой указатель vtable.
Не существует стандартного способа получения указателя vtable из экземпляра, поскольку он зависит от реализации компилятора. Смотрите этот пост для более подробной информации.
Тем не менее, G ++ и MSVC ++, похоже, размечают объекты класса, как описано в wikipedia .
Классы могут иметь указатели на несколько таблиц. Ради простоты я расскажу о
классы, которые имеют только один указатель vtable.
Чтобы получить указатель на функцию из vtable, это можно сделать так просто:
int* cVtablePtr = (int*)((int*)c)[0];
void* doSomethingPtr = (void*)cVtablePtr[1];
Где c - это экземпляр класса C для определения этого класса:
class A
{
public:
virtual void A1() { cout << "A->A1" << endl; }
virtual void DoSomething() { cout << "DoSomething" << endl; };
};
class C : public A
{
public:
virtual void A1() { cout << "C->A1" << endl; }
virtual void C1() { cout << "C->C1" << endl; }
};
Класс C - это просто структура, первым членом которой в этом случае является указатель на vtable.
В случае JIT-компилятора возможно кэширование
поиск в виртуальной таблице путем регенерации кода.
Сначала JIT-компилятор может выдать следующее:
void* func_ptr = obj_instance[vtable_offest][function_offset];
func_ptr(this, param1, param2)
Теперь, когда func_ptr известен, JIT может уничтожить этот старый код и просто
Жесткий код, адрес функции в скомпилированном коде
hardcoded_func_ptr(this, param1, param2)
Одна вещь, которую я должен отметить, это то, что, хотя вы можете перезаписать указатель vtable экземпляров, не всегда возможно перезаписать содержимое vtable. Например, в Windows vtable помечен как только для чтения памяти, но в OS X это чтение / запись. Таким образом, попытка изменить содержимое виртуальной таблицы в Windows приведет к нарушению прав доступа, если вы не измените доступ к странице с помощью VirtualProtect .