Как создавался редактор ассемблерного кода sasm

Assembler в авиапроме: Интервью с разработчиком автопилотов на ASM для самолётов и беспилотников

Человек веками мечтал о небе. Братья Уилбур и Орвилл Райт, Альберто Сантос-Дюмон и братья Вуазен подарили его людям. И человек с каждым десятилетием поднимался всё выше и выше, увеличивал скорости, манёвренность, предельные перегрузки, преодолевал звуковой барьер, сталкивался раз за разом с труднейшими инженерными вызовами.

Авиация изменила мир — и его современный облик во многом сформировался за счёт быстрых авиасообщений, когда достижение другого континента или удалённой страны перестало быть трудным и опасным путешествием длиной в несколько недель, а то и месяцев.

Но с ростом скоростей и расстояний повысились требования к управляющим системам летательных аппаратов — микроконтроллерам, прошивкам, автопилотам.

Мне повезло познакомиться с отечественным разработчиком Владом Гордеевым, который занимается как разработкой систем дистанционного управления полетом самолётов, так и систем автоматического управления полетом ЛА. Я задал ему несколько вопросов — и оказался на пару часов в мире, где всё решают миллисекунды, такты, алгоритмы и нет права на ошибку.

Annotating code

It’s often useful to annotate a line of code with a comment. I use annotations
to leave notes to myself when I’m trying to understand how some piece of
machine code works.

Let’s consider again the code loaded by the sample script.

The instruction at address calls a subroutine that uses all
the addressing mode variants of the command. Let’s add an annotation
to that line of code to remind ourselves later what its purpose is.

Now whenever we disassemble code that includes the instruction at address
, we will see our annotation.

To remove an annotation, use the command with an address but without a description.

Aside: Number formats

go6502 accepts numbers in multiple formats. In most of the examples we’ve seen
so far, addresses and byte values have been specified in base-16 hexadecimal
format using the prefix.

The following table lists the number-formatting options understood by go6502:

Prefix Format Base Example Comment
(none) Decimal 10 -151 See note about hex mode.
Hexadecimal 16
Hexadecimal 16
Binary 2
Binary 2
Decimal 10 Useful in hex mode.

If you prefer to work primarily with hexadecimal numbers, you can change the
«hex mode» setting using the command.

In hex mode, numeric values entered without a prefix are interpreted as
hexadecimal values. However, because hexadecimal numbers include the letters
through , the interpreter is unable to distinguish between a number and
an identifier. So identifiers are not allowed in hex mode.

Assembling source code

go6502 has a built-in cross-assembler. To assemble a file on disk into a raw
binary file containing 6502 machine code, use the command (or
for short).

The command loads the specified source file, assembles it, and
if successful outputs a raw file containing the machine code into the
same directory. It also produces a source map file, which is used to
store (1) the «origin» memory address the machine code should be loaded at,
(2) a list of exported address identifiers, and (3) a mapping between source
code lines and memory addresses.

Once assembled, the binary file and its associated source map can be loaded
into memory using the command.

To be continued…

Конвенция вызова функций STDCALL (WinApi : Windows 95 — Windows 10).

Операционная система Windows содержит набор встроенных функций, которые обеспечивают удобство программирования, обслуживания и работы системы — так называемые WinApi — Windows Application programming interfaces.

Функций огромное количество. Они входят в стандартный пакет Windows любой версии и содержаться в библиотеках *.dll, расположенных в системных директориях Windows (System, System32, SysWOW64 — для 64 битной системы). Например, kernel32.dll содержит огромное количество функций, входящих в т.н. «Ядро операционной системы», например MoveFile — «переместить файл».

Для операционной системы Windows (WinApi) был разработана отдельная конвенция вызова функций. Она включила в себя преимущества PASCAL и С (Си) конвенций.

Конвенция STDCALL (WinApi) имеет следующие особенности.

Параметры загоняются в стек слева направо — снизу вверх, стек очищается вызываемая функция.

К слову можно сказать, что возвращаемое функцией WinApi значение содержиться в 32 битном регистре eax (нам он пока не известен, но это расширенный до 32 бит регистр ax).

Функция (процедура) содержит пять параметров:myFunc (a,b,c,d,e)

;Ассемблерный код:
push e; Пятый параметр — сверху
push d;
push c;
push b;Второй параметр
push a; Первый параметр (самый левый) — снизу
call myFunc

