我一直在通读以下系列文章:http://www.altdevblogaday.com/2011/11/09/a-low-level-curriculum-for-c-and-c
显示的反汇编代码和我在运行相同代码时生成的反汇编代码有很大的不同,我缺乏对这些差异的理解。
有没有人可以一行一行地介绍它,也许可以解释它在每一步中做了什么?从我所做的搜索中,我感觉到前几行与帧指针有关,在我的反汇编代码中似乎也有一些额外的行,以确保在将新值放入寄存器之前是空的(在本文的代码中没有)。
我使用XCode 4中的g++编译器在OSX (原作者使用的是Windows)上运行这个程序。我真的不知道这些差异是否是由于操作系统、架构(32位vs64位可能?)或者编译器本身。我猜它甚至可能是代码--我的代码包装在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完整的逐行分解将非常有启发性,但对理解这一点的任何帮助都将不胜感激。
发布于 2013-02-23 06:41:17
您的反汇编代码和本文的代码之间有两个主要区别。
其一,本文使用的是Intel汇编语法,而反汇编代码使用的是传统的Unix/AT&T汇编语法。在Wikipedia上记录了两者之间的一些差异。
另一个不同之处在于,本文省略了设置堆栈框架的函数prologue和销毁堆栈帧并返回给调用者的函数epilogue。他反汇编的程序必须包含做这些事情的指令,但是他的反汇编程序没有显示这些指令。(实际上,如果启用了优化器,堆栈帧可能会被省略,但显然没有启用。)
还有一些细微的差异:您的代码对局部变量使用的布局略有不同,并且您的代码在不同的寄存器中计算总和。
在苹果电脑上,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发布于 2013-02-23 06:29:53
原始文章中的所有代码都在您的代码中,只是周围有一些额外的东西。这一点:
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个说明。
发布于 2013-02-23 06:36:36
首先,“出自原始文章”的汇编程序使用的是"Intel“语法,而你的帖子中的”反汇编输出“是"AT&T语法”。这解释了指令的参数顺序是“从后到前”,让我们不要争论哪一个是对的或错的,好吗?,寄存器名称的前缀是%,常量的前缀是$。在引用寄存器的内存位置/偏移量的方式上也存在差异-英特尔汇编程序中的dword ptr [reg+offs]转换为l作为指令的后缀,而offs(%reg)。
32位与64位重命名了一些寄存器- %rbp与文章代码中的ebp相同。
实际的偏移量(例如-20)是不同的,部分原因是64位的寄存器更大,还因为你将argc和argv作为函数参数的一部分,这些参数作为函数开头的一部分存储-我有一种感觉,原来的文章实际上是在反汇编一个不同于main的函数。
https://stackoverflow.com/questions/15034247
复制相似问题