2016-12-21 3 views
0

Я экспериментировал с виртуальной таблицей и виртуальным указателем. Чтобы узнать больше, я сделал следующее:Доступ к VTABLE напрямую вызывает неопределенную ошибку

//a simple class 
    class X 
    { 
    public: 
     // fn is a simple virtual function 
     virtual void fn() { cout << "n = " << n << endl; } 
     // a member variable 
     int n; 
    }; 

    int main() 
    { 
    // create an object (obj) of class X 
    X *obj = new X(); 
    obj->n = 10; 

    // get the virtual table pointer of object obj 
    int* vptr = *(int**)obj; 

    __asm__("mov %eax, obj;"); 

    // function fn is the first entry of the virtual table, so it's vptr[0] 
    ((void (*)()) vptr[0])(); 

    // the above should be the same as the following 
    //obj->fn(); 

    return 0; 
    } 

Но компилятор дает следующее сообщение об ошибке:

/home/OaVTND/cclnoQaK.o: In function 'main': prog.cpp:(.text.startup+0x26): undefined reference to `obj'
collect2: error: ld returned 1 exit status

Я не знаком с языка ассемблера кода. Я заимствовал это из кода другого тела. Я использую сервер gcc-4.9 и Centos 7 x64 бит.

+1

Ваш встроенный asm разбит несколькими способами (вам необходимо передать адрес obj в качестве входного операнда для встроенной сборки, вы перемещаете произвольное содержимое% eax в obj). Непонятно, чего вы пытаетесь достичь. – yugr

+0

и что вы делаете в __asm__.? –

+2

@GreenTree: он пытается настроить указатель 'this', загружая адрес объекта в EAX. Это нормально - если оператор вызова не случайно использует EAX для вычисления целевого адреса. –

ответ

1

obj - локальная переменная, у нее нет связи, нет символа. просто попробуйте сделать свой объект глобальным.

+0

Я сделал obj как глобальный и снова перекомпилировал. Но выход: n = 1076818912 Который должен быть n = 10. Что происходит не так. –

+0

попробуйте приложить vptr [0] к указателю на функцию, которая принимает указатель на X., а затем передать адрес объекта напрямую. –

+0

как в yugrs ответ. –

1

Просто избавиться от встроенного ассемблере и сделать

((void (*)(void *)) vptr[0])(&obj); 

Предупреждение: Я предполагаю, что вы бежите на GCC Linux x86_64, как ABI детали на других платформах будет отличаться.

+0

Это точно не будет работать на 32-битной Windows. Указатель 'this' * не * передается как обычный аргумент (он передается в регистре ECX). Я не знаю, как linux обрабатывает это в режимах x86 и x64. –

+0

У меня возникает ощущение, что он будет работать на большинстве платформ, для которых GCC является основным компилятором (например, Linux), потому что у вас есть [Itanium ABI] (https: // mentorembedded .github.io/cxx-abi/abi.html). – yugr

+0

@MartinBonner Интересно, можете ли вы добавить __thiscall к типу функции, чтобы заставить MSVS использовать разумное соглашение о вызове. – yugr

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