В документации, которую вы связали, говорится:
Для виртуальной функции это 1 плюс смещение виртуальной таблицы (в байтах) функции.
В разделе Virtual Table Layout говорится:
смещения в виртуальной таблице определяются этой последовательностью распределения и естественным размером ABI и выравниванием
Смещение должно соответствовать требованиям выравнивания указателя функции.
Требования к выравниванию указателя функции, который является типом «POD», указаны в соответствующем C ABI. Я предполагаю, что указатели выровнены по размеру, поэтому адрес (и, следовательно, смещение) указателя должен быть четным числом, а его младший бит должен быть равен нулю.
Таким образом, реализация может просто проверить LSB поля смещения / указателя и знать, что тогда и только тогда, когда LSB является одним, она имеет дело с виртуальным методом.
Получив смещение в виртуальной таблице, он считывает указатель виртуальной таблицы из объекта и загружает фактический адрес функции из виртуальной таблицы, используя смещение от указателя элемента.
class C {
virtual int someMethod();
};
int invokeAMethod(C *c, int (C::*method)()) {
return (c->*method)();
}
На x86_64 clang действительно создает проверку LSB члена "ptr" указателя метода:
invokeAMethod(C*, int (C::*)()): # @invokeAMethod(C*, int (C::*)())
// c is in rdi, method.adj is in rdx, and method.ptr is in rdx
// adjust this pointer
add rdi, rdx
// check whether method is virtual
test sil, 1
// if it is not, skip the following
je .LBB0_2
// load the vtable pointer from the object
mov rax, qword ptr [rdi]
// index into the vtable with the corrected offset to load actual method address
mov rsi, qword ptr [rax + rsi - 1]
.LBB0_2:
// here the actual address of the method is in rsi, we call it
// in this particular case we return the same type
// and do not need to call any destructors
// so we can tail call
jmp rsi # TAILCALL
Я не смог поделиться ссылкой Godbolt для этого конкретного примера, потому что один из моих плагинов браузера вмешался, но вы можете сами поиграть с подобными примерами на https://gcc.godbolt.org.
person
PaulR
schedule
19.04.2018