-O 和 -wrap 的行为

问题描述 投票:0回答:1

我正在尝试使用 -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

有人可以帮助我理解为什么/如何看到这种行为吗?预先感谢

c gcc linker compiler-optimization
1个回答
0
投票

对于 gcc,

malloc()
被视为所谓的 “内置”函数,优化器会意识到并专门处理它(例如,它可以对其返回值做出某些假设,这会导致它自动失败)断言而不需要对其进行运行时测试)。如果您将
-fno-builtin-malloc
添加到编译选项中,则该特殊处理将被禁用:

$ gcc -Os -fno-builtin-malloc -Wl,-wrap=malloc 1.c -o opt
$ ./opt
Called __wrap_malloc
© www.soinside.com 2019 - 2024. All rights reserved.