OSX 64位C ++ DIsassembly逐行

时间:2013-02-22 22:26:15

标签: c++ assembly disassembly

我一直在阅读以下系列文章:http://www.altdevblogaday.com/2011/11/09/a-low-level-curriculum-for-c-and-c

显示的反汇编代码和我在运行相同代码时设法生成的反汇编代码差异很大,而我缺乏解释差异的理解。

是否有人可以逐行逐步介绍它并解释它在每一步中的作用?我从搜索中得到的感觉我已经完成了前几行与帧指针有关,在我的反汇编代码中似乎还有一些额外的行,以确保寄存器在将新值放入其中之前是空的(不存在)来自文章中的代码)

我在OSX上运行此操作(原作者正在使用Windows),使用XCode 4中的g ++编译器。我真的很不知道是否天气这些差异是由于OS,架构(32位对64位)也许?)或编译器本身。它甚至可能是我猜的代码 - 我的代码包含在main函数声明中,而原始代码却没有提到它。

我的代码:

int main(int argc, const char * argv[])
{

    int x = 1;
    int y = 2;
    int z = 0;

    z = x + y;

}

我的反汇编代码:

0x100000f40:  pushq  %rbp
0x100000f41:  movq   %rsp, %rbp
0x100000f44:  movl   $0, %eax
0x100000f49:  movl   %edi, -4(%rbp)
0x100000f4c:  movq   %rsi, -16(%rbp)
0x100000f50:  movl   $1, -20(%rbp)
0x100000f57:  movl   $2, -24(%rbp)
0x100000f5e:  movl   $0, -28(%rbp)
0x100000f65:  movl   -20(%rbp), %edi
0x100000f68:  addl   -24(%rbp), %edi
0x100000f6b:  movl   %edi, -28(%rbp)
0x100000f6e:  popq   %rbp
0x100000f6f:  ret    

原始文章中的反汇编代码:

mov    dword ptr [ebp-8],1
mov    dword ptr [ebp-14h],2
mov    dword ptr [ebp-20h],0
mov    eax, dword ptr [ebp-8]
add    eax, dword ptr [ebp-14h]
mov    dword ptr [ebp-20h],eax

完整的逐行细分将极具启发性,但理解这一点的任何帮助都将受到赞赏。

3 个答案:

答案 0 :(得分:2)

原始文章中的所有代码都在您的代码中,其中只有一些额外的东西。这样:

0x100000f50:  movl   $1, -20(%rbp)
0x100000f57:  movl   $2, -24(%rbp)
0x100000f5e:  movl   $0, -28(%rbp)
0x100000f65:  movl   -20(%rbp), %edi
0x100000f68:  addl   -24(%rbp), %edi
0x100000f6b:  movl   %edi, -28(%rbp)

直接对应于文章中提到的6条指令。

答案 1 :(得分:0)

首先,列为“来自原始文章”的汇编程序使用“Intel”语法,其中您的帖子中的“反汇编输出”是“AT& T语法”。这解释了指令的参数顺序是“回到前面”[让我们不争论哪个是对还是错,好吗?],并且寄存器名称以%为前缀,常量前缀为$ 。引用寄存器的存储位置/偏移的方式也有所不同 - 英特尔汇编程序中的dword ptr [reg+offs]转换为l作为指令的后缀,offs(%reg)

32位与64位重命名一些寄存器 - %rbp与文章代码中的ebp相同。

实际的偏移量(例如-20)是不同的,部分原因是寄存器在64位中更大,但也因为你有argcargv作为函数参数的一部分,这是作为函数开始的一部分存储的 - 我感觉原始文章实际上是在拆解与main不同的函数。

答案 2 :(得分:0)

您的反汇编代码与文章代码之间存在两个主要差异。

一个是本文使用的是英特尔汇编语法,而您的反汇编代码则使用传统的Unix / AT& T汇编语法。 Wikipedia上记录了两者之间的一些差异。

另一个区别是文章省略了设置堆栈帧的函数序言,以及函数结尾,它破坏了堆栈帧并返回给调用者。他拆解的程序必须包含执行这些操作的说明,但他的反汇编程序并没有显示它们。 (实际上堆栈帧可以,如果启用了优化器,可能会省略,但显然没有启用。)

还存在一些细微差别:您的代码对局部变量使用略微不同的布局,而您的代码在另一个寄存器中计算总和。

在Mac上,g ++不支持发出英特尔助记符,但是clang确实:

:; clang -S -mllvm --x86-asm-syntax=intel t.c
:; cat t.s
    .section    __TEXT,__text,regular,pure_instructions
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
## BB#0:
    push    RBP
Ltmp2:
    .cfi_def_cfa_offset 16
Ltmp3:
    .cfi_offset rbp, -16
    mov RBP, RSP
Ltmp4:
    .cfi_def_cfa_register rbp
    mov EAX, 0
    mov DWORD PTR [RBP - 4], EDI
    mov QWORD PTR [RBP - 16], RSI
    mov DWORD PTR [RBP - 20], 1
    mov DWORD PTR [RBP - 24], 2
    mov DWORD PTR [RBP - 28], 0
    mov EDI, DWORD PTR [RBP - 20]
    add EDI, DWORD PTR [RBP - 24]
    mov DWORD PTR [RBP - 28], EDI
    pop RBP
    ret
    .cfi_endproc


.subsections_via_symbols

如果添加-g标志,编译器将添加调试信息,包括源文件名和行号。它太大了,不能完全放在这里,但这是相关的部分:

    .loc    1 4 14 prologue_end     ## t.c:4:14
Ltmp5:
    mov DWORD PTR [RBP - 20], 1
    .loc    1 5 14                  ## t.c:5:14
    mov DWORD PTR [RBP - 24], 2
    .loc    1 6 14                  ## t.c:6:14
    mov DWORD PTR [RBP - 28], 0
    .loc    1 8 5                   ## t.c:8:5
    mov EDI, DWORD PTR [RBP - 20]
    add EDI, DWORD PTR [RBP - 24]
    mov DWORD PTR [RBP - 28], EDI