原理
可以使用gcc的链接选项 -Wl,–wrap=func。
会设置符号映射,在符号重定位阶段的时候,静态链接器对func函数的定位会定位到 __wrap_func 符号,对 __real_func 会定位到原func。
举例说明:
C Mock
libtest.h
/// @file libtest.h
#ifndef __LIBTEST_H__
#define __LIBTEST_H__
void test_func();
#endif
libtest.c
/// @file libtest.c
#include "libtest.h"
#include <stdio.h>
void test_func() {
printf("test_func\n");
};
test.c
/// @file test.c
#include "libtest.h"
int main() {
test_func();
return 0;
};
wrap.c
/// @file wrap.c
#include <stdio.h>
void __real_test_func();
void __wrap_test_func() {
printf("before test_func\n");
__real_test_func();
};
编译
gcc -g -O0 libtest.c test.c wrap.c -o test -Wl,--wrap=test_func
结果为
before test_func
test_func
C++ Mock
由于C++对符号有修饰,故需要对修饰后的符号名做映射。
libtest.h
/// @file libtest.h
#ifndef __LIBTEST_H__
#define __LIBTEST_H__
void test_func();
#endif
libtest.cc
/// @file libtest.cc
#include "libtest.h"
#include <stdio.h>
void test_func() {
printf("test_func\n");
};
test.cc
/// @file test.cc
#include "libtest.h"
int main() {
test_func();
return 0;
};
wrap.cc
/// @file wrap.cc
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
void __real__Z9test_funcv();
void __wrap__Z9test_funcv() {
printf("before test_func\n");
__real__Z9test_funcv();
};
#ifdef __cplusplus
}
#endif
编译
g++ -g -O0 libtest.cc test.cc wrap.cc -o test -Wl,--wrap=_Z9test_funcv
结果为
before test_func
test_func
C++ 成员函数Mock
需要在实现的__wrap_func的函数中传入一个const*对象指针(即this),编译器会为非静态成员函数插入该参数。
C++规定,编译成员函数时要额外添加一个参数,把当前对象的指针传递进去,通过指针来访问成员变量。
libtest.h
/// @file libtest.h
#ifndef __LIBTEST_H__
#define __LIBTEST_H__
class Hello {
public:
test_func();
};
#endif
libtest.cc
/// @file libtest.cc
#include "libtest.h"
#include <stdio.h>
void Hello::test_func() {
printf("test_func\n");
};
test.cc
/// @file test.cc
#include "libtest.h"
int main() {
Hello hello;
hello.test_func();
return 0;
};
wrap.cc
/// @file wrap.cc
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
void __real__ZN5Hello9test_funcEv(const Hello* pointer);
void __wrap__ZN5Hello9test_funcEv(const Hello* pointer) {
printf("before test_func\n");
__real__ZN5Hello9test_funcEv(pointer);
};
#ifdef __cplusplus
}
#endif
编译
g++ -g -O0 libtest.cc test.cc wrap.cc -o test -Wl,--wrap=_ZN5Hello9test_funcEv
结果为
before test_func
test_func