Вопрос

Я только начал изучать сборку x86 на Win32 и использовал masm с Visual Studio 2008, используя пользовательское правило сборки, которое поставляется с ide для файлов .asm.Я пытался использовать прерывание DOS для печати на консоли, но вместо этого получаю сообщение:«Необработанное исключение по адресу 0x00401004 в ASMTest.exe: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 Манагу прав в том, что вам следует использовать вызов Windows API, например WriteConsoleA, вместо использования прерывания 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

(Установите точку входа как главную)

Это было полезно?

Решение

Когда вы используете debug.exe для ввода этого кода, вы собираете 16-разрядную (8086 архитектура, "реальный режим") программу DOS. Указанная вами семантика верна для такой программы. Тем не менее, когда вы собираете программу с MASM, а затем связываете ее, вы пытаетесь создать 32-разрядную (архитектура i386, «защищенный режим») программу для Windows. Я могу ошибаться, но я не думаю, что вы можете по закону даже вызывать int 21h в последнем случае.

Другие советы

Возможно, это происходит из-за вашей инструкции 'ret'. Куда ты возвращаешься? Я полагаю, какое-то неизвестное место в памяти.

Вместо этого попробуйте использовать int 20h. Это выйдет "изящно".

Он работает в режиме отладки (вероятно), потому что это более "управляемый" процесс. окружающая среда.

Если мы запускаем 16-битное приложение DOS-*.com, то DOS заполняет код операции инструкции «int 20» внутри нашего PSP со смещением 0, а дополнительный DOS помещает слово с нулем в наш стек, прежде чем DOS разрешит нашему приложению выполниться.Таким образом, мы можем разместить простую инструкцию «ret» в конце нашего кода.Но мы должны убедиться, что наш указатель стека не поврежден и наш кодовый сегмент не изменен.

Чтобы связать 16-битное приложение с помощью MASM 6+, нам нужен 16-битный компоновщик.

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

Дирк

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top