我刚刚开始在win32上学习一些x86程序集,并且我使用masm和visual studio 2008一起使用了.asm文件的ide附带的自定义构建规则。我一直在尝试使用DOS中断打印到控制台,但我收到消息:“ASMTest.exe中0x00401004处的未处理异常:0xC0000005:访问冲突读取位置0xffffffff。”在8号线。我正在尝试输出单个ascii字符'A'(41h)这是masm代码:

.386
.MODEL flat, stdcall

.CODE
start:
    mov dl, 41h
    mov ah, 2
    int 21h
    ret
end start

当我使用debug.exe并使用'a'命令输入所有.CODE指令并运行它('g')时,它可以正常工作。

任何人都可以告诉我如何正确使用DOS中断?谢谢!

编辑:在win32上编程时,Managu是正确的,你应该使用像WriteConsoleA这样的Windows api调用,而不是使用DOS中断。 是一个有用的资源。如果有人正在寻找代码来执行此操作(就像我一样),这里是:

.386
.MODEL flat, stdcall

; Windows API prototypes
GetStdHandle proto :dword
WriteConsoleA proto :dword, :dword, :dword, :dword, :dword
ExitProcess proto :dword

STD_OUTPUT_HANDLE equ -11

.DATA
HelloWorldString db "hello, world", 10, 0

.CODE

strlen proc asciiData:dword
    ; EAX used as count, EBX as ascii char pointer, EDX (DL) as ascii char
    mov eax, -1
    mov ebx, asciiData
    mov edx, 0

    BeginLoop:
    inc eax       ; ++count (init is -1)
    mov dl, [ebx] ; *dl = *asciiptr
    inc ebx       ; ++asciiptr
    cmp dl, 0     ; if (*dl == '\0')
    jne BeginLoop ; Goto the beginning of loop

    ret
strlen endp

main proc
    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov ecx, eax
    invoke strlen, addr HelloWorldString
    invoke WriteConsoleA, ecx, addr HelloWorldString, eax, 0, 0
    ret
main endp

end

(将入口点设置为main)

有帮助吗?

解决方案

当您使用debug.exe输入此代码时,您正在组装一个16位(8086架构,“实模式”)dos程序。您指定的语义对于此类程序是正确的。但是,当您组装使用MASM的程序,然后链接它时,您正在尝试创建一个32位(i386体系结构,“保护模式”)Windows程序。我可能会弄错,但在后一种情况下,我认为你甚至不能合法地调用21h。

其他提示

由于你的'ret'指令,它可能会发生。你要回到哪里?我想,在记忆中有一些不为人知的地方。

相反,尝试使用int 20h。那将“优雅地”退出。

它在调试中工作(可能),因为这是一个更“管理”的部分。环境。

如果我们启动一个16位DOS - * .com应用程序,那么DOS填充“int 20”的操作码。我们的PSP内部的偏移量为0的指令和额外的DOS在我们的堆栈上推送一个字为零,然后DOS让我们的应用程序执行。所以我们可以放一个简单的“ret”。我们的代码末尾的指令。但是我们必须确保我们的堆栈指针没有被破坏,我们的代码段也没有改变。

为了使用MASM 6+链接16位应用程序,我们需要一个16位链接器。

ftp://ftp.microsoft.com/softlib/mslfiles/lnk563.exe

德克

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top