;———————————————————————-
;Функция содержит пять параметров:
myFunc:
push bp
mov bp,sp; Создаём стековый кадр. В bp — указатель на стековый кадр, регистр bp использовать нельзя!
e equ ; Последний параметр — сверху ()
d equ
c equ
b equ
a equ

;команды, которые могут использовать стек:
mov ax,e ; считать параметр «a» — . Можно и так, но это менее понятно: mov ax,
; Команды CALL при вызове функции, в стек поместили адрес возврата — 2 байта для процедуры типа NEAR (или 4 — для FAR), а потом еще и ВР — 2 байта (push bp — в начале нашей функции)
mov bx,с ; считать параметр «c» — . Можно и так, но это менее понятно: mov bx,
;…ещё команды

pop bp
ret 10 ; Из стека дополнительно извлекается 10 байт — стек освобождает вызываемая функция

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

;Ассемблерный код:

pushe; Пятый параметр — сверху

pushd;

pushc;

pushb;Второй параметр

pusha; Первый параметр (самый левый) — снизу

callmyFunc

;———————————————————————-
;Функция содержит пять параметров:

myFunc

pushbp

movbp,sp; Создаём стековый кадр. В bp — указатель на стековый кадр, регистр bp использовать нельзя!

eequbp+12; Последний параметр — сверху ()

dequbp+10

cequbp+8

bequbp+6

aequbp+4

;команды, которые могут использовать стек:

movax,e; считать параметр «a» — . Можно и так, но это менее понятно: mov ax,

; Команды CALL при вызове функции, в стек поместили адрес возврата — 2 байта для процедуры типа NEAR (или 4 — для FAR), а потом еще и ВР — 2 байта (push bp — в начале нашей функции)

movbx,с; считать параметр «c» — . Можно и так, но это менее понятно: mov bx,

;…ещё команды
 

popbp

ret10; Из стека дополнительно извлекается 10 байт — стек освобождает вызываемая функция

Реализация

Опыта написания GUI у меня до этого не было, да и C++ я на тот момент не знал (в 1 семестре у нас был C). Решил всему учиться сразу при написании проекта. Много слышал про фреймворк Qt и написание на нем приложений с графическим пользовательским интерфейсом. Его и было решено выбрать для проекта.

Qt — бесплатный кроссплатформенный фреймворк, да и достаточно популярный, что немаловажно при изучении. К тому же в комплекте с ним идет очень удобная среда разработки Qt Creator и замечательная справка Qt Assistant (однако только на английском)

Первые шаги

В первый день почитал немного лекций 2 курса по C++. Затем, так как хотелось побыстрее начать, прочитал первые 100 страниц книги Бланшета, Саммерфилда «Программирование GUI на C++» о программировании с использованием Qt.

Сначала был написан просто текстовый редактор с логом построения и окнами ввода/вывода. Программа умела собирать код, который был в текстовом редакторе и запускать построенную программу, передавая ей ввод и получая её вывод (и для сборки, и для запуска использовались QProcess).

Подсветка синтаксиса

«Какая же IDE может быть без подсветки?» — подумал я и решил прикрутить оную. Qt — очень богатый фреймворк, и даже для этой, с виду не такой распространенной задачи, там было решение — QSyntaxHighlighter. Нужно было только отнаследоваться от него и заимплементить функцию highlightBlock, которая будет вызываться автоматически, когда нужно. Функция подсвечивала синтаксис, проходя по списку пар <регулярное выражение QRegExp, необходимый формат текста (цвет, курсив и т.д.)>. Про регулярные выражения узнал опять же из Qt Assistant — очень удобная вещь, с тех пор применял их не в одной задаче.

Отладчик

По ходу дела я выкладывал первые версии на обозрение однокурсников и получал некоторый фидбек. Одной из самых востребованных и интересных фич был отладчик. И на самом деле, в начале, при написании программ на языке ассемблера, было где наделать ошибок. К тому же для более полного понимания интересно было посмотреть результаты работы отдельных команд (как меняются регистры, как выставляются флаги). Отладчик очень бы помог в этих случаях.

Решено было использовать стандартный консольный GDB, опять же запуская его через QProcess, на вход подавать нужные команды, соответствующие действиям пользователя в интерфейсе, и разбирая теми же регулярками его вывод.

