【问题标题】:Visual Studio only breaks on second line of assembly?Visual Studio 只在装配的第二行中断?
【发布时间】:2012-10-26 02:45:14
【问题描述】:

简短说明:

在汇编程序中我的.CODE 段的第一行设置断点不会停止程序的执行。

问题:

Visual Studio 的调试器会导致它无法在用汇编语言编写的程序的第一行创建断点怎么办?这是调试器的一些奇怪之处,多字节指令中断的情况,还是我只是在做一些愚蠢的事情?

详情:

我在 Visual Studio 中编译并运行了以下汇编程序:

; Tell MASM to use the Intel 80386 instruction set.
.386
; Flat memory model, and Win 32 calling convention
.MODEL FLAT, STDCALL
; Treat labels as case-sensitive (required for windows.inc)
OPTION CaseMap:None

include windows.inc
include masm32.inc
include user32.inc
include kernel32.inc
include macros.asm

includelib masm32.lib
includelib user32.lib
includelib kernel32.lib

.DATA
    BadText     db      "Error...", 0
    GoodText    db      "Excellent!", 0

.CODE
main PROC
        ;int 3           ; <-- If uncommented, this will not break.
        mov ecx, 6       ; <-- Breakpoint here will not hit.
        xor eax, eax     ; <-- Breakpoint here will.
_label: add eax, ecx
        dec ecx
        jnz _label
        cmp eax, 21
        jz _good
_bad:   invoke StdOut, addr BadText
        jmp _quit
_good:  invoke StdOut, addr GoodText
_quit:  invoke ExitProcess, 0
main ENDP
END main

如果我尝试在 main 函数的第一行设置断点,mov ecx, 6,它会被忽略,程序会不停地执行。如果我将断点设置在之后的行 xor eax, eax 或任何后续行上,才会触发断点。

我什至尝试在函数的第一行插入一个软件断点int 3,它也被忽略了。

我注意到的第一件事很奇怪:在遇到我的一个断点后查看反汇编给了我以下信息:

01370FFF  add         byte ptr [ecx+6],bh  
--- [Path]\main.asm 
        xor eax, eax
00841005  xor         eax,eax  --- <-- Breakpoint is hit here
_label: add eax, ecx
00841007  add         eax,ecx  
        dec ecx
00841009  dec         ecx  
        jnz _label
0084100A  jne         _label (841007h)  
        cmp eax, 21
0084100C  cmp         eax,15h  

这里有趣的是,xor 在 Visual Studio 眼中是我程序中的第一个操作。缺少的是move ecx, 6 行。它认为我的源代码开始的正上方是实际将ecx 设置为 6 的行。因此,我的程序的实际启动已根据反汇编进行了破坏。

如果我将程序的第一行设为int 3,则反汇编代码中出现在上面的行是:

00F80FFF  add         ah,cl

正如其中一个答案所建议的,我关闭了ASLR,看起来反汇编更稳定了一些:

.CODE
main PROC
        ;mov ecx, 6
        xor eax, eax
00401000  xor         eax,eax  --- <-- Breakpoint is present here, but not hit.
_label: add eax, ecx
00401002  add         eax,ecx  --- <-- Breakpoint here is hit.
        dec ecx
00401004  dec         ecx  

在反汇编中可以看到完整的程序,但问题仍然存在。尽管我的程序从预期的地址开始,并且在反汇编中显示了第一个断点,但它仍然被跳过。将int 3 作为第一行仍然会导致以下行:

00400FFF  add         ah,cl  

并且不会停止执行,and 再次在反汇编中重新破坏我的程序的视图。然后我程序的下一行位于位置00401001,我认为这是有道理的,因为int 3 是一个单字节指令,但为什么它会在反汇编中消失?

即使使用“Step Into (F11)”命令启动程序也不允许我在第一行中断。事实上,没有断点,用 F11 启动程序根本不会停止执行。

除了我在这里详细介绍的内容之外,我不确定我还能尝试什么来解决这个问题。这超出了我目前对汇编和调试器的理解。

