Как вывести hello world на ассемблере
Перейти к содержимому

Как вывести hello world на ассемблере

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 , но может быть и любой дугой), чтобы было проще работать со строкой. Затем пишем DBDefine Byte — Определить Байт. В нашем случае это будет массив байтов, в котором каждый элемент имеет размер один байт.

Потом пишем саму строку. Каждый символ занимает один байт, поэтому мы и объявили массив байтов. Знак доллара означает конец строки. Так функция вывода понимает, где она должна завершить вывод. Если этот знак не поставить, то будет выведено множество символов — сначала наша строка, а потом разный мусор, содержащийся в ячейках памяти, следующих за нашей строкой. А в эмуляторах это вообще может считаться ошибкой и вывода не будет.

Ну вот мы и написали свою первую программу на языке ассемблера. Если что-то пропустили, то посмотрите видео:

Учебный курс. Урок 6. Hello, world!

PacMan ест Hello, World!

В этой части наконец-то напишем долгожданный «Hello, world!». Теперь почти всё должно быть понятно. Откроем в текстовом редакторе новый файл и сохраним его как hello.asm в директории C:\fasm. Для начала необходимо с помощью директивы 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, лишь кратко расскажу о тех функциях, которые мы будем использовать. Если вы захотите узнать больше, в Интернете можно найти подробное описание

Чтобы увидеть работу программы, надо дать команду fasm для компиляции исходного кода в файл COM, а затем запустить её из командной строки DOSBox.

Если вы помните, в третьем уроке про отладчик мы разбирали нашу первую программу в дебагере. Для работы дебагера мы редактировали dosbox.conf, чтобы закоментировать DPMI хост. Теперь нам нужно снова вызвать хост и раскомменировать эти две строки:

#cd CWSDPMI/BIN/
#CWSDPMI -p -s-

Уберите знаки решетки в начале строк и сохраните dosbox.conf. Теперь запускаем DOSBox и вводим команды:

fasm hello . asm
hello . com

Результат работы программы:

Результат работы программы hello.com

Если вы запустите программу в отладчике Turbo Debugger, то просмотреть выводимую строку можно, нажав Alt+F5 или выбрав в меню Turbo Debugger пункт Window->User Screen.

5 ответов к “Учебный курс. Урок 6. Hello, world!”

Sonnyj пишет:

не знаю, сколько времени затрачено на поиск, но гугл завел меня на этот сайт и именно то, что нужно!

ice-cube пишет:

Прочитал 6 уроков, наконец есть какой-то вывод на экран. Еще интересует, будут ли уроки про непосредственную работу с «железом»?

В планах написание нескольких уроков на тему портов ввода/вывода. Также на тему прерывания. К слову, любые манипуляции с железом из под windows — это только эмуляция прямого обращения к железу из-за особенностей ОС. Ну и лишних знаний не бывает. Программирование под МК на ассемблере будет включать массу всевозможных прерываний и обращений к ножкам ввода/вывода. Работа с МК это другой ассемблер, но суть та же.

Ответить От автора записи
Alex пишет:

Здравствуйте, все понятно, но хотелось-бы узнать, как можно перезаписать в переменную другое значение?
Я пытался, при компиляции выдал ошибку, что такая уже есть. И ещё, как обращаться к функциям DOS(int 21h) повторно? При попытке вывести переменную на экран второй раз, программа ничего не пишет и не завершается. Ответьте пожалуйста на оба вопроса)

Добрый день 🙂
В нашем случае команда mov пожет за один вызов перезаписать только один байт строки по указанному адресу. То есть чтобы переписать значение в строке по её адресу в памяти, нужно будет пройти каждый байт от адреса начала строки и поместить туда новое значение:
mov [hello],10 ;Cпецсимвол ASCII переноса строки
mov [hello+1],13 ;Спецсимвол ASCII возврата каретки
mov [hello+2],’L’
mov [hello+3],’a’
mov [hello+4],’m’
mov [hello+5],’p’
mov [hello+6],’$’ ;Обязательно указываем на завершение строки.
int 21h ;Обращение к функции 0x9 DOS.

