【问题标题】:What do these instructions in the diassembly phase indicate?反汇编阶段的这些指令说明了什么?
【发布时间】:2020-08-11 04:53:37
【问题描述】:

您好,当我在 clion IDE 调试器中运行 c++ 代码时,main() 返回后,调试器会进入一个名为反汇编的文件,其中包含看起来像汇编代码的内容。那些指示是什么?它有什么作用?我应该关心吗?由于我是 C++ 新手,因此我正在熟悉语言、IDE 和其他相关内容。

start:
    nop
    movl   %eax, %edi
    callq  0x2e82e                    ; symbol stub for: exit
    hlt
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop


exit:
    jmpq   *0x268c241c(%rip)


exit:
    pushq  %rbp
    movq   %rsp, %rbp
    pushq  %rbx
    pushq  %rax
    movl   %edi, %ebx
    cmpl   $0xad, %edi
    jne    0x5a404                    ; <+41>
    leaq   0x2683a31e(%rip), %rcx
    movq   (%rcx), %rax
    testq  %rax, %rax
    je     0x5a404                    ; <+41>
    xorl   %eax, %eax
    xchgq  %rax, (%rcx)
    testq  %rax, %rax
    jne    0x5a427                    ; <+76>
    xorl   %eax, %eax
    callq  0x8017c                    ; symbol stub for: _tlv_exit
    xorl   %edi, %edi
    callq  0x5a196                    ; __cxa_finalize
    movq   0x268354f7(%rip), %rax
    testq  %rax, %rax
    je     0x5a420                    ; <+69>
    callq  *%rax
    movl   %ebx, %edi
    callq  0x8000e                    ; symbol stub for: __exit
    callq  *%rax
    ud2

还有这个

_tlv_exit:
    pushq  %rbp
    movq   %rsp, %rbp
    pushq  %rbx
    pushq  %rax
    movq   0x268db5e9(%rip), %rdi
    callq  0x2e92a                    ; symbol stub for: pthread_getspecific
    testq  %rax, %rax
    je     0x18e20                    ; <+54>
    movq   %rax, %rbx
    movq   0x268db5d5(%rip), %rdi
    xorl   %esi, %esi
    callq  0x2e942                    ; symbol stub for: pthread_setspecific
    movq   %rbx, %rdi
    addq   $0x8, %rsp
    popq   %rbx
    popq   %rbp
    jmp    0x1983e                    ; tlv_finalize_list
    addq   $0x8, %rsp
    popq   %rbx
    popq   %rbp
    retq
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop


start:
    nop
    movl   %eax, %edi
    callq  0x2e82e                    ; symbol stub for: exit
    hlt
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop


exit:
    jmpq   *0x268c241c(%rip)


pthread_getspecific:
    jmpq   *0x268c2470(%rip)