【问题讨论】:

  • "int 3" 和 "int3" 是两条不同的指令 - 试试后者(它是一个字节)。在 Linux 中,将“nop”作为文件中的第一件事有时会很有帮助。不同的情况,但在这里也可能有帮助(?)。
  • 看起来您更改了代码但没有重新构建 :) 您是否尝试重新构建然后设置断点?
  • @FrankKotler 感谢您的建议,但int3 是 MASM 中的语法错误。 int 3 绝对是英特尔平台的正确指令。
  • @OhadHoresh 构建是最新的。如果不是因为源代码已经过时,我将无法达到任何断点。
  • 如果您取消选中(调试选项)中的选项(要求源文件与原始版本完全匹配),您将能够使用过时的源代码打断点。跨度>

标签: visual-studio-2010 assembly masm


【解决方案1】:

01370FFF 添加字节 ptr [ecx+6],bh

至少我可以解释一个谜。注意地址,0x1370fff。 CODE 段永远不会从这样的地址开始,段开始于 0x1000 的倍数的地址。这使得起始地址的最后 3 个十六进制数字始终为 0。调试器感到困惑并开始反汇编错误地址处的代码,减一。实际起始地址为 0x1371000。反汇编开始很糟糕,因为 0x1370fff 处有一个 0。那是一条多字节的 ADD 指令。所以它会显示一段时间的垃圾,直到它偶然赶上真正的机器代码指令。

你需要帮助它,并给它一个命令,在正确的地址开始反汇编。在 VS 的地址框中,输入“0x1371000”。

另一个值得注意的怪癖是起始地址的奇怪值。进程通常从地址 0x400000 开始。您启用了一项名为 ASLR 的功能,即地址空间布局随机化。它是一种防病毒功能,可以使程序从不可预知的起始地址开始。不错的功能,但它并不能完全帮助调试程序。目前尚不清楚您是如何构建此代码的,但您需要 /DYNAMICBASE:NO 链接器选项将其关闭。

您需要记住的另一个重要的调试器怪癖是它们设置断点的方式。他们通过修补代码来做到这一点,将指令的起始字节替换为int 3 指令。当断点命中时,它会迅速用原始机器代码指令字节替换该字节。所以你永远不会看到这个。如果你选择了错误的地址来设置断点,就会出错,比如在多字节指令的中间。它现在不再破坏代码,改变的字节弄乱了原始指令。当你从一个糟糕的反汇编开始时,你很容易落入这个陷阱。

好吧,这样做是正确的方式。改为使用调试器的 STEP 命令开始调试。

【讨论】:

  • 对程序的起始地址感兴趣。我已经尝试了您的建议并更新了我的问题。取得了一些进展,但 VS 仍然不会在第一行遇到断点。
  • 我仍然无法在程序的第一行中断,但您的回答给出了可能导致问题的最佳描述。赏金是你的,除非有明确的答案,否则我会接受。
【解决方案2】:

我发现了问题的根源,但我不知道为什么会这样。

创建另一个 MASM 项目后,我注意到新项目在程序的第一行中断,并且反汇编似乎没有被破坏或更改。因此,我将其属性与我的原始项目(用于调试配置)进行了比较。我发现的唯一区别是我的原始项目禁用了增量链接。具体来说,它在链接器命令行中添加了/INCREMENTAL:NO

从命令行中删除此选项(从而启用增量链接)导致程序在调试期间按预期运行;我在反汇编窗口中显示的代码保持不变,我可以在main 过程的第一行打断点,int 3 指令也将作为第一行正确执行。

【讨论】:

    【解决方案3】:

    如果您按 F+11(步入)而不是 Start Debugging,调试器将在第一行停止。

    可能存在一些混乱的断点设置。删除项目目录中的所有 *.suo 文件以重置所有断点。

    请注意,如果您的项目具有主要功能,则其中将包含秘密标头和内容。要在真正的入口点设置断点,请使用:Debug + New Breakpoint + Break at Function -> wWinMainCRTStartup 用于 windows 程序或 ma​​inCRTStartup 或 wmainCRTStartup 用于控制台程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-02
      • 1970-01-01
      • 2015-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多