Ассемблер Hello World
результатом является краш программы. В отладчике показывает что возникает ошибка ACCESS_VIOLATION в момент исполнения инструкции int 21h. Изначально думал что это из-за особенностей windows 7. Но сделав то же самое на си, и разобрав потом файл с помощью IDA pro увидел там тот же самый int 21h который довольно успешно исполнялся. Подскажите пожалуйста как быть?
Отслеживать
задан 4 фев 2018 в 22:52
Андрей Беспалов Андрей Беспалов
90 1 1 серебряный знак 9 9 бронзовых знаков
Под windows в пользовательском режиме (в пользовательском приложении, а не ядре или драйвере) забудьте об использовании прерываний.
4 фев 2018 в 23:11
Спасибо большое за Ваш ответ. Но почему отладчики выдают ту же самую int 21h в работающем приложении?
4 фев 2018 в 23:21
Простите уж, но напомнило старую байку, как двое спорят до хрипоты — натурная съемка или постановка — мол, глянь, как тут вдарил! так он не мог полететь — явная постановка! Да ты, болван, физику не знаешь! — ну и так далее. Приходит третий, офигевает и говорит «Ребята, это ж «Том и Джерри»». Ребята, это ж функция DOS! Если 32-разрядная Windows и сделать выполнимый файл DOS, ну, тогда.
5 фев 2018 в 6:38
@АндрейБеспалов вечером постараюсь подробный ответ дать.
5 фев 2018 в 9:16
Благодарю Вас. Буду ждать
5 фев 2018 в 13:40
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Во-первых, вы компилируете ваш код как 32-битное консольное приложение (ключ /subsystem:console ). В обычном пользовательском приложении (не ядре или драйвере) под Windows использовать исключения DOS или BIOS нельзя.
Можно скомпилировать программу как 16-битный досовский исполняемый файл, но рабочий код будет выглядеть немного по-другому:
.model small .stack 100h .data message db 'Hello World',13,10,'$' ; для функции 9h прерывания 21h конец строки должен быть обозначен как символ '$', а не 0 .code start: mov ax, @data mov ds, ax mov dx, offset message mov ah, 09h int 21h mov ah, 4Ch int 21h end start
C:\masm32\bin\ml /c hello.asm C:\masm32\bin\link16 hello.obj,,nul,nul,nul
Выполнить полученный исполняемый файл можно несколькими способами:
- Запустив его под DOS
- Запустив его под Windows линейки Win 9x (от 95 до Me). Это настоящее выполнение кода без эмуляции.
- Запустив его под 32-разрядной Windows линейки NT (в том числе Win XP, Win 7 и даже Win 10, насколько я понимаю — но проверить это не могу). Это будет запуск через встроенный в систему эмулятор NTVDM.
- На любой Windows (и не только) системе с помощью эмулятора DosBox.
По поводу прерывания int 21h в программах под Windows. В каждом (почти каждом) приложении Windows есть код-«заглушка», который выполняется при попытке запуска приложения из-под DOS. В этом случае на экран выведется сообщение типа «This program cannot be run in DOS mode.» Вывод там происходит как раз с помощью 21h прерывания. При обычном запуске приложения под Windows этот код не выполнится. Если попытаться использовать прерывание под Windows, вы получите ошибку.
В качестве исключения можно использовать прерывание int3 (команда так и выглядит, без пробела), которое специально предназначено для остановки выполнения программы, и вызова отладчика.
Hello World на Ассемблере
После примеров простых программ на Паскале и С++ вы, наверно, не ожидали что я сразу перепрыгну на Ассемблер. Но вот перепрыгнул. И сегодня мы поприветствуем мир на языке ассемблера.
Итак, вот сразу пример, а потом его рассмотрим:
.model tiny .code ORG 100h begin: MOV AH, 9 ; Функция вывода строки на экран MOV DX, OFFSET Msg ; Адрес строки INT 21h ; Выполнить функцию RET ; Вернуться в операционную систему Msg DB 'Hello, World. $' ; Строка для вывода END begin
Как видите, программа на ассемблере, даже такая простая, содержит исходный текст значительно большего размера по сравнению с аналогичной программой на С++, а уж тем более на Паскале.
С другой стороны, это не так уж и страшно, как иногда думают те, кто никогда не программировал на Ассемблере.
Во всех подробностях разбирать этот код не будем — подробности в другой раз. Рассмотрим только основные инструкции.
Программа начинается с метки begin . В отличие, например, от Паскаля, это слово может быть каким угодно, например, start . Это всего лишь метка, которая обозначает начало какого-то участка кода.
К конце программы мы видим END begin . Инструкция END говорит ассемблеру, что следующее за ней слово означает конец блока кода, обозначенного этим словом. В нашем примере это означает, что здесь кончается блок кода, начинающийся со слова begin .
Далее уже начинается программа. Сначала в регистр АН мы записываем номер функции, которую собираемся потом выполнить. Номер 9 — это функция BIOS, которая выполняет вывод на устройство вывода. По умолчанию это монитор.
Затем в регистр DX мы записываем адрес строки. Адрес вычисляется с помощью оператора OFFSET . Например:
Здесь мы получаем адрес первого байта блока данных, обозначенного идентификатором Msg .
Затем мы вызываем прерывание 21h . Это прерывание выполняет функцию, номер которой записан в регистре АН. Поскольку у нас там записана функция 9, то прерывание выведет на экран строку.
Команда RET выполняет выход из процедуры или из программы. В нашем случае из программы. Таким образом программа завершается и мы возвращаемся в операционную систему.
Ещё несколько слов об объявлении строки:
Msg DB ‘Hello, World. $’
Вначале мы записываем идентификатор (в нашем случае Msg , но может быть и любой дугой), чтобы было проще работать со строкой. Затем пишем DB — Define Byte — Определить Байт. В нашем случае это будет массив байтов, в котором каждый элемент имеет размер один байт.
Потом пишем саму строку. Каждый символ занимает один байт, поэтому мы и объявили массив байтов. Знак доллара означает конец строки. Так функция вывода понимает, где она должна завершить вывод. Если этот знак не поставить, то будет выведено множество символов — сначала наша строка, а потом разный мусор, содержащийся в ячейках памяти, следующих за нашей строкой. А в эмуляторах это вообще может считаться ошибкой и вывода не будет.
Ну вот мы и написали свою первую программу на языке ассемблера. Если что-то пропустили, то посмотрите видео:
Hello World на ассемблере
Hello World на ассемблере. Как много в этом звуке. Для начала, вот, что мы будем лопатить в асме, классика:
#include int main(void)
На GNU assembly это будет примерно так:
######### write(1, message, 13) -> exit(0) .data msg: .ascii "Hello, world\n" .text .global _start _start: # entry point mov $1, %eax # syscall 1 (write) mov $1, %edi # file handle 1 (stdout) mov $msg, %esi # string address mov $13, %edx # size in bytes syscall # OS syscall mov $60, %eax # syscall 60 (exit) xor %edi, %edi # return 0 syscall # OS syscall
5. Hello world на ассемблер 8086
Статья основана на материале xrnd с сайта asmworld (из учебного курса по программированию на ассемблер 16-битного процессора 8086 под DOS). В этой части наконец-то напишем долгожданный «Hello, world!» . Теперь почти всё должно быть понятно. Для начала необходимо с помощью директивы db объявить строку, содержащую сообщение «Hello, word!» . Лучше сделать это в конце программы, за последней командой, иначе процессор может принять строку за код и попытаться её выполнить. Для вывода строки используется системная функция DOS. Чтобы напечатать строку, нужно поместить 9 в регистр AH , а в регистр DX поместить адрес строки, которая должна заканчиваться символом ‘$’ . Обращение к функциям DOS осуществляется с помощью команды int 21h. Вот код программы:
use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov dx,hello ;В DX адрес строки. mov ah,9 ;Номер функции DOS. int 21h ;Обращение к функции DOS. mov ax,4C00h ;\ int 21h ;/ Завершение программы ;------------------------------------------------------- hello db 'Hello, world!$'
В четвёртой строке FASM подставит адрес строки вместо hello. Не трудно догадаться, что завершение программы — это тоже функция DOS с номером 4Ch. Перед её вызовом в регистр AL помещается код завершения программы (ноль соответствует успешному завершению). Можно объединить эти две операции и сразу поместить в AX значение 4C00h. В учебном курсе я не буду подробно описывать функции DOS, лишь кратко расскажу о тех функциях, которые мы будем использовать. Если вы захотите узнать больше, в Интернете можно найти подробное описание ? Чтобы увидеть работу программы, надо запустить её из командной строки, иначе она печатает строку и сразу закрывается. Или можно написать простенький bat-файл для запуска:
hello.com pause
Результат работы программы: Если вы запустите программу в отладчике, то просмотреть выводимую строку можно, нажав Alt+F5 или выбрав в меню Turbo Debuger пункт Window->User Screen.
Просмотр 0 веток ответов