__cxa_finalize_ranges:
    pushq  %rbp
    movq   %rsp, %rbp
    pushq  %r15
    pushq  %r14
    pushq  %r13
    pushq  %r12
    pushq  %rbx
    subq   $0x18, %rsp
    movl   %esi, -0x2c(%rbp)
    movq   %rdi, -0x38(%rbp)
    leaq   0x26834d24(%rip), %rdi
    callq  0x804d6                    ; symbol stub for: pthread_mutex_lock
    movq   0x26834ca0(%rip), %r13
    testq  %r13, %r13
    je     0x5a17c                    ; <+383>
    movl   -0x2c(%rbp), %ebx
    addq   $0x8, -0x38(%rbp)
    movslq 0x8(%r13), %r15
    testq  %r15, %r15
    jle    0x5a16f                    ; <+370>
    decq   %r15
    movq   %r15, %r14
    shlq   $0x5, %r14
    movl   0x10(%r13,%r14), %r12d
    testl  %r12d, %r12d
    je     0x5a03d                    ; <+64>
    cmpl   $0x0, -0x2c(%rbp)
    je     0x5a102                    ; <+261>
    cmpl   $0x1, %r12d
    je     0x5a0a4                    ; <+167>
    cmpl   $0x3, %r12d
    je     0x5a0d1                    ; <+212>
    cmpl   $0x2, %r12d
    jne    0x5a102                    ; <+261>
    movq   0x28(%r13,%r14), %rax
    movq   -0x38(%rbp), %rcx
    xorl   %edx, %edx
    movq   -0x8(%rcx), %rsi
    cmpq   %rax, %rsi
    ja     0x5a096                    ; <+153>
    addq   (%rcx), %rsi
    cmpq   %rax, %rsi
    ja     0x5a102                    ; <+261>
    incq   %rdx
    addq   $0x10, %rcx
    cmpq   %rbx, %rdx
    jb     0x5a085                    ; <+136>
    jmp    0x5a03d                    ; <+64>
    movq   0x18(%r13,%r14), %rax
    movq   -0x38(%rbp), %rcx
    xorl   %edx, %edx
    movq   -0x8(%rcx), %rsi
    cmpq   %rax, %rsi
    ja     0x5a0c0                    ; <+195>
    addq   (%rcx), %rsi
    cmpq   %rax, %rsi
    ja     0x5a102                    ; <+261>
    incq   %rdx
    addq   $0x10, %rcx
    cmpq   %rbx, %rdx
    jb     0x5a0af                    ; <+178>
    jmp    0x5a03d                    ; <+64>
    movq   0x18(%r13,%r14), %rax
    movq   0x10(%rax), %rax
    movq   -0x38(%rbp), %rcx
    xorl   %edx, %edx
    movq   -0x8(%rcx), %rsi
    cmpq   %rax, %rsi
    ja     0x5a0f1                    ; <+244>
    addq   (%rcx), %rsi
    cmpq   %rax, %rsi
    ja     0x5a102                    ; <+261>
    incq   %rdx
    addq   $0x10, %rcx
    cmpq   %rbx, %rdx
    jb     0x5a0e0                    ; <+227>
    jmp    0x5a03d                    ; <+64>
    leaq   0x10(%r13,%r14), %rax
    movl   $0x0, (%rax)
    movb   $0x0, 0x26834b94(%rip)
    leaq   0x26834c25(%rip), %rdi
    callq  0x804e2                    ; symbol stub for: pthread_mutex_unlock
    cmpl   $0x1, %r12d
    je     0x5a13e                    ; <+321>
    cmpl   $0x3, %r12d
    je     0x5a145                    ; <+328>
    cmpl   $0x2, %r12d
    jne    0x5a14d                    ; <+336>
    movq   0x20(%r13,%r14), %rdi
    callq  *0x18(%r13,%r14)
    jmp    0x5a14d                    ; <+336>
    callq  *0x18(%r13,%r14)
    jmp    0x5a14d                    ; <+336>
    movq   0x18(%r13,%r14), %rdi
    callq  *0x10(%rdi)
    leaq   0x26834bec(%rip), %rdi
    callq  0x804d6                    ; symbol stub for: pthread_mutex_lock
    cmpb   $0x0, 0x26834b48(%rip)
    je     0x5a03d                    ; <+64>
    movq   0x26834b5b(%rip), %r13
    jmp    0x5a173                    ; <+374>
    movq   (%r13), %r13
    testq  %r13, %r13
    jne    0x5a039                    ; <+60>
    leaq   0x26834bbd(%rip), %rdi
    addq   $0x18, %rsp
    popq   %rbx
    popq   %r12
    popq   %r13
    popq   %r14
    popq   %r15
    popq   %rbp
    jmp    0x804e2                    ; symbol stub for: pthread_mutex_unlock


__cxa_finalize:
    testq  %rdi, %rdi
    je     0x5a1c5                    ; <+47>
    pushq  %rbp
    movq   %rsp, %rbp
    subq   $0x10, %rsp
    leaq   -0x10(%rbp), %rax
    movq   %rdi, (%rax)
    movq   $0x1, 0x8(%rax)
    movq   %rax, %rdi
    movl   $0x1, %esi
    callq  0x59ffd                    ; __cxa_finalize_ranges
    addq   $0x10, %rsp
    popq   %rbp
    retq
    xorl   %edi, %edi
    xorl   %esi, %esi
    jmp    0x59ffd                    ; __cxa_finalize_ranges


