我正在尝试使用 -wrap=symbol 来模拟函数进行单元测试,并且根据传递的 GCC 优化标志发现不同的行为
考虑下面的示例程序
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void * __wrap_malloc(size_t sz)
{
printf("Called %s", __func__);
return (void *) 0xDEADBEEF;
}
int main()
{
void *ptr;
ptr = malloc(10);
assert(0xDEADBEEF == (unsigned int)(uintptr_t)(ptr));
return 0;
}
使用优化时
❯ gcc -Os -Wl,-wrap=malloc 1.c -o opt
❯ ./opt
opt: 1.c:16: main: Assertion `0xDEADBEEF == (unsigned int)(uintptr_t)(ptr)' failed.
[1] 12546 abort ./opt
未经优化
❯ gcc -Wl,-wrap=malloc 1.c -o without_opt
❯ ./without_opt
Called __wrap_malloc
我尝试反汇编可执行文件
优化
0000000000400450 <main>:
400450: 48 83 ec 08 sub $0x8,%rsp
400454: b9 20 06 40 00 mov $0x400620,%ecx
400459: ba 10 00 00 00 mov $0x10,%edx
40045e: be ea 05 40 00 mov $0x4005ea,%esi
400463: bf ee 05 40 00 mov $0x4005ee,%edi
400468: e8 d3 ff ff ff callq 400440 <__assert_fail@plt>
40046d: 0f 1f 00 nopl (%rax)
未经优化
000000000040053e <main>:
40053e: 55 push %rbp
40053f: 48 89 e5 mov %rsp,%rbp
400542: 48 83 ec 10 sub $0x10,%rsp
400546: bf 0a 00 00 00 mov $0xa,%edi
40054b: e8 c7 ff ff ff callq 400517 <__wrap_malloc>
400550: 48 89 45 f8 mov %rax,-0x8(%rbp)
400554: 48 8b 45 f8 mov -0x8(%rbp),%rax
400558: 3d ef be ad de cmp $0xdeadbeef,%eax
40055d: 74 19 je 400578 <main+0x3a>
40055f: b9 4e 06 40 00 mov $0x40064e,%ecx
400564: ba 10 00 00 00 mov $0x10,%edx
400569: be 0a 06 40 00 mov $0x40060a,%esi
40056e: bf 10 06 40 00 mov $0x400610,%edi
400573: e8 c8 fe ff ff callq 400440 <__assert_fail@plt>
400578: b8 00 00 00 00 mov $0x0,%eax
40057d: c9 leaveq
40057e: c3 retq
40057f: 90 nop
没有调用wrap_malloc。看起来已经优化了。然后我尝试添加打印语句
int main()
{
void *ptr;
ptr = malloc(10);
>> printf("0x%x\n", (uintptr_t)ptr);
assert(0xDEADBEEF == (unsigned int)(uintptr_t)(ptr));
return 0;
}
❯ gcc -Os -Wl,-wrap=malloc 1.c -o print_opt
❯ ./print_opt
Called __wrap_malloc0xdeadbeef
print_opt: 1.c:17: main: Assertion `0xDEADBEEF == (unsigned int)(uintptr_t)(ptr)' failed.
[1] 31575 abort ./print_opt
现在我看到包装的函数被调用。但断言失败了
0000000000400450 <main>:
400450: 48 83 ec 08 sub $0x8,%rsp
400454: bf 0a 00 00 00 mov $0xa,%edi
400459: e8 f9 00 00 00 callq 400557 <__wrap_malloc>
40045e: bf 0a 06 40 00 mov $0x40060a,%edi
400463: 48 89 c6 mov %rax,%rsi
400466: 31 c0 xor %eax,%eax
400468: e8 c3 ff ff ff callq 400430 <printf@plt>
40046d: b9 48 06 40 00 mov $0x400648,%ecx
400472: ba 11 00 00 00 mov $0x11,%edx
400477: be 10 06 40 00 mov $0x400610,%esi
40047c: bf 14 06 40 00 mov $0x400614,%edi
400481: e8 ba ff ff ff callq 400440 <__assert_fail@plt>
400486: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40048d: 00 00 00
有人可以帮助我理解为什么/如何看到这种行为吗?预先感谢
对于 gcc,
malloc()
被视为所谓的 “内置”函数,优化器会意识到并专门处理它(例如,它可以对其返回值做出某些假设,这会导致它自动失败)断言而不需要对其进行运行时测试)。如果您将 -fno-builtin-malloc
添加到编译选项中,则该特殊处理将被禁用:
$ gcc -Os -fno-builtin-malloc -Wl,-wrap=malloc 1.c -o opt
$ ./opt
Called __wrap_malloc