【问题标题】:What is called in this optimised code在这个优化的代码中调用了什么
【发布时间】:2015-12-02 19:13:18
【问题描述】:

我有一个简单的 C 代码:

#include <stdio.h>

void p(){
    printf("jjjj");
}

int main(){
    p();
}

如果我在 Mac OSX 上使用 g++ 编译它并使用 otool -tv 反汇编,我可以看到 pmain 函数,并且 main 调用 p。使用优化 (-O3) 我得到了这个:

(__TEXT,__text) section
__Z1pv:
0000000100000f40    pushq   %rbp
0000000100000f41    movq    %rsp, %rbp
0000000100000f44    leaq    0x4b(%rip), %rdi
0000000100000f4b    xorl    %eax, %eax
0000000100000f4d    popq    %rbp
0000000100000f4e    jmp 0x100000f76
0000000100000f53    nopw    %cs:(%rax,%rax)
_main:
0000000100000f60    pushq   %rbp
0000000100000f61    movq    %rsp, %rbp
0000000100000f64    leaq    0x2b(%rip), %rdi
0000000100000f6b    xorl    %eax, %eax
0000000100000f6d    callq   0x100000f76
0000000100000f72    xorl    %eax, %eax
0000000100000f74    popq    %rbp
0000000100000f75    retq

似乎main 仍然调用地址0x100000f76 的东西。如何查看此位置的内容? g++ 在这里做什么?

【问题讨论】:

    标签: c gcc optimization


    【解决方案1】:

    你没有将p() 声明为static,所以你看到的是p() 的编译版本,它调用printf()(通过jmp),然后你也得到了一个内联p()main() 中的版本,它也只是转换为对printf() 的调用。如果您将p() 声明为static,那么您只会在main() 中看到内联调用。

    不过,要回答您的问题,0x100000f76 似乎将成为printf() 的入口点。

    比起分解你的代码,你可能会发现告诉编译器生成 asm 更有指导意义,因为这将包含更多有用的信息,例如gcc -S -O3(在 OS X 上使用 clang)生成:

        .section    __TEXT,__text,regular,pure_instructions
        .macosx_version_min 10, 11
        .globl  _p
        .align  4, 0x90
    _p:                                     ## @p
        .cfi_startproc
    ## BB#0:
        pushq   %rbp
    Ltmp0:
        .cfi_def_cfa_offset 16
    Ltmp1:
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
    Ltmp2:
        .cfi_def_cfa_register %rbp
        leaq    L_.str(%rip), %rdi
        xorl    %eax, %eax
        popq    %rbp
        jmp _printf                 ## TAILCALL
        .cfi_endproc
    
        .globl  _main
        .align  4, 0x90
    _main:                                  ## @main
        .cfi_startproc
    ## BB#0:
        pushq   %rbp
    Ltmp3:
        .cfi_def_cfa_offset 16
    Ltmp4:
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
    Ltmp5:
        .cfi_def_cfa_register %rbp
        leaq    L_.str(%rip), %rdi
        xorl    %eax, %eax
        callq   _printf
        xorl    %eax, %eax
        popq    %rbp
        retq
        .cfi_endproc
    
        .section    __TEXT,__cstring,cstring_literals
    L_.str:                                 ## @.str
        .asciz  "jjjj"
    
    
    .subsections_via_symbols
    

    在这里您可以看到jmpcallqprintf 而不仅仅是一些未知地址。

    【讨论】:

    • 有没有办法检查0x100000f76 调用的内容?我假设这里是printf,但是如果我有更复杂的代码呢?
    • 没有。我已经复制粘贴了我得到的所有东西。也许是因为它不是静态链接的。但我仍然很好奇如何检查此类调用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-13
    • 2012-10-08
    • 2019-07-21
    • 2020-01-18
    • 2021-08-14
    • 1970-01-01
    • 2017-05-19
    相关资源
    最近更新 更多