C语言 otool和objdump反汇编器是否输出包含在可执行文件中的确切机器指令?

l7mqbcuq  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(110)

我在一个名为test.c的文件中有这个简单的C程序:

void fx2(){

    int c = 30;
    c++;
}

void fx1(){

    int b = 20;
    b++;
    fx2();

}

int main(){

    int a = 10;
    a++; 
    fx1();
}

我在Ubuntu(22.04.3)x86_64系统中使用“gcc test.c -o test”编译了这个代码。然后我使用“objdump -d test”得到了这个:

0000000000001129 <fx2>:
    1129:   f3 0f 1e fa             endbr64 
    112d:   55                      push   %rbp
    112e:   48 89 e5                mov    %rsp,%rbp
    1131:   c7 45 fc 1e 00 00 00    movl   $0x1e,-0x4(%rbp)
    1138:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
    113c:   90                      nop
    113d:   5d                      pop    %rbp
    113e:   c3                      ret    

000000000000113f <fx1>:
    113f:   f3 0f 1e fa             endbr64 
    1143:   55                      push   %rbp
    1144:   48 89 e5                mov    %rsp,%rbp
    1147:   48 83 ec 10             sub    $0x10,%rsp
    114b:   c7 45 fc 14 00 00 00    movl   $0x14,-0x4(%rbp)
    1152:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
    1156:   b8 00 00 00 00          mov    $0x0,%eax
    115b:   e8 c9 ff ff ff          call   1129 <fx2>
    1160:   90                      nop
    1161:   c9                      leave  
    1162:   c3                      ret    

0000000000001163 <main>:
    1163:   f3 0f 1e fa             endbr64 
    1167:   55                      push   %rbp
    1168:   48 89 e5                mov    %rsp,%rbp
    116b:   48 83 ec 10             sub    $0x10,%rsp
    116f:   c7 45 fc 0a 00 00 00    movl   $0xa,-0x4(%rbp)
    1176:   83 45 fc 01             addl   $0x1,-0x4(%rbp)
    117a:   b8 00 00 00 00          mov    $0x0,%eax
    117f:   e8 bb ff ff ff          call   113f <fx1>
    1184:   b8 00 00 00 00          mov    $0x0,%eax
    1189:   c9                      leave  
    118a:   c3                      ret

我还在macOS(Monteray 12.6.5)x86_64系统中使用“clang test.c -o test”编译了test.c。然后我使用“otool -tV测试”,我得到了这个:

(__TEXT,__text) section
_fx2:
0000000100003f40    pushq   %rbp
0000000100003f41    movq    %rsp, %rbp
0000000100003f44    movl    $0x1e, -0x4(%rbp)
0000000100003f4b    movl    -0x4(%rbp), %eax
0000000100003f4e    addl    $0x1, %eax
0000000100003f51    movl    %eax, -0x4(%rbp)
0000000100003f54    popq    %rbp
0000000100003f55    retq
0000000100003f56    nopw    %cs:(%rax,%rax)
_fx1:
0000000100003f60    pushq   %rbp
0000000100003f61    movq    %rsp, %rbp
0000000100003f64    subq    $0x10, %rsp
0000000100003f68    movl    $0x14, -0x4(%rbp)
0000000100003f6f    movl    -0x4(%rbp), %eax
0000000100003f72    addl    $0x1, %eax
0000000100003f75    movl    %eax, -0x4(%rbp)
0000000100003f78    callq   _fx2
0000000100003f7d    addq    $0x10, %rsp
0000000100003f81    popq    %rbp
0000000100003f82    retq
0000000100003f83    nopw    %cs:(%rax,%rax)
0000000100003f8d    nopl    (%rax)
_main:
0000000100003f90    pushq   %rbp
0000000100003f91    movq    %rsp, %rbp
0000000100003f94    subq    $0x10, %rsp
0000000100003f98    movl    $0xa, -0x4(%rbp)
0000000100003f9f    movl    -0x4(%rbp), %eax
0000000100003fa2    addl    $0x1, %eax
0000000100003fa5    movl    %eax, -0x4(%rbp)
0000000100003fa8    callq   _fx1
0000000100003fad    xorl    %eax, %eax
0000000100003faf    addq    $0x10, %rsp
0000000100003fb3    popq    %rbp
0000000100003fb4    retq

我的问题是
1.考虑到这个简单的C程序,我能100%确定otool和objdump显示了包含在可执行“测试”中的确切机器指令吗?例如,两个函数序言指令pushq %rbpmovq %rsp,%rbp是否真的包含在实际的可执行“测试”中,或者这些反汇编程序是否可以省略/添加/修改指令以使程序更容易阅读和遵循?
1.看起来Ubuntu和macOS中的gcc和clang分别使用帧指针。我们可以说Ubuntu和macOS系统确实使用帧指针,或者说只有Ubuntu和macOS上下文中的特定编译器gcc和clang分别使用帧指针更合适吗?

3htmauhk

3htmauhk1#

考虑到这个简单的C程序,我能100%确定otool和objdump显示了可执行测试中包含的确切机器指令吗?例如,两个函数序言指令pushq %rbp和movq %rsp,%rbp”是否真的包含在实际可执行的“测试”中,或者这些反汇编程序可以省略/添加/修改指令以使程序更容易阅读和遵循?
它们不能总是显示“精确的”机器指令,因为当可执行文件在内存中被分配地址时,可能会发生重新定位,并且当程序被加载时,指令流中的地址会被更新。
除此之外,它们应该显示可执行文件中的实际指令,除了使用不同的助记符或具有相同含义的显示变体之外,可能包括对多个指令使用助记符。
看起来Ubuntu和macOS中的gcc和clang分别使用帧指针。我们是否可以说Ubuntu和macOS系统确实使用了帧指针,或者说只有Ubuntu和macOS上下文中的特定编译器gcc和clang才使用帧指针?
ClangGCC都有一个不使用帧指针的开关-fomit-frame-pointer,所以很明显它们并不总是使用帧指针。根据在高性能代码中使用它的经验,不使用帧指针的主要影响是它会中断调试,因为调试器(至少在macOS环境中)依赖于帧指针来获取有关调用树中进一步例程的一些信息。

z18hc3ub

z18hc3ub2#

1.反汇编程序通常精确地发出可执行文件中的指令。他们可能会遇到一些麻烦,二进制数据与指令以一种不会混淆处理器的方式穿插在一起,但可能会使反汇编程序难以决定代码在哪里继续。例如,clang编译器似乎生成“无意义”字节作为填充,以便下一个函数在16字节边界上开始,这对缓存行为有好处。反汇编程序不知道这一点,并试图将它们解释为指令。
1.使用帧指针(以及哪些寄存器用于参数和返回值传递)是ABI或调用约定的一部分,通常用于平台(操作系统),并由该平台的编译器遵循。一些语言可能在内部使用不同的调用约定,但在与C库代码交互时使用标准平台约定。

相关问题