Там были свои заморочки, связанные с дебагом именно кода, который получается из программы на языке ассемблера. Это происходило из-за того, что ассемблер NASM не добавлял полной отладочной информации в исполняемый файл (только информацию по функциям и переменным). Приходилось разбирать его листинги, чтобы, например, понять в каком месте в тексте программы мы сейчас находимся (GDB говорил только место в памяти).

Так или иначе, отладчик был реализован — можно было ходить по программе, ставить брейкпоинты, через некоторое время добавил показ регистров и памяти.

Ещё фичи

Перевел программу на русский — в приложениях на Qt хороший тон не использовать в коде отличный от английского язык. С помощью Qt это делается очень просто: все строки, которые нужно переводить, заключаются в функцию tr (например, tr("string to translate")). Затем Qt Linguist парсит все такие упоминания строк и позволяет перевести их и сохранить в файл с переводом. Этот файл загружается в программе при выборе другого языка.

В редактор добавил возможность делать правильные отступы табом, комментировать участок кода и другие необходимые мелочи. Добавил вкладки (QTabWidget), настройки цветовой цветов, опций сборки. Все достаточно просто, с точки зрения реализации здесь ничего особенного отметить не смогу.

В программу была включена библиотека макросов ввода/вывода io.inc для NASM (она была взята из курса «Архитектура и язык ассемблера» и немного изменена для правильной работы с отладчиком, а также была написана ее x64 версия). Она очень удобна для новичков: когда не знаешь соглашения о вызовах и не можешь вызвать printf, очень удобно вызвать макрос из этой библиотеки. Описание макросов библиотеки находится на сайте программы.

Летом 2014 добавил поддержку x64 и ассемблеров MASM, FASM, GAS (все по аналогии с NASM). Для поддержки нескольких ассемблеров выделил интерфейс Assembler — добавлять новые ассемблеры стало проще.

Программа 1. Получение данных из командной строки

Программа получает данные из командной строки и выводит их в небольшом windows-окне.

.486
.model flat, stdcall
option casemap: none

include /masm32/include/windows.inc
include /masm32/include/user32.inc
include /masm32/include/kernel32.inc

includelib /masm32/lib/user32.lib
includelib /masm32/lib/kernel32.lib

include /masm32/macros/macros.asm
uselib masm32, comctl32, ws2_32

.data

.code
start:

call GetCommandLine ; результат будет помещен в eax

push 0
push chr$(«Command Line»)
push eax ; текст для вывода берем из eax
push 0
call MessageBox

push 0
call ExitProcess

end start

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

.486

.model flat,stdcall

option casemapnone

includemasm32includewindows.inc

includemasm32includeuser32.inc

includemasm32includekernel32.inc

includelibmasm32libuser32.lib

includelibmasm32libkernel32.lib

includemasm32macrosmacros.asm

uselib masm32,comctl32,ws2_32

.data

.code

start

call GetCommandLine;результатбудетпомещенвeax

push

push chr$(«Command Line»)

push eax;текстдлявыводаберемизeax

push

call MessageBox

push

call ExitProcess

endstart

Код с вызовом функций можно было бы заменить кодом:

invoke GetCommandLine
invoke MessageBox, 0, eax, chr$(«Command Line»), 0
invoke ExitProcess, 0

1
2
3

invoke GetCommandLine

invoke MessageBox,,eax,chr$(«Command Line»),

invoke ExitProcess,

invoke — это встроенный макрос для упрощения кода, и при компиляции всё это преобразуется в ассемблерные команды.

Т.е. код

invoke MessageBox, 0, eax, chr$(«Command Line»), 0

1 invoke MessageBox,,eax,chr$(«Command Line»),

эквивалентен коду

push 0
push chr$(«Command Line»)
push eax
push 0
call MessageBox

1
2
3
4
5

push

push chr$(«Command Line»)

push eax

push

call MessageBox

Стек — это удобное место для хранения информации. Чаще всего он используется при вызове функций.

Все WinAPI-функции созданы по соглашению stdcall, то есть, передача аргументов в них производится через стек в обратном порядке. Возвращают эти функции значение в регистре eax.

Как мыслит процессор

Что­бы понять, как рабо­та­ет Ассем­блер и поче­му он рабо­та­ет имен­но так, нам нуж­но немно­го разо­брать­ся с внут­рен­ним устрой­ством про­цес­со­ра.

