저는 vtable 및 vpointers의 내부 동작에 대해 좀 더 배우려고 했으므로 일부 트릭을 사용하여 vtable에 직접 액세스하려고했습니다. 나는 Base
과 Derv
의 두 클래스를 만들었는데 각각은 두 개의 virtual
함수를 가지고 있습니다 (Derv
은 Base
을 오버라이드합니다).vtables 및 this 포인터
class Base
{
int x;
int y;
public:
Base(int x_, int y_) : x(x_), y(y_) {}
virtual void foo() { cout << "Base::foo(): x = " << x << '\n'; }
virtual void bar() { cout << "Base::bar(): y = " << y << '\n'; }
};
class Derv: public Base
{
int x;
int y;
public:
Derv(int x_, int y_) : Base(x_, y_), x(x_), y(y_) {}
virtual void foo() { cout << "Derived::foo(): x = " << x << '\n'; }
virtual void bar() { cout << "Derived::bar(): y = " << y << '\n'; }
};
지금 컴파일러는 메모리의 제 4 바이트 (32 비트)를 차지하고, 각 클래스에 대한 포인터를 추가 VTABLE. 포인터가 크기가 sizeof(size_t)
인 다른 포인터를 가리 키므로 size_t*
에 개체의 주소를 캐스팅하여이 포인터에 액세스했습니다. 이제 vpointer를 인덱싱하고 결과를 적절한 유형의 함수 포인터로 캐스팅하여 가상 함수에 액세스 할 수 있습니다. 나는 함수에서 다음 단계를 캡슐화 :
template <typename T>
void call(T *ptr, size_t num)
{
typedef void (*FunPtr)();
size_t *vptr = *reinterpret_cast<size_t**>(ptr);
FunPtr fun = reinterpret_cast<FunPtr>(vptr[num]);
//setThisPtr(ptr); added later, see below!
fun();
}
memberfunctions 중 하나가이 방법이라고
, 예를 들면, call(new Base(1, 2), 0)
을 호출하여 Base :: foo()를 호출하면 this
-pointer없이 호출되기 때문에 어떤 일이 일어날 지 예측할 수 없습니다.
template <typename T>
void setThisPtr(T *ptr)
{
asm (mov %0, %%ecx;" :: "r" (ptr));
}
은 조각에 setThisPtr(ptr)
라인의 주석 : 나는 (이 그러나 -m32
컴파일러 플래그로 컴파일 나를 강제로)를 ecx
레지스터에 저장에게 ++ 그 g을 알고는 this
-pointer을 조금 템플릿 사용 기능을 추가하여 해결 지금 그것을 작동하는 프로그램을 만드는 위 : vtable을 작동하고 조금 더 나은 자료를 이해하는 다른 사람들을 도울 수있는 방법을이 작은 프로그램을 작성하는 과정에서 내가 더 통찰력을 얻은 이후
int main()
{
Base* base = new Base(1, 2);
Base* derv = new Derv(3, 4);
call(base, 0); // "Base::foo(): x = 1"
call(base, 1); // "Base::bar(): y = 2"
call(derv, 0); // "Derv::foo(): x = 3"
call(derv, 1); // "Derv::bar(): y = 4"
}
나는이 공유하기로 결정 . 그러나 나는 여전히 몇 가지 질문을 가지고있다 :
1. 64 비트 바이너리를 컴파일 할 때이 포인터를 저장하기 위해 (gcc 4.x) 사용되는 레지스터는 어느 것입니까? 여기에 설명 된대로 모든 64 비트 레지스터를 시도했습니다 : http://developers.sun.com/solaris/articles/asmregs.html
2. this 포인터가/when은 어떻게 설정됩니까? 필자는 컴파일러가 각 함수 호출에서이 포인터를 객체를 통해 비슷한 방법으로 설정했다고 의심합니다. 이것은 다형성이 실제로 작용하는 방식입니까? (이 포인터를 먼저 설정 한 다음 vtable에서 가상 함수를 호출하면됩니까?).
이것은 일반적인 SO 질문에 대해 약간 길다.이 문제를 핵심 쟁점으로 요약 할 수 있습니까? (실제로 최종 질문과 직접적으로 관련이있는 게시물은 무엇입니까?) –
@Oli Charlesworth 글쎄, 내가이 질문에 온 것이기 때문에 그것은 나를위한 것이다. 두 번째 질문은 컴파일러가 다형성을 가능하게하는 비슷한 방법론을 사용하는지 묻습니다. 그래서 제 자신을 포함시켜야한다고 생각합니다. 이 정보를 공유하고 질문 할 수있는 다른 매체를 제안 하시겠습니까? – JorenHeit
당신은 여기에 질문을해야하며, 그 질문에 대해 충분한 컨텍스트를 가지고 이해해야합니다 (이러한 특정 질문에 대한 * 모든 컨텍스트가 필요하지는 않습니다.). 당신이 발견 한 것을 공유하고 싶다면 블로그를 설정해야합니다. –