Как получить указатель из таблицы C ++ vtable?

Допустим, у вас есть класс C ++, например:

class Foo {
 public:
  virtual ~Foo() {}
  virtual DoSomething() = 0;
};

Компилятор C ++ переводит вызов в поиск vtable:

Foo* foo;

// Translated by C++ to:
//   foo->vtable->DoSomething(foo);
foo->DoSomething();

Предположим, я писал JIT компилятор, и я хотел получить адрес функции DoSomething () для конкретного экземпляра класса Foo, чтобы я мог сгенерировать код, который переходит к нему напрямую, вместо того, чтобы выполнять поиск в таблице и косвенную ветвь.

Мои вопросы:

  1. Есть ли какой-нибудь стандартный способ C ++ сделать это (я почти уверен, что ответ отрицательный, но хотел бы спросить для полноты картины).

  2. Есть ли какой-либо дистанционно независимый от компилятора способ сделать это, например, реализованная кем-то библиотека, которая предоставляет API для доступа к vtable?

Я полностью открыт для взломов, если они будут работать. Например, если бы я создал свой собственный производный класс и мог определить адрес его метода DoSomething, я мог бы предположить, что vtable является первым (скрытым) членом Foo, и искать в его vtable, пока не найду свое значение указателя. Однако я не знаю, как получить этот адрес: если я напишу & DerivedFoo :: DoSomething , я получу указатель на член, а это нечто совершенно иное.

Может быть, я мог бы превратить указатель на член в смещение vtable.Когда я компилирую следующее:

class Foo {
 public:
  virtual ~Foo() {}
  virtual void DoSomething() = 0;
};

void foo(Foo *f, void (Foo::*member)()) {
  (f->*member)();
}

На GCC / x86-64 я получаю следующий результат сборки:

Disassembly of section .text:

0000000000000000 <_Z3fooP3FooMS_FvvE>:
   0:   40 f6 c6 01             test   sil,0x1
   4:   48 89 74 24 e8          mov    QWORD PTR [rsp-0x18],rsi
   9:   48 89 54 24 f0          mov    QWORD PTR [rsp-0x10],rdx
   e:   74 10                   je     20 <_Z3fooP3FooMS_FvvE+0x20>
  10:   48 01 d7                add    rdi,rdx
  13:   48 8b 07                mov    rax,QWORD PTR [rdi]
  16:   48 8b 74 30 ff          mov    rsi,QWORD PTR [rax+rsi*1-0x1]
  1b:   ff e6                   jmp    rsi
  1d:   0f 1f 00                nop    DWORD PTR [rax]
  20:   48 01 d7                add    rdi,rdx
  23:   ff e6                   jmp    rsi

Я не совсем понимаю, что здесь происходит, но если бы я мог перепроектировать это или использовать спецификацию ABI, я может сгенерировать фрагмент, подобный приведенному выше, для каждой отдельной платформы, как способ получения указателя из vtable.

17
задан Brad 26 September 2015 в 15:39
поделиться