Кро­ме того, что про­цес­сор уме­ет выпол­нять мате­ма­ти­че­ские опе­ра­ции, ему нуж­но где-то хра­нить про­ме­жу­точ­ные дан­ные и слу­жеб­ную инфор­ма­цию. Для это­го в самом про­цес­со­ре есть спе­ци­аль­ные ячей­ки памя­ти — их назы­ва­ют реги­стра­ми.

Реги­стры быва­ют раз­но­го вида и назна­че­ния: одни слу­жат, что­бы хра­нить инфор­ма­цию; дру­гие сооб­ща­ют о состо­я­нии про­цес­со­ра; тре­тьи исполь­зу­ют­ся как нави­га­то­ры, что­бы про­цес­сор знал, куда идти даль­ше, и так далее. Подроб­нее — в рас­хло­пе ↓

Какими бывают регистры

Обще­го назна­че­ния. Это 8 реги­стров, каж­дый из кото­рых может хра­нить все­го 4 бай­та инфор­ма­ции. Такой регистр мож­но раз­де­лить на 2 или 4 части и рабо­тать с ними как с отдель­ны­ми ячей­ка­ми.

Ука­за­тель команд. В этом реги­стре хра­нит­ся толь­ко адрес сле­ду­ю­щей коман­ды, кото­рую дол­жен выпол­нить про­цес­сор. Вруч­ную его изме­нить нель­зя, но мож­но на него повли­ять раз­лич­ны­ми коман­да­ми пере­хо­дов и про­це­дур.

Регистр фла­гов. Флаг — какое-то свой­ство про­цес­со­ра. Напри­мер, если уста­нов­лен флаг пере­пол­не­ния, зна­чит про­цес­сор полу­чил в ито­ге такое чис­ло, кото­рое не поме­ща­ет­ся в нуж­ную ячей­ку памя­ти. Он туда кла­дёт то, что поме­ща­ет­ся, и ста­вит в этот флаг циф­ру 1. Она — сиг­нал про­грам­ми­сту, что что-то пошло не так.

Фла­гов в про­цес­со­ре мно­го, какие-то мож­но менять вруч­ную, и они будут вли­ять на вычис­ле­ния, а какие-то мож­но про­сто смот­реть и делать выво­ды. Фла­ги — как сиг­наль­ные лам­пы на пане­ли при­бо­ров в само­лё­те. Они что-то озна­ча­ют, но толь­ко само­лёт и пилот зна­ют, что имен­но.

Сег­мент­ные реги­стры. Нуж­ны были для того, что­бы рабо­тать с опе­ра­тив­ной памя­тью и полу­чать доступ к любой ячей­ке. Сей­час такие реги­стры име­ют по 32 бита, и это­го доста­точ­но, что­бы полу­чить 4 гига­бай­та опе­ра­тив­ки. Для про­грам­мы на Ассем­бле­ре это­го обыч­но хва­та­ет.

Так вот: всё, с чем рабо­та­ет Ассем­блер, — это коман­ды про­цес­со­ра, пере­мен­ные и реги­стры.

Здесь нет при­выч­ных типов дан­ных — у нас есть толь­ко бай­ты памя­ти, в кото­рых мож­но хра­нить что угод­но. Даже если вы поме­сти­те в ячей­ку какой-то сим­вол, а потом захо­ти­те рабо­тать с ним как с чис­лом — у вас полу­чит­ся. А вме­сто при­выч­ных цик­лов мож­но про­сто прыг­нуть в нуж­ное место кода.

Как сжать загрузчик для STM8 до размера 8 байт в памяти FLASH

Со времени написания предыдущей статьи ” Как сжать загрузчик для STM8 до размера 18 байт в памяти FLASH” появились две версии загрузчика STM8uLoader . Загрузчик STM8uLoader версии $36 научился передавать управление прикладной программе по любому адресу в памяти RAM без участия хост-программы. Размер 18 байт загрузчика в памяти FLASH не изменился, в области OPTION Bytes размер увеличился до 53 байта (занял все доступное пространство).
В отдельную ветку выделилась версия $0D загрузчика. Основное требование к этой версии: максимально сжать код. На сегодняшний день размер кода во FLASH памяти 8 байт в EEPROM памяти 35 байт.

Как я отказался от вычисления квадратного корня

Из песочницы

Очень часто при цифровой обработке сигналов необходимо вычислить длину вектора, обычно это делается по формуле A=SQRТ(X^2+Y^2). Здесь возвести в квадрат значение не сложно, но операция вычисления квадратного корня не является простой операцией, особенно для микроконтроллеров. Кроме того, алгоритмы вычисления корня выполняются не стабильное время, и для алгоритмов, в которых таких вычислений много, становится сложно прогнозировать время, необходимое для вычислений.
С такой задачей столкнулся и я. О том, как я отказался от процедуры вычисления корня, читайте ниже.

