В этой части наконец-то напишем долгожданный «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!$’
Ассемблер Как скомпилировать asm в exe 2019
В четвёртой строке 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
Результат работы программы:
Если вы запустите программу в отладчике Turbo Debugger, то просмотреть выводимую строку можно, нажав Alt+F5 или выбрав в меню Turbo Debugger пункт Window->User Screen.
5 ответов к “Учебный курс. Урок 6. Hello, world!”
Sonnyj пишет:
не знаю, сколько времени затрачено на поиск, но гугл завел меня на этот сайт и именно то, что нужно!
ice-cube пишет:
Прочитал 6 уроков, наконец есть какой-то вывод на экран. Еще интересует, будут ли уроки про непосредственную работу с «железом»?
В планах написание нескольких уроков на тему портов ввода/вывода. Также на тему прерывания. К слову, любые манипуляции с железом из под windows — это только эмуляция прямого обращения к железу из-за особенностей ОС. Ну и лишних знаний не бывает. Программирование под МК на ассемблере будет включать массу всевозможных прерываний и обращений к ножкам ввода/вывода.
Создание проекта в Visual Studio с ассемблерным модулем
Работа с МК это другой ассемблер, но суть та же.
Ответить От автора записи
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 — перенос строки и возврат каретки.
Источник: asmbase.ru
Изучаем архитектуру Intel x86-64 при помощи ассемблера (Часть 1 — Hello World на голом железе)
Я давно хотел научиться писать операционную систему или хотя бы попробовать эту задачу на зуб. Почему ОС начинают писать на языке ассемблера? Дело в том, что работа ОС обеспечивается определенными особенностями архитектуры процессора. Это, например, наличие нескольких уровней привилегий (режим ядра, режим пользователя), поддержка виртуальной памяти, поддержка многозадачности.
Работа с этими особенностями архитектуры процессора подразумевает использование таких машинных команд и регистров процессора, о которых компиляторы высокоуровневых языков программирования (например C/C++) ничего не знают. Поэтому — ассемблер. В следующей серии заметок я буду писать о своих опытах исследования архитектуры процессоров Intel как то: работа в реальном режиме, переход в защищенный режим, написание загрузчика (bootloader), обработка прерываний, включение механизма виртуальной памяти и пр.
В Интернете я нашел несколько хороших ресурсов по теме:
- Руслан Аблязов — Программирование на ассемблере на платформе х86-64 — 2011
- Intel 64 and IA-32 Architectures Software Developer’s Manual
- BrokenThorn OS Development Series
- OSDev.org
- OSDever.net
Кроме того, если вы не знакомы с языком ассемблера для процессоров семейства x86, рекомендую вам книгу Kip Irvine — Assembly Language for x86 Processors, 7th edition — 2014.
Начнем с того, что напишем программу HelloWorld, запускающуюся на голом железе (без операционной системы) и запустим ее на виртуальной машине.
Программа HelloWorld
Ниже показан исходный код программы HelloWorld на языке ассемблера Flat Assembler (FASM), которая будет стартовать на голом железе в реальном режиме работы x86-совместимого процессора (комментарии пишу на английском — привычка, которая возникла у меня в связи с проблемами с кодировками кириллицы).
; HelloWorld real mode
use16 ; generate 16-bit code
org 7C00h ; the code starts at 0x7C00 memory address
start :
jmp far dword 0x0000 : entr ; makes CS=0, IP=0x7c05
entr :
xor ax , ax ; ax = 0
mov ds , ax ; setup data segment ds=ax=0
cli ; when we set up stack we need disable interrupts because stack is involved in interrupts handling
mov ss , ax ; setup stack segment ss=ax=0
mov sp , 0x7C00 ; stack will grow starting from 0x7C00 memory address
sti ; enable interrupts
mov si , message
cld ; clear direction flag (DF is a flag used for string operations)
mov ah , 0Eh ; BIOS function index (write a charachter to the active video page)
puts_loop :
lodsb ; load to al the next charachter located at [si] address in memory (si is incremented automatically because the direction flag DF = 0)
test al , al ; zero in al denotes the end of the string
jz puts_loop_exit
int 10h ; call BIOS standard video service’s function
jmp puts_loop
puts_loop_exit :
cli ; disable interrupts before halting the processor
hlt ; halt the processor
;jmp $ ; alternatively to hlt we could run an infinite loop
message db ‘Hello World!’ , 0
finish :
; The size of a disk sector is 512 bytes. Boot sector signature occupies the two last bytes.
; The gap between the end of the source code and the boot sector signature is filled with zeroes.
times 510 — finish + start db 0
db 55h , 0AAh ; boot sector signature
Компиляция исходного кода
Объяснения того, как работает программа — потом, сначала давайте скомпилируем исходный код. Компилировать будем ассемблером Flat Assembler (FASM). Скачиваем с официального сайта архив с дистрибутивом FASM. Внутри архива находится компилятор fasm.exe. Я рекомендовал бы распаковать архив в папку C:FASM и добавить путь к этой папке в переменную окружения PATH. Далее запускаем командную строку и компилируем исходный код:
fasm HelloWorld.asm HelloWorld.bin
HelloWorld.asm — это приведенный выше файл с исходным кодом, HelloWorld.bin — это скомпилированный машинный код.
Создание образа дискеты
Операционная система должна загружаться с какого-то носителя (жесткого диска, CD-ROM, флешки, дискеты и т. д.). Создадим образ загрузочной дискеты с нашим машинным кодом. Виртуальная машина сможет загрузиться с виртуальной дискеты, используя этот образ. Создавать образ дискеты умеет unix’овая утилита под названием dd. Существует версия этой утилиты под Windows.
Если вы пользуетесь средой Cygwin, то утилита dd есть в ее составе. Итак, запускаем командную строку:
dd if=»/dev/zero» of=»floppy.img» bs=1024 count=1440
dd if=»HelloWorld.bin» of=»floppy.img» conv=notrunc
1-я команда создает образ дискеты floppy.img и заполняет его нулями, 2-я — записывает в самое начало образа нашу программу.
Установка и запуск виртуальной машины Bochs
Я имел дело всего с тремя виртуальными машинами: Oracle VM VirtualBox, VMware Workstation Player и Bochs. Bochs хотя и обладает очень скромным графическим интерфейсом, хорош тем, что он легкий и может выполнять машинный код пошагово, т. е. с ним можно производить отладку исходного кода программы.
Скачиваем с официального сайта программу установки (файл с расширением .exe) и запускаем его (все настройки я оставлял по-умолчанию). После установки запускаем Bochs. Возникает диалоговое окно Bochs Start Menu. В списке Edit Options выбираем Disk boot sector signature
После включения процессор работает в 16-разрядном режиме (т. н. реальный режим работы процессора). Две ассемблерные команды, имеющие одно и то же мнемоническое обозначение, будут иметь разные машинный код в зависимости от режима работы процессора (режимов на сегодняшний день существует три: реальный (16-разрядный), защищенный (32-разрядный) и длинный (64-разрядный)). Поэтому компилятор должен знать, какой машинный код ему генерировать, 16-, 32- или 64-разрядный — для этого мы используем директиву
Настройка сегментных регистров:
start :
jmp far dword 0x0000 : entr ; makes CS=0, IP=0x7c00
entr :
xor ax , ax ; ax = 0
mov ds , ax ; setup data segment ds=ax=0
mov ss , ax ; setup stack segment ss=ax=0
mov sp , 0x7C00 ; stack will grow starting from 0x7C00 memory address
Зачем помещать нули в сегментные регистры? Дело в том, что мы не знаем, каковы значения этих регистров в момент запуска программы. Единственное, что мы знаем — это что наша программа будет загружена по адресу 0x7C00 и что первая машинная команда будет выполнена. В то же время, наша программа рассчитана на то, что в сегментных регистрах cs и ds будут нули, т. е. все метки в программе обозначают смещения относительного базового адреса, равного нулю. Стек мы пока не используем, но это пока — нелишним будет проинициализировать и регистры ss и sp.
Как вывести текстовую строку на экран. После старта процессора в реальном режиме в оперативную память из BIOS загружена таблица прерываний и загружены обработчики прерываний. Среди них есть программные прерывания — те, обработчики которых можно вызвать командой int.
Эти прерывания по сути являются функциями, которые BIOS предоставляет нашей программе, и эти функции позволяют осуществлять ввод-вывод, в том числе на экран компьютера. Функции BIOS могут принимать параметры через регистры. Например функция int 10h принимает два параметра: параметр ah=0Eh уточняет задачу функции — «записать символ в видеопамять»; параметр al — ASCII-код символа, который надо записать в видеопамять. И мы последовательно в цикле помещаем в регистр al символы строки «Hello World!» и вызываем прерывание int 10h:
puts_loop :
lodsb ; load to al the next charachter located at [si] address in memory (si is incremented automatically because direction flag DF = 0)
test al , al ; zero in al means the end of the string
jz puts_loop_exit
int 10h ; call BIOS standard video service’s function
jmp puts_loop
puts_loop_exit :
Некоторые функции BIOS приведены на странице OsDev.org — BIOS.
Заканчивается программа инструкцией hlt , которая останавливает работу процессора. Из этого состояния он может быть выведен только прерыванием (как немаскируемым, так и маскируемым) или перезагрузкой (reset).
В следующей заметке я расскажу о настройке проекта osdevlearning, который размещен на BitBucket, и в который я буду помещать наши эксперименты по изучению архитектуры Intel x86-64.
Источник: dvsav.ru
Как запустить ассемблер?
3 ноября 2014 г.
Просмотров: 1207
Инструкции
Язык программирования ассемблер традиционно славится плохой репутацией: его сложно изучать и еще сложнее на нем программировать. Однако, несмотря на некоторую сложность в восприятии, данный язык имеет ряд преимуществ: высокая скорость работы программ на ассемблере и возможность запрограммировать любое действие компьютера.
Вам понадобится
- — права администратора.
Источник: imguru.ru