最近在CPPUTEST框架下写单元测试程序,测试用例对于memcpy打桩(即定义一个本地的memcpy,不链接到C库的memcpy)。
函数原型如下:
void *memcpy(void *dest, const void *src, size_t n)
{
printf("this is my stub\n");
}
运行的时候,发现size_t 如果是一个变量,或者一个比较大的值,printf会执行。如果size_t是一个小于120的数,printf不会被执行。开始的时候,以为是C++函数重载导致的。结果在本地并没有发现memcpy的其他定义。用了objdump出来看汇编。发现一个有意思的现象,如下:
void fun(char const * const filename){
char *aa = NULL;
406f54: 48 c7 45 f0 00 00 00 movq $0x0,0xfffffffffffffff0(%rbp)
406f5b: 00
char *bb =NULL;
406f5c: 48 c7 45 f8 00 00 00 movq $0x0,0xfffffffffffffff8(%rbp)
406f63: 00
(void)memcpy((void *)aa, (const void *)bb, 1024*1024);
406f80: 48 8b 45 f0 mov 0xfffffffffffffff0(%rbp),%rax
406f84: 48 8b 55 f8 mov 0xfffffffffffffff8(%rbp),%rdx
406f88: 48 89 c7 mov %rax,%rdi
406f8b: 48 89 d6 mov %rdx,%rsi
406f8e: ba 00 00 10 00 mov $0x100000,%edx
406f93: e8 f2 c0 ff ff callq 40308a <memcpy>
406f98: 48 8b 05 09 f3 22 00 mov 2290441(%rip),%rax
406f9f: 48 83 c0 01 add $0x1,%rax
406fa3: 48 89 05 fe f2 22 00 mov %rax,2290430(%rip)
(void)memcpy((void *)aa, (const void *)bb, 1);
406fc6: 48 8b 55 f0 mov 0xfffffffffffffff0(%rbp),%rdx
406fca: 48 8b 45 f8 mov 0xfffffffffffffff8(%rbp),%rax
406fce: 0f b6 00 movzbl (%rax),%eax
406fd1: 88 02 mov %al,(%rdx)
406fd3: 48 8b 05 de f2 22 00 mov 2290398(%rip),%rax
406fda: 48 83 c0 01 add $0x1,%rax
406fde: 48 89 05 d3 f2 22 00 mov %rax,2290387(%rip)
return EAaTrblCbStatus_Ok;
406fe5: b8 00 00 00 00 mov $0x0,%eax
}
可以看到,编译器对于第二次的memcpy做了优化,不调用memcpy函数,就直接做了内存拷贝。
百度了下,发现如下链接说的比较详细了。
http://blog.sina.com.cn/s/blog_4017fe890100hat2.html
在单元测试的makefile中加入-fno-builtin参数。终于如愿以偿了,每次测试case,都调用了memcpy桩函数。