Masm x86 程序集崩溃时的 DOS 中断

发布于 2024-08-04 08:51:53 字数 1554 浏览 8 评论 0原文

我刚刚开始学习 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)

I've just begun learning some x86 assembly on win32, and I've used masm with visual studio 2008 using the custom build rule that comes with the ide for .asm files. I've been trying to use the DOS interrupt to print to the console, but instead I receive the message: "Unhandled exception at 0x00401004 in ASMTest.exe: 0xC0000005: Access violation reading location 0xffffffff." on the 8th line. I'm trying to output the single ascii character 'A' (41h) Here is the masm code:

.386
.MODEL flat, stdcall

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

When I use debug.exe, and use the 'a' command to input all .CODE instructions, and run it ('g'), it works fine.

Can anyone enlighten me on how to use the DOS interrupt correctly? Thanks!

EDIT: When programming on win32, Managu is right that you should use a windows api call like WriteConsoleA instead of using the DOS interrupt. This was a helpful resource. In case anyone is looking for the code to do this (like I was), here it is:

.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

(Set the entry point to main)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

脸赞 2024-08-11 08:51:53

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

When you use debug.exe to input this code, you're assembling a 16-bit (8086 architecture, "real mode") dos program. The semantics you specify are correct for such a program. However, when you assemble the program you've got here with MASM, and then link it, you're trying to create a 32-bit (i386 architecture, "protected mode") Windows program. I could be mistaken, but I don't think you can legally even invoke int 21h in the latter case.

禾厶谷欠 2024-08-11 08:51:53

它可能是由于您的“ret”指令而发生的。你要回到哪里?我想,记忆中某个未知的地方。

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

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

It's possible that it occurs because of your 'ret' instruction. Where are you returning to? Some unknown place in memory, I imagine.

Instead, try using int 20h. That will exit "gracefully."

It works in debug (probably) because that's a more "managed" environment.

遗忘曾经 2024-08-11 08:51:53

如果我们启动一个 16 位 DOS-*.com 应用程序,那么 DOS 会在 PSP 内的偏移量 0 处填充“int 20”指令的操作码,并且在 DOS 让我们的应用程序执行之前,额外的 DOS 将一个带零的字压入我们的堆栈中。所以我们可以在代码末尾放置一个简单的“ret”指令。但我们必须确保我们的堆栈指针没有损坏并且代码段没有更改。

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

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

短剑

If we start a 16 bit DOS-*.com application, then DOS fill the opcode of an "int 20" instruction inside of our PSP at offset 0 and additional DOS push a word with zero on our stack before DOS let our application execute. So we can place a simple "ret" instruction at the end of our code. But we have to make sure that our stackpointer is not corrupted and our codesegment is not changed.

For to link a 16 bit application using MASM 6+ we need a 16 bit linker.

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

Dirk

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文