【问题标题】:Assembly - Why this CALL function doesn't work?汇编 - 为什么这个 CALL 函数不起作用?
【发布时间】:2016-09-06 14:10:46
【问题描述】:

我不明白为什么这段代码中的 CALL 函数不起作用:

#include<stdio.h>

void main() {

    __asm {

        jmp L1

        L2:
        mov eax, 8
        ret

        L1:
        call L2
    }
}

如果我一步步调试代码,'call L1'这一行没有被处理,程序直接跳到最后。怎么了?我正在使用 Intel 32 位寄存器开发 VisualStudio2015。

【问题讨论】:

  • 调试器经常不能完全理解内联汇编。是否有可能代码正在正确执行但调试器无法正确跟踪它?您可以通过在jmp L1 之前将EAX 设置为8 以外的值,然后在call L2 之后检查它的值来找出答案。在您的代码中执行此操作,而不是从调试器中执行此操作。
  • 另外,如果您要编写这样的代码,请考虑使用独立的 .asm 文件,而不是插入到 C 函数中的“内联汇编”。这不太可能与编译器发生冲突。 (具体来说,如果您使用call,或者在程序集插入中移动堆栈指针,编译器通常会非常非常困惑。)
  • 还可以查看编译器创建的最终二进制文件的反汇编。分支是去你期望的地方,还是编译器编译错了?
  • 您是否有可能只是错误地使用了调试器并使用 F10 来跳过而不是 F11 来进入调用?我想发生了对 L2 的调用,但是您没有进入 L2 函数以逐条执行它。
  • @CodyGray :如果您假设他们使用跨步而不是步入,则可以重现。从 OP 的角度来看,呼叫似乎没有发生(即使发生了)。我认为这正是问题所在。

标签: debugging assembly call


【解决方案1】:

问题
你偶然发现了step over F10 and step into F11. 之间的区别

当您使用(默认)step over 时,call 似乎被忽略了。
您需要step into 代码,然后调试器将按照您的预期运行。

跳过
这与step over 一起工作的方式是调试器在下一条指令上设置一个断点,在那里暂停并再次将断点移动到下一条指令。
Step over 知道(条件)跳转并解释了这一点,但是忽略(跳过)调用语句;它将call 解释为跳转到另一个子例程并“假设”您希望留在当前上下文中。
这些自动断点是短暂的,不像手动断点会一直持续到您取消它们。

步入
Step into 做同样的事情,但也在每个呼叫目的地设置断点;实际上会引导您深入森林,遍历每个子程序。

走出去
如果您使用 ShiftF11 已经“进入”子程序 Visual Studio allows you to step out 太深;这将带您回到初始调用后的下一条指令。
其他一些调试器将此功能命名为“运行直到返回”。

调试高级代码
当调试器处理高级语言源代码(例如 C)时,它会为每一行源代码保留一个目标地址列表。它将计划每行源代码的断点。
除了每一行高级代码都转换为零或多行汇编之外,它的工作方式与单步执行原始汇编代码相同。

【讨论】:

  • 也许您可以多描述一下两者之间的区别。由于跨步试图在当前指令之后放置断点,而不对其进行检查(指令=高级语言中的命令行)。 Step-into 会首先分析当前行,如果涉及到一些调用,它会在其中设置断点(无论是高层调用,还是在 ASM 中直接call 都可以考虑)。调试器通常还有“Step-out”,它将继续执行当前代码,直到它超出当前范围(ASM 中的“RET”),如果您不小心将“step-into”过深,它会很方便。跨度>
  • 对于汇编语言,您可能需要“单步指令”而不是上述任何一种。我无法从文档中判断这是否可以使用 Visual Studio,但它does appear to be possible with WinDbg
猜你喜欢
  • 1970-01-01
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 2015-08-21
  • 2021-10-28
相关资源
最近更新 更多