Почему следует изучать язык ассемблера?

В современной практике индустриального программирования языки ассемблера применяются крайне редко. Для разработки низкоуровневых программ практически в большинстве случаев используется язык си, позволяющий достигать тех же целей многократно меньшими затратами труда, причем с такой же, а иногда и большей эффективностью получаемого исполняемого кода (последнее достигается за счет применения оптимизаторов). На ассемблере сейчас реализуются очень специфические участки ядер операционных систем и системных библиотек. Более того, программирование на ассемблере было вытеснено и из такой традиционно ассемблерной области, как программирование микроконтроллеров. Большей частью прошивки для них также пишут на си. Тем не менее программирование на языке ассемблера очень часто применяется при написании программ, использующих возможности процессора, не реализуемые языками высокого уровня, а также при программировании всевозможных нестандартных программистских хитростей. Отдельные ассемблерные модули, как и ассемблерные вставки в текст на других языках, присутствуют и в ядрах операционных систем, и в системных библиотеках того же языка си и других языков высокого уровня. Сегодня едва ли кому придет в голову сумасшедшая мысль писать крупную программу на чистом ассемблере.

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

Вообще, профессиональный пользователь компьютера, системный ли администратор, или программист, может позволить себе что-то не знать, но ни в коем случае не может позволить не понимать сути происходящего, как устроена вычислительная система на всех ее уровнях, от электронных логических схем до громоздких прикладных программ. А непонимание чего-то влечет за собой ощущение в глубине подсознания некоей загадочности, непостижимого таинства, происходящего по мановению чьей-то волшебной палочки. Такое ощущение для профессионала недопустимо категорически. Он просто обязан быть уверен вплоть до глубинных слоев подсознания, что то устройство, с которым он имеет дело, ничего волшебного и непознаваемого собой не представляет.

Иными словами, до тех пор пока существуют процессоры, ассемблер будет необходим.

В этом отношении совершенно не важно, какую конкретно архитектуру и язык какого конкретного ассемблера изучать. Зная один язык ассемблера, ты с успехом можешь начать писать на любом другом, потратив лишь некоторое время на изучение справочной информации

Но самое главное в том, что, умея мыслить языком процессора, ты всегда будешь знать, что, для чего, почему и зачем происходит. А это уже не просто уровень программирования мышкой, а путь к созданию программного обеспечения, несущего печать великого мастерства.

Русская идеология

В русском дизассемблере подход прямо противоположный. Вся дизассемблируемая программа представлена как ОБЛАСТЬ ДАННЫХ. И задачей дизассемблера является наоборот выделить область кода. А что останется, то и будет областью данных. И здесь на первый вопрос машины — а с чего начать, где взять первый байт кода? — ответ четкий и однозначный. У любой программы есть точка входа и где находится ее адрес тоже известно. Поэтому первая инструкция проста — бери стартовый адрес. Он указывает на первый байт кода. Следующая инструкция — декодируй первый байт. Далее анализируй. Если команда простая, типа MOV, ADD, значит за ней следующий байт кода. Тогда шагай на него и снова декодируй. Если встретилась команда JMP, тогда инструкция — за нее шагать нельзя. Там еще не ясно что. Но, у команды JMP есть операнд, который четко указывает на область кода. Соответственна и инструкция будет однозначна — бери адрес перехода и продолжай шагать с новой области кода. Если встретилась команда RET, или функция DOS — завершить процесс, тогда остановись и оглянись назад. Возможно, по ходу процесса встречались условные переходы. Они возможно указывают еще на не пройденные области кода. Тогда их надо пройти. А уж когда все адреса кода отработаны, тогда заверши процесс. Настало время представить результат человеку для творческой работы.

Разумеется, по ходу процесса будут встречаться команды CALL вызова процедуры. На первый взгляд ситуация не сложная. Эта команда предполагает возврат на место после нее. А значит запомни адрес вызова и шагай дальше. Однако, на практике не во всех процедурах авторы предусматривают этот возврат. Они, пусть и не часто, но могут завершиться функцией DOS — завершить процесс. А это значит, после такой команды CALL продолжения кода может и не быть. Возможны и другие варианты, например текстовые сообщения, после команды CALL, и только после этого сообщения продолжение кода. По этой причине дизассемблеру дана четкая инструкция — при первой встрече всегда прерви текущую дорогу кода, войди в процедуру и изучи ее по выше описанному алгоритму. А по результату принимай решение. Если есть хотя бы одно нормальное завершение процедуры командой RET, тогда вернись из нее и продолжи предыдущую траекторию кода. Иначе прервись.

