何时使用汇编语言来调试C/C++程序?

5

何时使用汇编调试c/c++程序?

学习一些汇编语言有助于调试程序吗?

11个回答

7
在你无法(或尚未)可靠地重现错误时,例如由于堆栈损坏,它非常有帮助。您可能会收到一个或两个核心转储文件,很可能来自客户。即使假设您的调试器是可靠的,查看汇编代码也可以告诉您确切哪条指令导致崩溃(因此哪个内存片段已被损坏)。
此外,在我的经验中(主要用于内核调试),调试器在处理优化代码方面相对较差。它们会将参数等东西搞错,为了真正了解发生了什么,我需要查看反汇编代码。
如果我可以可靠/轻松地重现问题,那么处理反汇编代码通常不会像处理程序一样有所帮助,因为我会通过单步执行程序获得更多信息。另一方面,达到可以重现问题的程度通常已经超过了解决问题的一半。

抢我先说了,而且说得更好。 - Dipstick

3
我猜您在询问何时使用反汇编来调试您的C/C++代码。
有些情况下,您会怀疑编译器未按您所需生成代码。通常,当优化版本的可执行文件无法正常运行,但未经优化的形式却能够正常工作时,您需要检查反汇编以查看哪些优化改变了行为。
另一种情况是当您想要了解可执行文件的行为,但没有源代码可用于开始时,这被称为逆向工程。您只能使用可执行文件的反汇编进行操作。 反汇编和分析工具 的维基参考,可帮助您了解工具并开始学习最适合您环境的工具。

3

我无法告诉你“何时”,但有时候你可能会遇到奇怪的C/C++行为,而且你真的不知道发生了什么......只需要看一下汇编代码,它永远不会欺骗你。

但是我总是检查我的C程序的ASM代码......出于优化、好奇心和学习目的。

无论如何,都要学习x86汇编语言!


学习优化器并将其应用于自己的需求,这是一个加分项。 - diapir

2

汇编语言可以帮助调试程序的原因在于gcc经常为你进行优化。您需要查看汇编代码,以查找任何gcc的“改进”,并确保它们不会破坏程序。

例如:

/* global */
int x = 1;

void *myFunc() {
    /* do something productive */
    x = 0;
    return NULL;
} 

int main() {
    thread_create(myFunc);

    while(x) continue;

    exit(1);
}

在某些优化下,while(x) continue; 会变成 jmp 0xDEADBEEF(其中 0xDEADBEEFjmp 指令)。你可以在汇编语言中看到这一点,并知道要将 x 改为 volatile。
否则,汇编语言可能会阻碍你理解任何东西。

2

除非你怀疑编译器,否则不要降低调试的级别。最好在与算法表达意图相同的抽象级别上进行调试。

如果你用C/C++编写代码,则使用一个好的C/C++调试器。


有时候你需要从不同的角度来看待问题。而且你可以从汇编和字节码中学到很多东西。 - Matthew Whited

2

我确实已经多次回到阅读汇编代码了。GCC使得这相当方便。

一个很好的例子是我的一个问题的主题。GCC在2.95和3.4.3之间改变了行为,而查看可疑函数的汇编代码可以解释为什么我的程序会崩溃。

在某些情况下,如果您真的需要知道某些访问是如何进行的,那么它也非常有用。例如,如果您将内存映射到总线上,则可能想知道您正在执行16位访问而不是32位访问。

我最近使用汇编的另一个案例是检查我的“易失性”变量是否真正被视为易失性。结果发现几乎所有编译器有时都会出错,因此我已经开始检查特定情况的输出,以确保汇编实际上引用了内存位置而不是某个寄存器。


1

这可能有助于一些高级编程内容,并且了解“引擎盖下”发生的事情总是有帮助的。但是,除非您正在进行汇编编码(如果是这样,您会知道汇编语言),否则使用汇编调试可能过度了。错误可能直接存在于您的代码中,而不是在您的代码和汇编之间的转换中。


1
在某些情况下,您别无选择,只能退回到汇编语言。如果您的系统崩溃,而您只有一个核心转储或堆栈跟踪以及少量符号,则盯着高级源代码看是不会让您走得太远的。

核心转储或堆栈跟踪具有指向您的代码的地址,因此并不真正需要汇编。 - Gerhard
抱歉Gerhard,我不理解你的评论。如果您无法理解从C代码生成的汇编程序,那么您如何确定地址指向代码中的确切位置? - Dipstick

0

我认为使用内存转储进行调试比学习汇编语言更有用。例如,使用Visual Studio,您可以检查在特定代码行后哪些内存位置发生了变化。在调试模式下,快捷键是ALT-6。您可以使用标准监视来获取变量位置。


0

我曾经利用我的汇编技能搜索由我们使用的编译器新版本引起的错误。但编译器错误非常罕见,所以我的答案是否定的,不适用于调试。

从你的源代码中观察编译器如何通过汇编解决问题是很有趣的,但那并不是真正的调试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接