题
我刚刚开始在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
德克