В процессе дизассемблирования могут возникать ситуации, на которые заранее инструкций не напишешь. Например, те же команды JMP и CALL могут иметь и неявную адресацию перехода\вызова. Эти адреса могут предварительно загружаться в регистры или размещаться в области данных в виде таблиц. В этих ситуациях уровня машинного декодирования явно недостаточно. Необходимо перейти на уровень смыслового декодирования, чтобы разобраться, например, со структурой таблицы. В таких случаях машине дана инструкция — запроси дополнительную инструкцию у человека. А для этого пометь эту проблемную ситуацию и продолжи дальше, не нарушая принципы описанного выше алгоритма.

Помимо основного процесса есть и попутные, параллельные

Например, не маловажной задачей является выявление OFFSETных меток

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

На следующем проходе она будет отработана. Разумеется, машине не всегда удается решить эту задачу, поэтому на втором проходе машине дана инструкция — все места загрузки регистров без автоофсета пометь, как проблемные, в помощь человеку….

Подробнее об интерактивном режиме, распаковке файлов в процессе дизассемблирования можно узнать в пакете программы RD16. Она выставлена в разделе «дополнения к языкам программирования».

Создаём исполняемый файл PRG.COM.

Для достижения нашей цели делаем следующее.

;Строка, после точки с запятой является комментарием
;и не обрабатывается ассемблером
; prg.asm — название файла.
.model tiny ; создаём программу типа СОМ
.code ; начало сегмента кода
org 100h ; начальное значение смещения программы в памяти — 100h
start:
mov ah,9 ; номер функции DOS — в АН
mov dx,offset message ; адрес строки — в DX
int 21h ; вызов т.н. «прерывания» — системной функции DOS
ret ; завершение СОМ-программы
message db «Hello, World!»,0Dh,0Ah,’$’ ; строка для вывода
end start ; конец программы.

1
2
3
4
5
6
7
8
9
10
11
12
13

;Строка, после точки с запятой является комментарием
;и не обрабатывается ассемблером
; prg.asm — название файла.

.modeltiny; создаём программу типа СОМ

.code; начало сегмента кода

org100h; начальное значение смещения программы в памяти — 100h

start

movah,9; номер функции DOS — в АН

movdx,offsetmessage; адрес строки — в DX

int21h; вызов т.н. «прерывания» — системной функции DOS

ret; завершение СОМ-программы

messagedb»Hello, World!»,0Dh,0Ah,’$’; строка для вывода

endstart; конец программы.

В папке D:\TASM.2_0\TASM\ находим «батник» ASM-COM.BAT со следующим текстом:

tasm.exe prg.asm
tlink.exe /t /x prg.obj

1
2

tasm.exeprg.asm

tlink.exetxprg.obj

Первая строка — запуск транслятора с названием нашего файла с кодом, расположенного в одной директории с транслятором.

Вторая строка — запуск компилятора с параметрами /t /x и название объектного файла — prg.obj, получившегося в результате выполнения первой команды.

Чтобы посмотреть список всех возможных параметров с пояснениями для файлов tasm.exe и tlink.exe необходимо запустить эти программы без параметров. Если вы сделаете это, не выходя из оболочки NC, то, чтобы просмотреть чистое окно DOS нажмите Ctrl+O, чтобы вернуться в NC, нажмите сочетание клавиш повторно.

После запуска ASM-COM.BAT в этой же директории появится файл prg.com. Запустив его мы увидим сообщение «Hello World!» в окне MS-DOS (при необходимости просмотра, снова применяем Ctrl+O).

Батник ASM-EXE.BAT предназначен для создания исполняемого файла формате *.EXE (предусматривает раздельную сегментацию для кода, данных и стека — наиболее распространённый формат исполняемых файлов DOS).

Батник COMPLEX.BAT предназначен для создания исполняемых файлов из двух файлов кода (названия обязательно должны быть prg.asm, prg1.asm).

Наша первая программа на ассемблере прекрасно работает!

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

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

Adblock
detector