Ну а куда проще объявить еще одну переменную с другой строкой:
.
mov dx,hello ;В DX адрес строки.
mov ah,0x9 ;Номер функции DOS.
int 21h ;Обращение к функции DOS.
mov dx,hello1 ;В DX адрес новой строки строки.
int 21h ;Обращение к функции DOS 0x9.
.
hello1 db 10,13,’Lamp$’ ;Последовательность 10,13 — перенос строки и возврат каретки.

Как вывести hello world на ассемблере

1) Почему цифра 9 помещается именно в ah, а не куда либо?
2) Почему offset message помещается именно в dx, а не куда либо?
3) Как взаимодействуют ah и dx
4) int 20h и ret это то же самое? Как я понял это возврат управления из процедуры вызывающей программе. А где эта вызывающая программа? Если это всё что вне метки program: то почему после ret идёт ещё одна строчка (она что пропускается?).
5) Почему строчка «message db «Hello World!»,0Dh,0Ah,’$'» идёт в конце, а не в начале. Получается строчка «mov dx,offset message «, которая записывает адрес сообщения перескакивает вперёд и потом перескакивает назад?

Регистрация: 09.01.2008
Сообщений: 26,238

вы вызываете функцию MS DOS (int 21h)
для каждой из функций задаются ВХОДНЫЕ параметры, что делает функция, и выходные параметры.

вот описание функции AH=9 — 09H Display Text

 Expects: AH 09H DS:DX address of a string terminated with a '$' (ASCII 24H) ──────────────────────────────────────────────── Returns: none ──────────────────────────────────────────────── Info: The string, up to the terminating character '$' is sent to the Standard Output. Backspaces are handled as in the 02H Display Char function. The Normal procedure for displaying a 'newline' is to embed a CR/LF pair (ASCII 0dH followed by ASCII 0aH) in the string. Strings containing '$' may be printed via 40H Write File (BX=0).

т.е. разработчики MS DOS сказали, что эта функция определяется кодом в AH
а какой текст выводить, находится по адресу DS:DX.
кроме того, эта строчка обязательно должна иметь знак ‘$’ в конце.

3) Как взаимодействуют ah и dx
5) Почему строчка «message db «Hello World!»,0Dh,0Ah,’$'» идёт в конце, а не в начале. Получается строчка «mov dx,offset message «, которая записывает адрес сообщения перескакивает вперёд и потом перескакивает назад?

потому что эта строчка представляет собой ДАННЫЕ! Данные, в отличие от кода НЕ ВЫПОЛНЯЮТСЯ. Это ТЕКСТ, который будет выведен.

p.s. может Вам книжки какие для начинающих почитать!
Методом тыка изучать Ассемблер — это не очень продуктивно!

Serge_Bliznykov
Посмотреть профиль
Найти ещё сообщения от Serge_Bliznykov

Art1xFX / lab2masm.asm

Разработать программу вывода строки “Hello World” на экран в стилях masm и tasm с использованием директивы db определить в сегменте данных строку ‘Hello World’,10,13,’$’. Инициализировать регистр ds адресом сегмента данных. С помощью функции 9 прерывания 21h вывести эту строку на экран.

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

.MODEL SMALL ;Модель памяти
.DATA ;Сегмент данных
MESSAGE DB «Hello World» , 10 , 13 , ‘$’
.CODE ;Сегмент кода
MAIN: ;Точка входа в приложение
MOV AX , @DATA ;Инициализация сегмента данных
MOV DS , AX ;Через регистр AX
MOV AH , 9H ;Вывод строки на экран
MOV DX , OFFSET MESSAGE ;находящейся по адресу в DX
INT 21H ;до символа $
MOV AH , 4CH ;Завершение программы
INT 21H
END MAIN

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

SDATA SEGMENT PARA ‘DATA’ ;Сегмент данных
MESSAGE DB «Hello World» , 10 , 13 , ‘$’
SDATA ENDS
SCODE SEGMENT PARA ‘CODE’ ;Сегмент кода
ASSUME CS : SCODE , DS : SDATA
MAIN: ;Точка входа
MOV AX , SDATA ;Инициализация сегмента данных
MOV DS , AX ;Через регистр AX
MOV AH , 9H ;Вывод строки на экран
MOV DX , OFFSET MESSAGE ;находящейся по адресу в DX
INT 21H ;до символа $
MOV AH , 4CH ;Завершение программы
INT 21H
SCODE ENDS
END MAIN

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *