成员函数指针,动态绑定(vc平台)
来源:互联网 发布:军事网络的安全保护 编辑:程序博客网 时间:2024/05/17 06:01
上一篇介绍了gcc对成员函数指针做了thunk的处理,本篇介绍vc对成员函数指针如何处理,还有动态绑定相关的处理。
同样用回上一篇的例子:
struct point {float x,y;};struct obj{ virtual ~obj {} void foo(int) {} void foo(point) {} virtual void vfoo() {}};struct objobj : public obj{ virtual ~objobj {} virtual void vfoo() {}};void main(){ obj o; objobj oo; //void* pofp = (void*) (void(obj::*)(point))&obj::foo; // error C2440: “类型转换”: 无法从“void (__cdecl obj::* )(point)”转换为“void *” void(obj::*pi)(int) = &obj::foo; void(obj::*pp)(point) = &obj::foo; void(objobj::*vp)() = &objobj::vfoo; NOOP ((&oo)->*vp)(); NOOP ((&oo)->*pi)(1); NOOP ((&o)->*pp)(pt);}
成员函数指针定义以及调用的代码,所对应的反汇编:
00000001`3f461159 488d05e6feffff lea rax,[test!ILT+65(?fooobjQEAAXHZ) (00000001`3f461046)]00000001`3f461160 48898424d8000000 mov qword ptr [rsp+0D8h],rax ; void(obj::*pi)(int) = &obj::foo;00000001`3f461168 488d05b4feffff lea rax,[test!ILT+30(?fooobjQEAAXUpointZ) (00000001`3f461023)]00000001`3f46116f 48898424e0000000 mov qword ptr [rsp+0E0h],rax ; void(obj::*pp)(point) = &obj::foo;00000001`3f461177 488d05b9feffff lea rax,[test!ILT+50(??_9objobj$B7AA) (00000001`3f461037)]00000001`3f46117e 48898424e8000000 mov qword ptr [rsp+0E8h],rax ; void(objobj::*vp)() = &objobj::vfoo;00000001`3f461186 488d8c2498000000 lea rcx,[rsp+98h]00000001`3f46118e ff9424e8000000 call qword ptr [rsp+0E8h] ; ((&oo)->*vp)(); test!ILT+50(??_9objobj$B7AA) (00000001`3f461037)00000001`3f461195 ba01000000 mov edx,100000001`3f46119a 488d8c2498000000 lea rcx,[rsp+98h]00000001`3f4611a2 ff9424d8000000 call qword ptr [rsp+0D8h] ; ((&oo)->*pi)(1); test!ILT+65(?fooobjQEAAXHZ) (00000001`3f461046)
上面有三处指针赋值,被赋地址分别信息分别如下:
test!ILT+65(?fooobjQEAAXHZ):00000001`3f461046 e955020000 jmp test!obj::foo (00000001`3f4612a0)0:000> dt 00000001`3f4612a0obj::foo void test!obj::foo+0( int)test!ILT+30(?fooobjQEAAXUpointZ):00000001`3f461023 e9a8020000 jmp test!obj::foo (00000001`3f4612d0)0:000> dt 00000001`3f4612d0obj::foo void test!obj::foo+0( point)test!ILT+50(??_9objobj$B7AA):00000001`3f461037 e964050000 jmp test!objobj::`vcall'{8}' (00000001`3f4615a0)0:000> dt 00000001`3f4615a0objobj::`vcall'{8}'Symbol not found.0:000> u 00000001`3f4615a0 L3test!objobj::`vcall'{8}':00000001`3f4615a0 488b01 mov rax,qword ptr [rcx]00000001`3f4615a3 ff6008 jmp qword ptr [rax+8] ; => jmp test!objobj::vfoo
函数的调用都经由一个间接跳转,这是hook的基础,天生带上了M属性,这不是本篇的主题。忽视这个间接跳转(或者看作短路),我们认为非虚的成员函数指针直接指向成员函数本体,但是虚函数指针指向的是一小块类似thunk的处理代码。虚函数是动态绑定的,thunk相关的处理是必要的。vc编译器在可以正确分析出绑定的情况下,将这段thunk处理内联到调用处罢了。
SDK中使用thunk的地方还有,atlthunk.h, olecall_.s, oledisp1.cpp, qithunk.s, stdcallthunk.s。这些使用thunk的地方大都与com相关,目的各不相同。例如,qithunk.s就是queryinterface thunk,也就是用于调试com, 别有用心加了一层模仿IUnknown调用虚函数的过程,使得com的方法被调用前都必须先经过qithunk的虚函数,从而可以被中断而不用知道执行的是哪种具体的com。当你不知道com的调试信息时,也可以中断到com的每个方法入口。qithunk是这里面我认为比较容易分析的,只要了解IUKnown接口和虚函数表就可以分析了。
又如IDispatch是用于实现动态绑定的接口,vbscript和jscript中使用到的对象都实现了这个接口。在script中调用对象的属性或方法时,是通过属性名或方法名来绑定com的执行函数。这种方式跟objc的消息调用在形式上有点像。window.getElementById("form"), 调用的是window.invoke(GETDISPID("getElementById"), ..., args("form"),...); 在objc中[window getElementById:"form"],调用是objc_sendMsg(window, "getElementById:", "form");
本篇浅略提及了thunk和动态绑定,有了感性认识后,分析objc中SEL的动态绑定就不会太陌生了。分析objc的文章也请在未来的日子关注。
我的另一处博客地址:http://www.cnblogs.com/bbqzsl
- 成员函数指针,动态绑定(vc平台)
- 函数指针动态绑定
- C++调用空指针对象的成员函数——静态绑定与动态绑定
- C++成员函数指针动太绑定
- C++ 消息(成员函数调用)的动态绑定
- 函数指针和成员函数指针有什么不同,反汇编带看清成员函数指针的本尊(gcc@x64平台)
- 函数指针和成员函数指针有什么不同,反汇编带看清成员函数指针的本尊(gcc@x64平台)
- C++类对象空指针访问成员函数(静态绑定)
- Java面向对象 多态动态绑定(非静态成员函数、成员变量、静态成员函数)
- 类成员指针和成员函数指针(深入理解)
- vc如何动态增加类的成员函数
- 函数指针 成员函数指针
- C++ 指向成员的指针(数据成员指针,函数成员指针)
- 普通函数指针和指向成员函数指针(转载)
- 一般函数指针和类成员函数指针(转)
- 成员函数的指针(C++)
- 成员函数指针【转贴】
- 类成员函数指针
- ACCESS网站示例-连载-配置文件
- K&R C与ANSI C的区别
- MAC常用快捷键
- linux"$* "$*" $@ "$@"用法解释
- ACE_OutputCDR,ACE_InputCDR,ACE_Message_Block使用2
- 成员函数指针,动态绑定(vc平台)
- 蓝桥杯特殊回文数
- windows下Markdownpad的简单用法
- java 一点浅薄的东西 分享1
- 机器学习中的数学(3)-模型组合(Model Combining)之Boosting与Gradient Boosting
- linux运行级别
- Python 递归函数选择排序和二分查找
- Linux内核工程导论——网络:Filter(LSF、BPF、eBPF)
- 排序算法