exit:
    pushq  %rbp
    movq   %rsp, %rbp
    pushq  %rbx
    pushq  %rax
    movl   %edi, %ebx
    cmpl   $0xad, %edi
    jne    0x5a404                    ; <+41>
    leaq   0x2683a31e(%rip), %rcx
    movq   (%rcx), %rax
    testq  %rax, %rax
    je     0x5a404                    ; <+41>
    xorl   %eax, %eax
    xchgq  %rax, (%rcx)
    testq  %rax, %rax
    jne    0x5a427                    ; <+76>
    xorl   %eax, %eax
    callq  0x8017c                    ; symbol stub for: _tlv_exit
    xorl   %edi, %edi
    callq  0x5a196                    ; __cxa_finalize
    movq   0x268354f7(%rip), %rax
    testq  %rax, %rax
    je     0x5a420                    ; <+69>
    callq  *%rax
    movl   %ebx, %edi
    callq  0x8000e                    ; symbol stub for: __exit
    callq  *%rax
    ud2


_tlv_exit:
    jmpq   *0x2680cbd6(%rip)


pthread_getspecific:
    movq   %gs:(,%rdi,8), %rax
    retq

【问题讨论】:

  • 这是“如何读取程序集输出?”如果是这样,您需要查看您正在为其编译的 ISA 的文档(例如 x86_64 或 x86)。
  • "disassembly" 不是文件名,它是调试器在没有高级源代码时所做的事情。 (相反,它向您显示机器代码的文本表示;总是有机器代码,因为那是 CPU 运行的内容。您可以要求调试器向您展示任何功能的反汇编,而不是高级源代码。)
  • 这不是必须的,但是如果你试图找出一个棘手的性能问题,你会经常想要查看汇编输出,看看编译器是否做你认为它正在做的事情。这是一种更高级的东西,除非你正在编写性能关键的代码,并且你正在将一些东西从纳秒中缩短,否则它不太可能是重要的。
  • @sK500:调试器本身不会运行您的代码,它只是在内核和 CPU 硬件的帮助下在单独的进程中控制它的执行单步/断点。您可以通过 asm 指令 (GDB stepi / si) 或源代码行 (GDB step / s) 单步执行。在编译器将您的高级源代码转换为机器代码之前,它根本无法运行,但调试信息会告诉调试器机器代码中的哪个位置代表新源代码行的块的开始。 (调试版本就是这么简单,比如gcc -O0,否则来自不同语句的代码可能会混合在一起。)

标签: c++ assembly x86-64 disassembly


【解决方案1】:

程序集输出只是编译器生成的可执行代码的转储,但以人类可读的形式1。这实际上并没有被编译器使用,它只是编译过程的一个工件,供参考。

请记住,已编译的可执行文件可以随时转换为汇编代码,IDA ProGhidra 等工具擅长对任何可执行文件执行此操作,但编译器可以添加在最终编译阶段丢失的上下文信息以 cmets 或对事物有用的标签的形式。

编译器通常会为您编译的可执行文件发出调试提示,以便它可以将堆栈跟踪转换为映射回原始源代码的内容。这些工件更有用,因为它们允许您单步执行 C++ 代码而不是汇编代码。如果您不得不在没有源代码的库中进行调试,那么您将无法通过可执行代码的汇编视图进行单步调试。


1 假设您可以阅读assembly code

【讨论】:

  • 谢谢,这很有帮助,我会检查这些说明的含义
【解决方案2】:

您发布的代码是来自您的 libc 运行时的支持代码。除其他外,运行时负责:

  • 实现 atexit 挂钩;
  • 设置 IO 流(cin、cout);
  • 运行任何全局静态变量的构造函数。

This answer 有更完整的概述。您可以搜索有关 libc_start_main 和相关函数的文章以了解更多信息。

【讨论】:

    猜你喜欢
    • 2015-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    • 2017-08-25
    • 2019-12-09
    • 1970-01-01
    • 2021-11-23
    相关资源
    最近更新 更多