2013-02-22 51 views
0

我已通过以下一系列文章读拆卸线:http://www.altdevblogaday.com/2011/11/09/a-low-level-curriculum-for-c-and-cOSX 64位C++通过线

所示的反汇编代码和反汇编代码我管理,以产生同时运行相同的代码变化相当显著和我缺乏解释差异的理解。

有没有人可以逐行浏览它,也许可以解释它在每个步骤中做了什么?我从周围搜索中得到了感觉,我已经完成了前几行与帧指针有关的事情,在我的反汇编代码中似乎还有一些额外的行,以确保在将新值写入它们之前寄存器是空的(缺席从文章中的代码)

我在OSX(原作者使用Windows)上使用g ++编译器从XCode 4中运行此操作。我真的无法知道这些差异是由于操作系统,体系结构(32位还是64位可能?)或编译器本身。它甚至可能是我猜的代码 - 我的代码被包装在主函数声明中,而原始代码没有提到这一点。

我的代码:

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 

通过在线故障提供全系列将是非常有启发但任何帮助理解这一点,将不胜感激。

回答

0

你反汇编的代码和文章的代码有两个主要的区别。

其中之一是该文章使用英特尔汇编语法,而您的反汇编代码使用传统的Unix/AT汇编语法。两者之间的一些差异记录在Wikipedia

另一个区别是本文忽略了设置堆栈帧的函数序言和函数epilogue,它破坏了堆栈帧并返回给调用者。他正在分解的程序必须包含执行这些操作的指令,但他的反汇编程序没有显示它们。 (其实堆栈帧可如果优化已启用,可能会被忽略,但它显然不是启用。)

也有一些细微的差别:你的代码是使用局部变量稍有不同的布局,你的代码是在不同的寄存器中计算总和。

在Mac上,G ++不支持英特尔的发光助记符,但铛做:

:; 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 
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条指令。

0

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

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

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

+0

谢谢你 - 绝对清除了一些我不明白的东西!事实上,这是一个不同的语法,完全解释了许多以及你对不同偏移的看法。 – GeoffK 2013-02-22 22:43:12

+0

原文似乎很好。在x86上,'argc'和'argv'将被调用者推送,因此相对于'ebp'处于* positive *偏移量(ebp + 0是旧BP,ebp + 4是返回地址,ebp + 8是第一个参数...)。在x86_64 OSX上,前两个参数传入'rdi'(在这种情况下是'edi',因为它是一个int)和'rsi'。它看起来像是用'-O0'编译的,所以参数会立即保存到堆栈中。 – 2013-02-22 23:03:02

+0

对此不以为然 - 但我如何启用这些优化?肯定会喜欢用/不用,并且比较 – GeoffK 2013-02-22 23:05:56