Я искал способ получить доступ к vtable напрямую через указатель и наткнулся на этот пост: http://www.codeproject.com/Tips/90875/Displaying-vtable-when-debugging
Он работает нормально, и я могу вызывать функции через записи vtable.
Но у меня возникают проблемы с пониманием этой линии део:
void (**vt)() = *(void (***)())ptr;
ptr
это указатель на объект. Как я могу расшифровать эту строку и как vt
получить виртуальный адрес?
Спасибо.
void (**vt)()
vt — указатель на указатель на некоторую функцию. Эта функция возвращает void и не принимает параметров.
void (***)()
означает указатель на указатель на указатель на такую функцию (т.е. на один уровень указателя больше, чем выше).
Во-первых, вы приводите ptr к такому трехуровневому указателю на функцию.
Затем вы получите то, на что он указывает (с *
), то есть двухуровневый указатель на функцию, т.е. тот же тип переменной Vt. Это означает, что вы можете назначить его vt, и это именно то, что делает эта строка.
И почему?
Одиночный указатель на функцию void-no-param-function может храниться в такой переменной x: void(*x)()
, И не совсем связанный, если вы хотите передать некоторый массив в функцию, вы передаете указатель. То есть. Достаточно сохранить адрес массива в указателе, чтобы получить доступ ко всему массиву (если длина известна).
Это означает void(**vt)()
может хранить (адрес) массив указателей на функции.
Vtable — это не что иное, как массив указателей на функции.
Если у вас есть класс Car с некоторыми переменными, такими как color и vtable, и он использует, например,. 200 байт на объект. Указатель на автомобиль похож на указатель на 200-байтовый массив, и если вы обращаетесь к цвету в коде, компилятор ищет, что цвет, например, равен. байт 133 и генерирует доступ к нему.
Где vtable находится внутри этого объекта, определяется реализацией, но часто в начале. Если у вас есть указатель на автомобиль, это указатель на массив из 200 байт, разделенный сначала на несколько указателей функций, а затем на некоторые другие данные …
=> Vtable, т.е. массив указателей на функции, запускается с начального адреса автомобиля.
=> Если вы приведете указатель автомобиля на указатель на vtable, т.е. указатель на «массив указателей на функции», т.е. указатель на «указатель на указатель на функцию» и, что у вас есть массив vtable.
Фактическое расположение _vtable в объекте зависит от компилятора. Код предполагает, что адрес _vtable сохраняется первым в объекте (что, похоже, делают все современные компиляторы). Кроме того, существует только один vtable на класс, который хранится в одном месте. Таким образом, каждый экземпляр имеет адрес для этого массива указателей на функции.
По сути, вы создаете переменную с именем vt, которая представляет собой массив указателей на функции, которые возвращают void и не принимают параметров. Затем вы инициализируете эту переменную содержимым, найденным в первом члене объекта (адрес виртуальной таблицы).
(void (***)())ptr
означает, что вы приведете эти первые 4 (32-битный компьютер) или 8 (64-битный компьютер) к указателю на массив указателей на функции, которые возвращают void и не принимают параметров.
*(void (***)())ptr
возвращает содержимое этих 4 или 8 байтов, то есть адрес виртуальной таблицы.