2015-07-09 1 views
1

Таким образом, можно сделать системный вызов пользовательской функцией для чистых виртуальных функций [1]. Это ставит вопрос о том, что может сделать такая функция. Для GCCНаписание пользовательского чистого виртуального обработчика: каково состояние стека и регистрируется при его вызове

Vtable for Foo 
Foo::_ZTV3Foo: 5u entries 
0  (int (*)(...))0 
8  (int (*)(...))(& _ZTI3Foo) 
16 0u 
24 0u 
32 (int (*)(...))__cxa_pure_virtual 

И он помещается непосредственно в слот для чистой виртуальной функции. Так как прототип функции void foo() не соответствует подлинной сигнатуре, является ли стек еще нормальным? В частности, я могу выбросить исключение и поймать его где-нибудь и продолжить выполнение.

[1] Is there an equivilant of _set_purecall_handler() in Linux?

ответ

0

Прочитайте x86-64 ABI supplement, чтобы понять, что происходит на самом деле; в частности около calling conventions.

В вашем случае стек безопасен (поскольку вызов void foo(void) безопасен вместо вызова любой другой подписи), и вы, вероятно, можете сделать какое-то исключение.

Подробная информация о компиляторе и процессоре. Возможно, ваш хак может работать, но, возможно, нет, но он действительно неспособен (поскольку технически это неопределенное поведение, IIUC).

Я не уверен, что это сработает. Возможно, компилятор испустит косвенный переход, и вы перейдете на нулевой адрес, и это будет SIGSEGV

Обратите внимание, что виртуальный вызов является просто косвенным скачком; с

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

extern "C" void doit(Foo*f) { 
    f->bar(); 
} 

ассемблерного кода (производится с g++-4.9 -Wall -O -fverbose-asm -S foo.cc) является:

 .type doit, @function 
doit: 
.LFB0: 
     .file 1 "foo.cc" 
     .loc 1 7 0 
     .cfi_startproc 
.LVL0: 
     subq $8, %rsp  #, 
     .cfi_def_cfa_offset 16 
     .loc 1 8 0 
     movq (%rdi), %rax # f_2(D)->_vptr.Foo, f_2(D)->_vptr.Foo 
     call *(%rax) # *_3 
.LVL1: 
     .loc 1 9 0 
     addq $8, %rsp  #, 
     .cfi_def_cfa_offset 8 
     ret 
     .cfi_endproc 
.LFE0: 
     .size doit, .-doit 

, и я не видел каких-либо проверок в отношении несвязанных виртуальных методов выше.

Это намного лучше и более переносимо, чтобы определить виртуальные методы в базовом классе для исключения исключения.

Вы можете настроить свой компилятор GCC с помощью MELT, чтобы соответствовать вашим странным потребностям!

+0

Ссылка на страницу спецификации ABI? – user877329

+0

вызов конвенций и регистров. –

+0

Кстати, в отношении вашего последнего предложения можно предоставить определение для чистой виртуальной функции, так что предложение может быть сделано для чистых виртуальных функций при сохранении абстрактного класса. – celticminstrel

Смежные вопросы