2012-02-09 195 views
0

我正在阅读一本C语言书,它很多内容都与asm有关,并且正在用GDB来查看寄存器和内存。 问题是,当我编译和反汇编完全相同的源文件(实际上使用cd书附带的源文件)时,汇编指令看起来与本书中的内容有很大不同。 这本书使用英特尔风味的大会,我把“集拆卸英特尔”在gdb,所以它不是..只是说明是在不同的顺序,有些都在一起不同,还有一些其他的怪癖。gdb的奇怪结果

例如,在该书中有EIP寄存器MOV指令:对应于初始化变量i为0,在for循环中

(gdb) x/i $eip 
mov DWORD PTR[ebp-4], 0x0 

(I = 0,I < 10,I ++ )

然而,在我的GDB控制台,与在同一个地方断点(设置打破为主;运行)我看到这一点:

(gdb) x/i $eip 
mov DWORD PTR[esp+0x1c], 0x0 

察觉到它的引用不同的瑞吉如果我检查esp的值,它本身就是0x1c,而不是ebp 。但是,如果我尝试检查0x1c或者esp + 0x1c处的内容,它告诉我我无法查看这些地址

因此,随着本书的继续,我无法遵循,因为它开始跟踪ebp,ebp-4等内容的踪迹,并且在我的asm中,ebp寄存器似乎没有任何事情发生。该书写于2008年,所以我不能想象它如此过时以至于gcc或gdb的版本更改会引入显着的更改(或者做到了这一点?)......是否有可能存在一些编译器优化或默认情况下打开的某些内容会产生这样的不同结果?

在此先感谢

编辑:奇怪。我尝试了每个建议,但没有成功。然后我做了a.out并重新编译为新的,现在它工作正常(指令与本书不同,但我可以查看与本书相对应的地址;只要我可以遵循相应的模式,一切都很好,不必是完全相同的asm,这只会让它太容易!) 再次感谢您的所有帮助和建议。

回答

0

这将是非常平台和编译器特定的。恐怕没有什么可以做的了。

+0

谢谢。本书使用的是32位英特尔版本,我都是用gcc编译的(我需要检查版本并更新qeustion),运行linux。本书基于Ubuntu(同样需要检查版本),我正在运行最新的Arch安装。 我会假设与相同的体系结构和相同的编译器(gcc)的机器代码将是相同的没有? 无论哪种方式,我觉得奇怪的是,一个值正在被初始化到我无法检查的地址,也奇怪它被$ esp引用,即堆栈指针... – speakingcode 2012-02-09 05:11:06

+1

不,没有理由它应该是相同的。你可以用'-O0'或'-march = i386'来玩。但这完全不同,这并不奇怪。 – 2012-02-09 05:14:01

1

有一百万件事情可能导致这种情况。如果你在不同的体系结构上编译你的代码,我期望这样做(并且不,这并不一定意味着32位和64位 - 实际上,任何不同的CPU体系结构都可以改变执行顺序,我将会解释) 。如果您通过优化来编译程序,它将改变执行顺序以最好地利用CPU的管道。这可能意味着添加一些NOOP指令,或者完全重新排序(当然是在合理范围内)。另外一些CPU有多种处理方式,一种方式通常比另一种处理速度快(intel LOOP指令出现在脑海中 - 现代编译器避免像鼠疫这样的指令,因为它很糟糕)。如果一个寄存器比另一个更有效,它将使用它。

故事的寓意:出于学习的目的,作者和读者都需要禁用所有优化。另外为了增加积分:使用相同版本的gcc和相同的平台。

+0

感谢您的洞察力。这就是我想知道的,我怎么能不强制优化。我明白,确切的内存地址,甚至指令可能因体系结构而异,这是编译器的重点,但我只是感到惊讶,它有很大的不同 - 即使在asm似乎是一个不同的程序(它是一起的没有什么,但一个for循环主要是非常简单的遵循) 真的,虽然问题是说价值初始化在我无法检查(esp + 0x1c),不应该是这样的地址 – speakingcode 2012-02-09 07:21:02

+0

@rootlicker 'gcc -O0'(这是字母O后跟数字0) – 2012-02-09 15:09:07

1

它看起来像你编译的代码编译为-fomit-frame-pointers,这成为GCC-4.6的默认值。

尝试用明确的-fno-omit-frame-pointer构建。我希望结果会更接近这本书。